amazing!!!

哀吾生之须臾,羡长江之无穷


  • 首页

  • 分类

  • 归档

  • 标签

TypeScript with React的一些总结

发表于 2018-11-20 |

久了没更新blog,算下来也有一年多了,这一年作为一个重度依赖React前端工作者,想对自己工作有所总结。所以呢,这一篇文章就用于总结一些 TypeScript with React 的经验吧。

项目架构

自从 UmiJS 发布以来,我在公司及个人项目中得到很好的应用。所以这里分享的也是基于此框架建立的解决方案。
基本的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
umi version: 1.x
+ dist // 生产环境构建产物
+ mock // mock 文件所在目录,基于 express
+ node_modules // 依赖库
+ src
+ assets // 资源目录
+ components // 组件
+ layouts // 布局组件
-index.tsx // 全局布局
+ models // dva models
+ pages // router page
+ services // 通信services
+ utils // 工具函数
- global.ts // 可以在这里加入 polyfill
- global.less // 约定的全局样式文件,自动引入
- .umirc.js
- .webpackrc.js
- package.json
- tsconfig.json
- typings.d.ts

文件分析

tsconfig.json

ts的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"compilerOptions": {
"target": "es6",
"module": "es6",
"moduleResolution": "node",
"jsx": "react",
"baseUrl": ".",
"paths": {
"src": ["src"],
"services/*": ["src/services/*"],
"components/*": ["src/components/*"],
"assets/*": ["src/assets/*"],
"utils/*": ["src/utils/*"]
},
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true
}
}

typings.d.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
declare module "*.css";
declare module "*.less";
declare module "*.png";
declare module "*.gif";
declare module "BMap"; // BMap
declare module "BMapLib"; // BMapLib
interface Window { // umi允许通过window.g_app 访问store
g_app: {
_store: {
dispatch: Function,
getState: Function
}
}
}
interface Array<T> { // 使用中发现这个函数会报错???
includes: (item: T) => boolean
}

编写一个标准的React Component

1
2
3
4
5
6
7
+ MyComponent
+ __snapshots__ // 测试快照
- index.react.test.tsx.snap // 快照文件
- index.tsx
- index.less // 组件样式,采用的css module
- index.react.test.tsx // jest test
- PropsType.ts

PropsType.ts

1
2
3
4
5
6
7
8
9
10
11
12
interface PropsType {
style?: React.CSSProperties, // 父容器style
headstyle?: React.CSSProperties, // 头部样式
titleTextstyle?: React.CSSProperties, // 标题文字样式
iconImg?: string, // 图标图片
color?: string,
title?: string,
children?: React.ReactNode,
right?: React.ReactNode, // 右侧内容
}
export default PropsType;

index.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import React from 'react';
import styles from "./index.less";
import PropsType from "./PropsType";
export default ({ style, headstyle, titleTextstyle, iconImg, color, title, children, right }: PropsType) => {
return (
<div className={styles.container} style={style}>
<div className={styles.head} style={headstyle}>
{
title ?
<div className={styles.title}>
{
iconImg ?
<img
className={styles.iconImg}
src={iconImg}
/>
:
<span className={styles.icon} style={{ backgroundColor: color || "#2f81f8" }}>
</span>
}
<span className={styles.titleText} style={titleTextstyle}>{title}</span>
</div>
:
<div></div>
}
<div className={styles.right}>
{right}
</div>
</div>
<div className={styles.content}>
{children}
</div>
</div>
);
}

index.react.test.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from "react";
import CustomIconList from "./index";
import renderer from "react-test-renderer";
test("CustomIconList render", () => {
const component = renderer.create(
<CustomIconList
style={{ height: 200 }}
headstyle={{ backgroundColor: "#0f0" }}
iconImg="icon-test"
color="#f00"
title="test title"
titleTextstyle={{ fontSize: 12 }}
right={<span>test right</span>}
>
<span>test children</span>
</CustomIconList>
).toJSON();
expect(component).toMatchSnapshot();
});

页面基类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { Component } from "react";
import router from 'umi/router';
import qs from "qs";
import moment from 'moment';
import { RouteComponentProps } from 'react-router';
import { FormComponentProps } from 'antd/lib/form';
import { DispatchProp } from 'react-redux';
interface PageComponentInterface<P = {}, S = {}, SS = any> extends Component<P, S, SS> {
}
interface PropsType extends RouteComponentProps<any>, FormComponentProps, DispatchProp<any>{
}
export default class PageComponent<P extends PropsType, S> extends Component<P, S> implements PageComponentInterface<P, S> {
public searchParams = qs.parse(this.props.location.search, { ignoreQueryPrefix: true });
goBackHandle = () => {
router.goBack();
};
searchResetHandle = () => {
this.props.form.resetFields();
router.push(`?`);
};
searchBtnHandle = (e: React.MouseEvent) => {
e.preventDefault();
this.props.form.validateFields((error, values: Object) => {
if (!error) {
Object.keys(values).forEach(key => {
if (moment.isMoment(values[key])) {
values[key] = (values[key] as moment.Moment).valueOf();
}
});
router.push(`?${qs.stringify({
...values,
})}`);
}
});
};
handlePaginationChange = (page, pageSize) => {
const oldParams = qs.parse(this.props.location.search, { ignoreQueryPrefix: true });
const newParams = { ...oldParams, pageIndex: page, pageSize: pageSize };
if (oldParams.pageSize && oldParams.pageSize != pageSize) {
newParams.pageIndex = 1;
}
router.push(`?${qs.stringify(newParams)}`);
};
}

使用方法:

1
2
3
4
5
6
7
8
9
10
11
import {connect} from 'dva';
import React from "react";
@connect(({ tradePlan, loading }) => ({
list: tradePlan.list,
pagination: tradePlan.pagination,
loading: loading.effects['tradePlan/queryList']
}))
class Index extends PageComponent<PropsType, StateType> {
}

实例上就会挂载基类上的方法

工具类的应用

validator.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface NumberRegClass {
}
interface NumberRegConstructorOptions {
positive: boolean //正数
}
export class NumberReg extends RegExp implements NumberRegClass {
/**
* @param {number} int 整数位
* @param {number} decimals 小数位
* @param {NumberRegConstructorOptions} options? 参数
*/
constructor(int: number, decimals: number, options?: NumberRegConstructorOptions) {
const { positive = false } = options || {};
super(`^(${positive ? '' : '\\-?'})([1-9]\\d{0,${int - 1}}|0)${decimals ? `(\\.\\d{0,${decimals - 1}}[1-9])` : ''}?$`);
}
/**
* 验证bit位的整数
* @param {number} bit 整数位数
* @returns RegExp
*/
static int(bit: number): RegExp { //整数
return new RegExp(`^(\\-?[1-9]\\d{0,${bit - 1}}|0)$`);
}
}

validator.test.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { NumberReg } from './validator';
/// <reference types="jest" />
test('NumberReg test', () => { // 数字正则
const number5and4 = new NumberReg(5, 4);
expect(number5and4.test('12345.1234')).toBe(true);
expect(number5and4.test('-12345.1234')).toBe(true);
expect(number5and4.test('0.1234')).toBe(true);
expect(number5and4.test('-0.1234')).toBe(true);
expect(number5and4.test('12345.12345')).toBe(false);
expect(number5and4.test('12345.120')).toBe(false);
expect(number5and4.test('123456.12')).toBe(false);
expect(number5and4.test('-123456.12')).toBe(false);
});

总结

以上,是部分运用在TypeScript with React的小结而已,感觉通篇的代码也贴得太多了。(然而还有很多不知道怎么描述。
总之,就是让可复用的组件能够独立的进行编写,测试。
为所有的工具类函数提供unit test,才能更完善的服务于业务。

nodejs addon Hello,World

发表于 2017-09-15 | 分类于 NodeJs |

nodejs自身v8的addon可以通过c++实现高效的拓展功能

下面将通过js调用addon输出Hello,World

  • node -v: 8.4.0
  • npm -v: 5.3.0
    较低版本的node好像会有问题,之前用7.*好像不行(逃

首先安装node-gyp,在工程根目录创建binding.gyp

npm install node-gyp -g

1
2
3
4
5
6
7
8
9
binding.gyp
{
"targets": [
{
"target_name": "hello",
"sources": ["native\hello.cc"]
}
]
}

创建native目录并在其中创建.cc文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
hello.cc
#include <node.h>
#include <v8.h>
void Method(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
args.GetReturnValue().Set(
v8::String::NewFromUtf8(isolate, "Hello,World"));
}
void init(v8::Local<v8::Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(hello, init); //arg0与target_name一致

在工程根目录下 node-gyp configure 后会生相应的vs工程在build中,然后在vs中Release

在生成后,写js去调用:

1
2
var hello = require('./build/Release/hello.node').hello();
console.log(hello);

输出结果:
图片

浅谈void运算符

发表于 2017-08-10 | 分类于 web前端 |

最近开了个新坑,其实并不是开坑(逃—兴趣使然,所以想看一下underscore.js的源码,所以俺跟着@hanzichi的解读文章一起了解咯
解读文章地址

关于void运算符,参考自MDN

先放相关地址
MDN对void运算符的解释如下:

The void operator evaluates the given expression and then returns undefined.

就是说 void 运算符 对给定的表达式进行求值,然后返回 undefined。就是说void后面不管跟什么,最后都会返回一个undefined,比如 void 0, void(0), void(1+1) 等等。
在以前的使用中俺只在处理a标签默认事件,当然现在在MDN上查到了更多用法辣

立即调用的函数表达式

在使用立即执行的函数表达式时,可以利用 void 运算符让 JavaScript 引擎把一个函数识别成函数表达式而不是函数声明(语句)。

1
2
3
4
5
6
7
8
9
10
11
12
void function iife() {
var bar = function () {};
var baz = function () {};
var foo = function () {
bar();
baz();
};
var biz = function () {};
foo();
biz();
}();

JavaScript URIs

当用户点击一个以 javascript: URI 时,浏览器会对冒号后面的代码进行求值,然后把求值的结果显示在页面上,这时页面基本上是一大片空白,这通常不是我们想要的。只有当这段代码的求值结果是 undefined 的时候,浏览器才不会去做这件傻事,所以我们经常会用 void 运算符来实现这个需求。像下面这样:

1
2
3
4
5
6
7
8
<a href="javascript:void(0);">
这个链接点击之后不会做任何事情,如果去掉 void(),
点击之后整个页面会被替换成一个字符 0。
</a>
<p> chrome中即使<a href="javascript:0;">也没变化,firefox中会变成一个字符串0 </p>
<a href="javascript:void(document.body.style.backgroundColor='green');">
点击这个链接会让页面背景变成绿色。
</a>

为什么用「void 0」代替「undefined」

在underscore的源码中,没有出现undefined,而用 void 0 代替之,之所以要这么处理是因为undefined在一些情况下可能会被重写,下面列出这几种情况

  1. undefined 并不是保留词(reserved word),它只是全局对象的一个属性,在低版本 IE 中能被重写。

    1
    2
    3
    4
    5
    var undefined = 10;
    // undefined -- chrome
    // 10 -- IE 8
    alert(undefined);
  2. undefined 在 ES5 中已经是全局对象的一个只读(read-only)属性了,它不能被重写。但是在局部作用域中,还是可以被重写的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (function() {
    var undefined = 10;
    // 10 -- chrome
    alert(undefined);
    })();
    (function() {
    undefined = 10;
    // undefined -- chrome
    alert(undefined);
    })();

在进行一些值判断的时候就可以用 void 0 了:

1
2
3
4
var a = [];
// true
a === void 0;

所以综上所述,用「void 0」代替「undefined」是一个正确的选择,而且还可以节省代码空间,事实上,不少 JavaScript 压缩工具在压缩过程中,正是将 undefined 用 void 0 代替掉了。

react-native 学习笔记(三)

发表于 2017-07-11 | 分类于 React-Native |

react-native android打包

之前用create-react-native-app创建的应用在打包方面不是很实用,要通过expo打包,所以之后我使用了官方推荐的react-native-cli来创建应用

搭建开发环境

这一点在文档上已经很清晰了
中文:https://reactnative.cn/docs/0.46/getting-started.html
原文:https://facebook.github.io/react-native/docs/getting-started.html
需要注意的是这里都没有说明在react-native run-android的时候需要启动虚拟机,需要自己在android里面手动启动

打包应用

我把之前做的B/S应用改成了R-N应用,首页上采用了R-N的模块,内页使用了WebView以重用之前的代码

生成签名密钥

打包android应用需要生成一个签名密钥

keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息。最后它会生成一个叫做my-release-key.keystore的密钥库文件。

设置gradle变量

把my-release-key.keystore文件放到你工程中的android/app文件夹下。
编辑C:\Users\用户名.gradle\gradle.properties(没有这个文件你就创建一个),添加如下的代码(注意把其中的**替换为相应密码)

MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*
MYAPP_RELEASE_KEY_PASSWORD=*

添加签名到项目的gradle配置文件

编辑你项目目录下的android/app/build.gradle,添加如下的签名配置:

…
android {
…
defaultConfig { … }
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
…
signingConfig signingConfigs.release
}
}
}
…

修改应用名称和图标

编辑项目目录下的:android\app\src\main\res\values\strings.xml

MyProject
MyProject改成你需要的名字就好了。

图标在android\app\src\main\res文件夹下每个mipmap开头的文件夹下有一个不同尺寸的版本,可以自行输出,也可以使用Android Studio批量修改。

生成发行APK包

运行如下命令:

cd android && ./gradlew assembleRelease
生成的APK文件位于android/app/build/outputs/apk/app-release.apk,即可用于发布

启用Proguard代码混淆来缩小APK文件的大小(可选)

Proguard是一个Java字节码混淆压缩工具,它可以移除掉React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少APK的大小。

重要:启用Proguard之后,你必须再次全面地测试你的应用。Proguard有时候需要为你引入的每个原生库做一些额外的配置。参见app/proguard-rules.pro文件。

要启用Proguard,设置minifyEnabled选项为true:

def enableProguardInReleaseBuilds = true

react-natice 学习笔记(二)

发表于 2017-07-01 | 分类于 React-Native |

一个应用通常是不会只有一个页面的,所以为了实现多页跳转,要用到导航组件

StackNavigator的使用

做一个两页的demo吧,首先创建两个文件,MainScreen.js 和 ProfileScreen.js
在app.js中import

1
2
3
4
5
6
7
8
import { StackNavigator, } from 'react-navigation';
import MainScreen from './MainScreen.js';
import ProfileScreen from './ProfileScreen.js';
export default App = StackNavigator({
Main: {screen: MainScreen},
Profile: {screen: ProfileScreen},
});

通过StackNavigator注册导航,感觉跟路由很像啊
然后分别在MainScreen.js 和 ProfileScreen.js 渲染视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// MainScreen.js:
import React from 'react';
import {
StyleSheet,
Text,
View,
Image,
Button,
Alert
} from 'react-native';
export default class MainScreen extends React.Component {
static navigationOptions = {
title: '首页',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image
source={ require('./images/laopo.jpg') }
style={styles.laopo}
/>
<Text>上面那个是我老婆</Text>
<Button
title="看更多..."
color="#841584"
onPress={() =>
navigate('Profile')
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
laopo: {
width: 450,
height: 500,
left: 40,
top: -80
}
});

可以通过navigate()跳转导航

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// ProfileScreen.js
import React from 'react';
import { StyleSheet, Text, View, ScrollView, Image, Button, NavigatorIOS} from 'react-native';
export default class ProfileScreen extends React.Component {
static navigationOptions = {
title: 'Aimer!!!',
};
render() {
const { navigate } = this.props.navigation;
let content = [];
for (let i = 0; i < myImage.length; i ++) {
content.push(<Image key={i} source={myImage[i]} style={ styles.image }/>);
}
return (
<View style={styles.container}>
{/*<Image source={myImage[0]} style={ styles.image }/>*/}
{ content }
<Button style={ styles.navbar }
title="回首页"
onPress={() =>
navigate('Main')
}
/>
</View>
);
}
}
const myImage = [
require('./images/aimer.jpg'),
require('./images/aimer2.jpg'),
require('./images/aimer_live1.jpg')
]
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
navbar: {
top: 500
},
image: {
height: 200,
margin: 10
}
});

效果如图:
图片
首页的图之前发过了,就不发了

(end)

react-native 学习笔记(一)

发表于 2017-06-30 | 分类于 React-Native |

创建好项目之后,现在就可以修改app.js并保存看效果了

一些基本组件的使用

图片
这里列出了几个上手的组件,通过props添加属性,这里以Image举例:

Image

1
2
3
4
<Image
source={ require('./images/laopo.jpg') }
style={styles.laopo}
/>

source属性可以指定一个图片的地址,可以是一个对象

1
source={{ url: '/image.jpg' }}

也可以用 require() 引入静态资源。

StyleSheet

这里要讲一下style的定义方式,可以直接

1
2
3
4
sytle={{
width: 400,
height: 400
}}

当然更推荐的是在代码内用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
laopo: {
width: 450,
height: 500,
left: 40,
top: -80
}
});

然后再style属性里如上的方式添加样式,跟css的属性还是比较有出入,这些就去看文档就好啦

Button

1
2
3
4
5
6
7
<Button
title="看更多..."
color="#841584"
onPress={() =>
console.log('button被点击了')
}
/>

onPress是button被按下时的时间,在可点击的组件里都可以注册这个事件

在需要捕捉用户点击操作时,可以使用”Touchable”开头的一系列组件。这些组件通过onPress属性接受一个点击事件的处理函数。当一个点击操作开始并且终止于本组件时(即在本组件上按下手指并且抬起手指时也没有移开到组件外),此函数会被调用。

基本API

这里说几个基本的API吧,最基本的莫过于Alert了

Alert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<Button
title="Click Me!!"
onPress={() => {
Alert.alert(
'标题',
'内容',
[
{text: '嘿嘿嘿', onPress: () => console.log('嘿嘿嘿')},
{text: '取消', onPress: () => console.log('取消'), style: 'cancel'},
{text: '确定', onPress: () => console.log('确定')},
],
{ cancelable: false }
);
}}
/>

这一看就能看懂吧。。。效果如图
图片

AlertIOS

这个是针对IOS用的,启动一个允许用户输入的对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
AlertIOS.prompt(
'标题',
'内容',
[
{text: '嘿嘿嘿', onPress: () => console.log('嘿嘿嘿')},
{text: '取消', onPress: () => console.log('取消'), style: 'cancel'},
{text: '确定', onPress: () => console.log('确定')},
],
(promptData) => {
console.log(promptData)
}
);
/>

(end)

react-native 初探

发表于 2017-06-29 | 分类于 React-Native |

前端圈聊这个react-native也好长一段时间了,以前也写过一段时间react,不是react吹,所以一直没玩这个native,看来我还是naive啊。

Getting Started

我现在用的ios手机,但是我没macOS啊,所以只有用Create React Native App这个工具了,官网是这么说的,反正就是可以直接跑在手机上啦,但是不能用第三方的组件。

Create React Native App is the easiest way to start building a new React Native application. It allows you to start a project without installing or configuring any tools to build native code - no Xcode or Android Studio installation required (see Caveats).

安装

首先安装Create React Native App

1
npm install -g create-react-native-app

这里要注意npm的版本问题,必需用npm@4.x的版本。
notSupport
如果遇到这种报错,就需要手动先安装react
needReact

1
npm install -g react

创建&启动

安装好之后就可以创建项目啦,创建后进入项目目录然后执行npm start

1
2
3
create-react-native-app FirstApp
cd FirstApp
npm start

一切就绪之后命令行中就会显示二维码,在appStore里面下载安装Expo扫码就可以预览项目了。
如下:
guide
点击Got it按钮
显示的页面就是项目目录下app.js的内容了,修改app.js并保存,页面会自动刷新。

(end)

git命令参考手册

发表于 2017-06-29 | 分类于 其他 |

收藏到这里,以后用的时候好找;不知道扔什么分类了,参考手册?就其他吧…

命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
git init # 初始化本地git仓库(创建新仓库)
git config --global user.name "xxx" # 配置用户名
git config --global user.email "xxx@xxx.com" # 配置邮件
git config --global color.ui true # git status等命令自动着色
git config --global color.status auto
git config --global color.diff auto
git config --global color.branch auto
git config --global color.interactive auto
git clone git+ssh://git@192.168.53.168/VT.git # clone远程仓库
git status # 查看当前版本状态(是否修改)
git add xyz # 添加xyz文件至index
git add . # 增加当前子目录下所有更改过的文件至index
git commit -m 'xxx' # 提交
git commit --amend -m 'xxx' # 合并上一次提交(用于反复修改)
git commit -am 'xxx' # 将add和commit合为一步
git rm xxx # 删除index中的文件
git rm -r * # 递归删除
git log # 显示提交日志
git log -1 # 显示1行日志 -n为n行
git log -5
git log --stat # 显示提交日志及相关变动文件
git log -p -m
git show dfb02e6e4f2f7b573337763e5c0013802e392818 # 显示某个提交的详细内容
git show dfb02 # 可只用commitid的前几位
git show HEAD # 显示HEAD提交日志
git show HEAD^ # 显示HEAD的父(上一个版本)的提交日志 ^^为上两个版本 ^5为上5个版本
git tag # 显示已存在的tag
git tag -a v2.0 -m 'xxx' # 增加v2.0的tag
git show v2.0 # 显示v2.0的日志及详细内容
git log v2.0 # 显示v2.0的日志
git diff # 显示所有未添加至index的变更
git diff --cached # 显示所有已添加index但还未commit的变更
git diff HEAD^ # 比较与上一个版本的差异
git diff HEAD -- ./lib # 比较与HEAD版本lib目录的差异
git diff origin/master..master # 比较远程分支master上有本地分支master上没有的
git diff origin/master..master --stat # 只显示差异的文件,不显示具体内容
git remote add origin git+ssh://git@192.168.53.168/VT.git # 增加远程定义(用于push/pull/fetch)
git branch # 显示本地分支
git branch --contains 50089 # 显示包含提交50089的分支
git branch -a # 显示所有分支
git branch -r # 显示所有原创分支
git branch --merged # 显示所有已合并到当前分支的分支
git branch --no-merged # 显示所有未合并到当前分支的分支
git branch -m master master_copy # 本地分支改名
git checkout -b master_copy # 从当前分支创建新分支master_copy并检出
git checkout -b master master_copy # 上面的完整版
git checkout features/performance # 检出已存在的features/performance分支
git checkout --track hotfixes/BJVEP933 # 检出远程分支hotfixes/BJVEP933并创建本地跟踪分支
git checkout v2.0 # 检出版本v2.0
git checkout -b devel origin/develop # 从远程分支develop创建新本地分支devel并检出
git checkout -- README # 检出head版本的README文件(可用于修改错误回退)
git merge origin/master # 合并远程master分支至当前分支
git cherry-pick ff44785404a8e # 合并提交ff44785404a8e的修改
git push origin master # 将当前分支push到远程master分支
git push origin :hotfixes/BJVEP933 # 删除远程仓库的hotfixes/BJVEP933分支
git push --tags # 把所有tag推送到远程仓库
git fetch # 获取所有远程分支(不更新本地分支,另需merge)
git fetch --prune # 获取所有原创分支并清除服务器上已删掉的分支
git pull origin master # 获取远程分支master并merge到当前分支
git mv README README2 # 重命名文件README为README2
git reset --hard HEAD # 将当前版本重置为HEAD(通常用于merge失败回退)
git rebase
git branch -d hotfixes/BJVEP933 # 删除分支hotfixes/BJVEP933(本分支修改已合并到其他分支)
git branch -D hotfixes/BJVEP933 # 强制删除分支hotfixes/BJVEP933
git ls-files # 列出git index包含的文件
git show-branch # 图示当前分支历史
git show-branch --all # 图示所有分支历史
git whatchanged # 显示提交历史对应的文件修改
git revert dfb02e6e4f2f7b573337763e5c0013802e392818 # 撤销提交dfb02e6e4f2f7b573337763e5c0013802e392818
git ls-tree HEAD # 内部命令:显示某个git对象
git rev-parse v2.0 # 内部命令:显示某个ref对于的SHA1 HASH
git reflog # 显示所有提交,包括孤立节点
git show HEAD@{5}
git show master@{yesterday} # 显示master分支昨天的状态
git log --pretty=format:'%h %s' --graph # 图示提交日志
git show HEAD~3
git show -s --pretty=raw 2be7fcb476
git stash # 暂存当前修改,将所有至为HEAD状态
git stash list # 查看所有暂存
git stash show -p stash@{0} # 参考第一次暂存
git stash apply stash@{0} # 应用第一次暂存
git grep "delete from" # 文件中搜索文本“delete from”
git grep -e '#define' --and -e SORT_DIRENT
git gc
git fsck

我要放我老婆照片了!!
老婆

重写console下的方法

发表于 2017-06-29 | 分类于 web前端 |

实现方式

还是最近在做的移动端调试工具,需要重写window.console对象,通过重写可以将之后代码中的控制台输出映射到自己的输出面板中。
上代码,重写的逻辑是很简单的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
var tempFunction, color,
output = document.querySelector('#output');
for (var key in console) {
if (key.match(/log|debug|error|info|warn|dir/)) {
tempFunction = console[key];
switch (key) {
case 'log':
color = '#1F2D3D';
break;
case 'debug':
color = '#1D8CE0';
break;
case 'error':
color = '#FF4949';
break;
case 'info':
color = 'blue';
break;
case 'warn':
color = '#F7BA2A';
break;
case 'dir':
color = '#58B7FF';
break;
default:
color = '#1F2D3D';
break;
}
(function (color, tempFunction) {
console[key] = function () {
var result = '';
for (var i = 0; i < arguments.length; i ++) {
if ('object' == typeof arguments[i]) {
//TODO
//递归遍历对象控制输出,这里不做演示,在我的ajax-watcher库里是用的jquery插件
} else {
result += arguments[i];
}
}
var element = document.createElement("p");
element.style.color = color;
element.innerText = result;
output.appendChild(element);
tempFunction.apply(console, arguments);
}.bind(window);
})(color, tempFunction);
}
}

详情解释

  1. for (var key in console) 遍历console对象,因为console对象下并不是所有方法都需要重写,所以这里用key.match(/log|debug|error|info|warn|dir/)筛选出需要重写的方法
  2. tempFunction = console[key]; 用临时遍历保存console下的方法,并根据key更换最后需要显示的颜色
  3. 闭包保留color和tempFunction,直接console[key] = function () {};重写console下的方法
  4. 重写方法的内部实现根据需求来写

浏览器中监听全局的报错API

发表于 2017-06-27 | 分类于 web前端 |

onerror事件

window对象下可以通过onerror事件监听全局的抛错信息。
最近在做一个移动端的调试工具库,所以了解了一下这个API,使用方法如下:

1
2
3
window.onerror = function (message, source, lineno, colno, error) {
//Todo
};

参数介绍

这里只能给onerror赋值,不能通过window.addEventListener添加事件监听。

  • message 错误信息
  • source 错误来源(来源文件)
  • lineno 报错行
  • colno 报错列
  • error error对象
12
vldh

vldh

一个在浅色床单上哭泣的失败者的博客

13 日志
4 分类
12 标签
GitHub weibo
© 2017 - 2018 vldh
由 Hexo 强力驱动
主题 - NexT.Pisces