Commit 2f6a9aef authored by shangbj's avatar shangbj

init

parents
# 前端组wiki
### 前端组相关hosts
```
192.168.155.65 gitlab.dev.daikuan.com
192.168.145.8 wiki.dev.daikuan.com
192.168.145.8 dashboard.dev.daikuan.com
192.168.145.8 placehold.it
192.168.155.149 rap.crm.yxqiche.com
```
### dashboard站点
http://dashboard.dev.daikuan.com
### wiki项目
```bash
git clone http://gitlab.dev.daikuan.com/fe/wiki.git
```
### 使用说明
* SUMMARY.md为左边栏目录
* 所有文件通过markdown格式来写, .md命名
* 直接在master编写, push后自动更新
# Summary
* [简介](./README.md)
### 环境
* [基础环境](环境/基础环境.md)
* [配置npm源](环境/配置npm源.md)
* [sync命令](环境/sync命令.md)
* [测试机器](环境/测试机器.md)
* [远端构建机器环境](环境/远端构建机器环境.md)
### 项目相关
* [上线流程](项目相关/上线流程.md)
* [npm依赖版本管理](项目相关/npm依赖版本管理.md)
* [yarn/npm](项目相关/yarn.md)
* [crm项目踩坑](项目相关/crm项目踩坑.md)
* [gulp/webpack项目区别(deprecated)](项目相关/gulp项目与webpack项目命令区别.md)
* [gulp项目文档(deprecated)](项目相关/gulp项目文档.md)
### 规范
* [vue编码规范](规范/vue编码规范.md)
* [ES6编码规范](规范/es6编码规范.md)
* [分支开发规范](规范/分支开发规范.md)
### git
* [git基本使用](git/git基本使用.md)
* [git分支管理策略](git/git分支管理策略.md)
### TypeScript
* [为什么要学习TypeScript](typescript/为什么要学习TypeScript.md)
* [TypeScript环境搭建](typescript/TypeScript环境搭建.md)
* [TypeScript基本类型](typescript/TypeScript基本类型.md)
### 其它
* [推荐网站](其它/推荐网站.md)
* [文档](其它/文档.md)
\ No newline at end of file
# git工作流
### 工作流
基于gitflow, 简化版本
参考文档: http://nvie.com/posts/a-successful-git-branching-model/
区别: 不设`release`, `develop`分支, 暂不打tag, 保留`master`, `feature/*`, `hotfix/*`
### 项目
`feprogram/taoche`等项目锁定master, 不允许直接在master下改动,需要提交merge request进行review
`act`等项目进行敏捷开发, 不锁定master, 分支自行管理
`crm`等项目设立develop分支,特性分支开发完成后合并入develop, master分支从develop单向merge
### 工作流程
1. 基于最新master建立分支,功能分支`feature/xxx` 或 线上bug修复分支 `hotfix/xxx`
2. 在分支下开发
3. 开发完成, merge master到当前分支,release灰度/上线。
# git基本使用
#### 开始
```
git config --global user.name xxx
git config --global user.email xxx
```
#### 基本命令
* git checkout -b xxx : 创建分支并切换到分支xxx
* git status : 查看当前分支状态
* git add . : 将新添加的文件加入暂存区
* git commit -am “注释” :添加并提交所有修改文件
* git merge xxx : 将xxx(本地)分支的代码合并到当前分支
* git pull : 从远端获取, 或git pull origin xxx(分支名)
* git push : 更新到远端, 或git push origin xxx(分支名)
* git add filename : 添加未跟踪的文件到暂存区
* git add . : 添加所有未跟踪的文件到暂存区
* git log : 日志
#### 使用合并流程
1. [master下]创建分支: `git checkout -b xxx`
2. [分支下] 开发代码并不断commit, 开发完毕
3. [分支下] 切换到master: `git checkout master`
3. [master下] 更新代码: `git pull`
4. [master下] 切换到分支xxx: `git checkout xxx`
5. [分支下] 合并master到分支: `git merge master`
6. [分支下] 切换master: `git checkout master`
7. [master下] 合并分支xxx到master: `git merge xxx`
8. [master下] 更新到远端 `git push`
#### 分支命名
建议采用git-flow规范:
1. 新项目,新功能: feature/xxx
2. 快速更改,修复bug: hotfix/xxx
#### 注意事项
1. windows下客户端: sourcetree(注册需翻墙), tortoiseGit, mac下客户端: sourcetree, tower
2. master分支尽量不要进行耗时项目开发,远端master要保持随时可以上线版本
3. push之前要先pull
4. 所有命令操作都在根目录下执行。
5. 不建议单文件commit, 每次commit都是提交当前所有的修改
#### alias 别名
使用命令行的同学可以在git bash里 `vi ~/.gitconfig`, 将下面别名加入文件末尾:
```
[alias]
cm = commit
co = checkout
ac = !git add -A && git commit
st = status -sb
tags = tag -l
branches = branch -a
cleanup = git config --global alias.cleanup "git branch --merged | grep -v '*' | xargs git branch -d"
remotes = remote -v
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --
```
\ No newline at end of file
# 基本类型 LIST
### TypeScript基本类型有如下几种:
#####Boolean
#####Number
#####String
#####Array
#####Tuple
#####Enum
#####Any
另外还有void类型,主要用于标识方法返回值的类型。
```javascript
// Boolean
let isDone: boolean = false;
isDone = true;
// Number
let num: number = 1; // 整数
num = 2.5; // 小数
num = 0xf00d; // 十六进制
num = 0b0101; // 二进制
num = 0o123; // 八进制
// String
let str: string = 'Hello world';
let content: string = `${str} too`; // 使用表达式拼接字符串时,需要使用(`)符号将拼接内容包括起来
// Array
let numbers1: number[] = [1, 2];
let numbers2: Array<number> = [1, 2, 3]; // 另外一种定义数组类型的方式,与nunber[]等价
// Tuple(元组类型)
let t: [string, number] = ['No.', 1];
t = ['This is No.', 2]; // 值类型与定义的一致,编译通过。
//t = [2, 'This is No.']; // 值类型与定义的不一致,编译失败,提示错误。
// Enum(枚举)
enum Operator1 { Add, Update, Delete, Select };
let opt1: Operator1 = Operator1.Add; // opt1的值为0。取枚举项的默认值。
enum Operator2 { Add = 1, Update, Delete, Select };
let opt2: Operator2 = Operator2.Update; // opt2的值为2。当某一项设置了值后,后续项的值都顺次加1。
let opt2Name: string = Operator2[2]; // opt2Name的值为Update。通过值索引可以得到枚举项的名称。
```
#####另外,Any类型是一个特殊的类型。它表示当前对象的类型由具体的值的类型来确定,它可以适用于任何强类型。
```javascript
// Any
let obj: any = 'This is a string.';
obj = 1;
obj = [1, 2];
obj = false;
obj = {};
obj = function () { return false; };
```
#####Any类型的值可以通过强制类型转换将值转换成目标类型
```javascript
// 强制类型转换
let obj1: any = 'This is a string.';
let len: number = (<string>obj1).length;
len = (obj1 as string).length;
```
#####将以上代码进行编译后将转换成ES5标准的JavaScript源码,如下
```javascript
// Boolean
var isDone = false;
isDone = true;
// Number
var num = 1; // 整数
num = 2.5; // 小数
num = 0xf00d; // 十六进制
num = 5; // 二进制
num = 83; // 八进制
// String
var str = 'Hello world';
var content = str + " too"; // 使用表达式拼接字符串时,需要使用(`)符号将拼接内容包括起来
// Array
var numbers1 = [1, 2];
var numbers2 = [1, 2, 3]; // 另外一种定义数组类型的方式,与nunber[]等价
// Tuple(元组类型)
var t = ['No.', 1];
t = ['This is No.', 2]; // 值类型与定义的一致,编译通过。
//t = [2, 'This is No.']; // 值类型与定义的不一致,编译失败,提示错误。
// Enum(枚举)
var Operator1;
(function (Operator1) {
Operator1[Operator1["Add"] = 0] = "Add";
Operator1[Operator1["Update"] = 1] = "Update";
Operator1[Operator1["Delete"] = 2] = "Delete";
Operator1[Operator1["Select"] = 3] = "Select";
})(Operator1 || (Operator1 = {}));
;
var opt1 = Operator1.Add; // opt1的值为0。取枚举项的默认值。
var Operator2;
(function (Operator2) {
Operator2[Operator2["Add"] = 1] = "Add";
Operator2[Operator2["Update"] = 2] = "Update";
Operator2[Operator2["Delete"] = 3] = "Delete";
Operator2[Operator2["Select"] = 4] = "Select";
})(Operator2 || (Operator2 = {}));
;
var opt2 = Operator2.Update; // opt2的值为2。当某一项设置了值后,后续项的值都顺次加1。
var opt2Name = Operator2[2]; // opt2Name的值为Update。通过值索引可以得到枚举项的名称。
// Any
var obj = 'This is a string.';
obj = 1;
obj = [1, 2];
obj = false;
obj = {};
obj = function () { return false; };
// 强制类型转换
var obj1 = 'This is a string.';
var len = obj1.length;
len = obj1.length;
```
###方法
#####一、方法标准声明和使用
```javascript
// 方法声明
function func(x: number, y: number): number {
return x + y;
}
```
在TypeScript里,方法声明可以明确定义每一个参数的类型,和返回值的类型。在编译时,编译器会检查方法体的返回值类型是否符合定义的类型,同时在调用的时候也会检查传入的参数类型是否符合定义的类型,参数个数是否符合定义的个数。
```javascript
let result1 = func(1, 2); // 正确的调用方式。
let result2 = func_lambda(1, 2, 3); // 错误的调用方式。参数个数多余定义。
let result3 = func_lambda(1); // 错误的调用方式。参数个数少于定义。
let result4 = func_lambda('1', '2'); // 错误的调用方式。参数类型不符合定义。
```
方法声明也支持使用Lambda表达式。
```javascript
// lambda表达式声明
let func_lambda: (x: number, y: number) => number = function (x, y) { return x + y };
```
#####二、缺省参数声明
TypeScript也支持缺省参数的声明方式。
```javascript
// 缺省参数定义
let showName = function (firstName: string, lastName?: string): string {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
};
let wholeName1 = showName('小亮', 'Xiaoliang');
let wholeName2 = showName('小亮');
```
通过在参数名称后面加上?,标识该参数是缺省的,调用时如果对应参数位置不传入,对应参数位置则为undefined。
#####三、默认值参数声明
```javascript
// 默认值参数定义
let showName2 = function (firstName: string, lastName = 'Lee'): string {
return firstName + ' ' + lastName;
};
let wholeName3 = showName2('小亮');
```
通过在参数名称后加上=号并赋值,标识该参数具有默认值。调用时如果对应参数位置不传入或者传入undefined,则取默认值,否则取对应位置传入的值。
#####四、多参数声明
```javascript
// 默认值参数定义
// 多参数定义
let restParamsFunc = function (param1: string, ...restParams: string[]): string {
return param1 + ' ' + restParams.join(' ');
};
let resParamsFuncResult = restParamsFunc('a', 'b', 'c');
```
通过在参入名称前加上...(三个小数点),标识对应位置的参数可以传入多个。因为参数类型已明确定义,所以传入的多个参数的类型必须与定义保持一致,否则编译时将提示错误。
#####五、其他类型参数声明
#####对象类型:
```javascript
// 对象类型参数
let jsonParamFunc = function (x: { p1: string }): string {
return x.p1;
};
let jsonParamFuncResult1 = jsonParamFunc({ p1: 'a' }); // 赋值类型正确
let jsonParamFuncResult2 = jsonParamFunc({ p1: 'a', p2: 'b' }); // 赋值类型错误,参数属性比定义的多。
let jsonParamFuncResult3 = jsonParamFunc({ p3: 'c' }); // 复制类型错误,参数属性名不匹配。
let params = { p1: 'a', p2: 'b' };
let jsonParamFuncResult4 = jsonParamFunc(params); // 用变量代替直接复制,编译器检查通过。
```
#####方法类型:
```javascript
// 方法类型参数
let funcParamFunc = function (func: (x: string, y: string) => string): string {
let _x = 'a';
let _y = 'b';
return func(_x, _y);
};
let funParamFuncResult = funcParamFunc(function (x, y) { return x + y });
```
方法参数类型可定义为一个固定结构的方法,该方法就成为了一个回调方法。
#####六、方法重载
```javascript
// 方法重载
function overloadFunc(x: { p1: string }): string;
function overloadFunc(x: number): number;
function overloadFunc(x): any {
if (typeof x == 'object') {
return x.p1;
}
if (typeof x == 'number') {
return x;
}
}
let overloadFuncResult1 = overloadFunc({ p1: 'a' });
let overloadFuncResult2 = overloadFunc(1);
```
\ No newline at end of file
# 环境搭建 LIST
### 特性
#####可选的静态类型
#####枚举、接口和类
#####命名空间
#####模块
#####Lambda表达式
#####编译时类型检查
在2013年6月微软正式发布了0.9版。之后在不断更新的过程中逐渐支持ECMAScript 2015(ES6)标准。
###环境准备
#####安装Node.js
安装文件下载地址:Node.js Downloads。TypeScript源码需要进行编译以后才能运行,Node.js提供了编译环境。
#####安装TypeScript编译工具
安装好Node.js后,打开cmd窗口,输入以下命令
npm install -g typescript
使用npm包管理工具下载TypeScript包并在全局环境下安装,安装成功后就可以通过 tsc 命令编译TypeScript源码。
可以通过 tsc -v 命令查看当前TypeScript版本。
###开发
主要包括但不限于以下几个目录和文件
/ts:TypeScript源码文件存放的文件夹
/js:编译之后生成的JavaScript文件存放的文件夹
tsconfig.json:TypeScript编译配置文件
#####tsconfig.json
```javascript
{
"compilerOptions": {
"target": "es5",
"noImplicitAny": false,
"module": "commonjs",
"removeComments": true,
"sourceMap": false,
"outDir": "js"
},
"include":[
"ts"
],
"exclude": [
"js"
]
}
```
有几个重要的属性需要解释一下:
target:编译之后生成的JavaScript文件需要遵循的标准。有三个候选项:es3、es5、es2015。
noImplicitAny:为false时,如果编译器无法根据变量的使用来判断类型时,将用any类型代替。为true时,将进行强类型检查,无法推断类型时,提示错误。
module:遵循的JavaScript模块规范。主要的候选项有:commonjs、AMD和es2015。为了后面与node.js保持一致,我们这里选用commonjs。
removeComments:编译生成的JavaScript文件是否移除注释。
sourceMap:编译时是否生成对应的source map文件。这个文件主要用于前端调试。当前端js文件被压缩引用后,出错时可借助同名的source map文件查找源文件中错误位置。
outDir:编译输出JavaScript文件存放的文件夹。
include、exclude:编译时需要包含/剔除的文件夹。
#####添加Demo源文件
在ts文件夹添加 app.ts 和 demo.ts 两个源文件
##### Demo.ts
```javascript
/**
* Demo
*/
class Demo {
a: number;
b: number;
constructor(a: number, b: number) {
this.a = a;
this.b = b;
}
sum(): number {
return this.a + this.b;
}
}
export {Demo};
```
##### app.ts
```javascript
/**
* app.ts
*/
import {Demo} from './models/demo';
const demo = new Demo(1, 2);
console.log(demo.sum());
```
###配置编译和调试文件
在.vscode里添加tasks.json文件
```javascript
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "tsc",
"isShellCommand": true,
"args": ["-p", "."],
"showOutput": "always",
"problemMatcher": "$tsc"
}
```
修改生成的launch.json文件内容,指定启动入口文件的路径
```javascript
{
"version": "0.2.0",
"configurations": [
{
"name": "启动",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/js/app.js",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": null,
"runtimeArgs": [
"--nolazy"
],
"env": {
"NODE_ENV": "development"
},
"externalConsole": false,
"sourceMaps": false,
"outDir": null
},
]
}
```
以上配置完成后,使用 Ctrl+Shift+B 启动编译,如果VS Code的OUTPUT窗口没有任何异常信息显示,则表示编译成功。在js文件夹里将会生成编译后的JavaScript文件
#####demo.js
```javascript
"use strict";
var Demo = (function () {
function Demo(a, b) {
this.a = a;
this.b = b;
}
Demo.prototype.sum = function () {
return this.a + this.b;
};
return Demo;
}());
exports.Demo = Demo;
```
#####app.js
```javascript
"use strict";
var demo_1 = require('./models/demo');
var demo = new demo_1.Demo(1, 2);
console.log(demo.sum());
```
\ No newline at end of file
# 为什么要学习TypeScript LIST
### 前言
随着Node.js的流行,JavaScript已经随处可见。但同时,你也一定意识到,随着JavaScript应用的复杂度和大小不断增加,管理JavaScript项目已经越来越困难了。正是基于此,TypeScript开始进入人们的视野
###TypeScript的前世今生
TypeScript是一种免费开源的编程语言,它由Microsoft主导研发。TypeScript作为JavaScript的超集,它的语法更严格,我们在编写代码的时候就能够发现大部分错误。不仅如此,按照TypeScript官方的说法,TypeScript使得我们能够以JavaScript的方式实现自己的构思。TypeScript对面向对象的支持也非常完善,它拥有面向对象编程语言的所有特性。
学习网站:http://www.typescriptlang.org/
###ECMAScript和TypeScript
ECMAScript是JavaScript的一种规范。目前ECMAScript 6还只是作为测试版发行,ECMAScript 5和一些浏览器实现了对ECMAScript 6的支持。TypeScript继承了ECMAScript 6的大部分语法,因此你不必重新学习它。官方计划在TypeScript 1.6引入ES6迭代器,以便你将TypeScript代码转换为ECMAScript 6的代码。
###开发工具
大多数的Web开发工具,不管它是免费的还是收费的,都支持TypeScript开发。大部分编辑器,比如Visual Studio,Visual Studio Code,WebStorm,Atom,Sublime text或者Eclipse,都对TypeScript有非常完善的支持。
###为什么要用TypeScript
1. 完全的面向对象,类和对象。基于此,TypeScript将成为提高开发人员开发效率的利器,它很容易理解和接受。
2. 在编写代码的阶段,TypeScript就能够找到大部分的错误,而JavaScript在这方面就没那么友好了
3. 相比JavaScript,TypeScript的重构也更容易。
\ No newline at end of file
# 推荐网站
### 文章/订阅
* 奇舞周刊: https://weekly.75team.com/
* awesome-vue: https://github.com/vuejs/awesome-vue#libraries--plugins
* 阮一峰: http://www.ruanyifeng.com/blog/
### 工具类
* linux命令查询: http://man.linuxde.net/
* es6浏览器支持: http://ruanyf.github.io/es-checker/index.cn.html
* pagespeed insights: https://developers.google.com/speed/pagespeed/insights/
* 微信接口校验: https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
* Caniuse: http://caniuse.com/
* bootCDN: http://www.bootcdn.cn/
* codePen: https://codepen.io/pen
* jquery替代: http://youmightnotneedjquery.com/
* 正则检查: http://www.regexpal.com/
* 屏幕尺寸: http://screensiz.es/phone
# 文档
### git
* gitflow工作流: http://nvie.com/posts/a-successful-git-branching-model/
### html相关
* https://www.w3.org/TR/html5/
### css相关
* CSS参考手册: http://www.css88.com/book/css/
* Sass中文文档: http://www.css88.com/doc/sass/
* bourbon: http://bourbon.io/docs/
### javascript相关
* javascript标准参考教程: http://javascript.ruanyifeng.com/
* Node.js: https://nodejs.org/dist/latest-v6.x/docs/api/
* 阮一峰es6文档: http://es6.ruanyifeng.com/
* ES6 feature: https://github.com/ES-CN/es6features/blob/master/README.md
* jquery: http://w3school.com.cn/jquery/jquery_reference.asp
* TypeScript中文文档:http://www.css88.com/doc/typescript/
### vue相关(1.x)
* vue: https://v1.vuejs.org/api/
* vue-router: https://github.com/vuejs/vue-router/tree/1.0/docs/zh-cn
* vue-resource: https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
### vue相关(2.x)
* vue: https://cn.vuejs.org/v2/api/
* vue-router: https://router.vuejs.org/
* vuex: https://vuex.vuejs.org/
* ssr: https://ssr.vuejs.org/
### 类库及工具相关
* webpack2中文文档: http://www.css88.com/doc/webpack2/
* webpack3中文文档: http://www.css88.com/doc/webpack/
* Parcel中文文档:http://www.css88.com/doc/parcel/
* Markdown入门参考: http://xianbai.me/learn-md/
* emoji图标: https://www.webpagefx.com/tools/emoji-cheat-sheet/
* iscroll5: http://iscrolljs.com/
* React-router: https://react-guide.github.io/react-router-cn/docs/API.html
* Ramda: http://ramdajs.com/docs/
* Ramda函数参考: http://www.ruanyifeng.com/blog/2017/03/ramda.html
* React0.14.x: http://react-ie8.xcatliu.com/
* Swiper3: http://idangero.us/swiper/api/#.WA3XgZN97IE
* Swiper2: http://2.swiper.com.cn/api/index.html
* Chartjs: http://www.chartjs.org/docs/latest/
* Immutable: http://facebook.github.io/immutable-js/docs/#/
* 百度地图api: http://lbsyun.baidu.com/index.php?title=jspopular/guide/introduction
* Chrome 开发者工具中文文档: http://www.css88.com/doc/chrome-devtools/
* ant.Design: https://ant.design/index-cn#/docs/react/introduce
\ No newline at end of file
# sync命令
各系统 `npm run sync`依赖于系统命令rsync, windows用户默认没有安装rsync,需要单独安装windows版本的cwRsync, 下载地址
http://dl.pconline.com.cn/download/402117-1.html
\ No newline at end of file
# 基础环境
#### nodejs
>`>= 8`
>LTS版本
>download: https://nodejs.org/en/
#### npm
> `>= 5.3`
#### yarn
> `>= 1.6`
```bash
npm install -g yarn
```
\ No newline at end of file
# 测试机器
### 可用测试机
* dev1: 192.168.145.9:8011
* dev2: 192.168.145.9:8013
* beta1: 192.168.154.243:8011
* beta2: 192.168.154.243:8013
### 将dist目录同步到测试机(项目需要依赖sync模块)
`npm run sync [dev|beta|dev1|dev2|beta1|beta2]`
```bash
# 同步dev1, dev2
npm run sync dev
# 同步dev2
npm run sync dev2
# 同步所有测试机
npm run sync
```
\ No newline at end of file
### 远端构建环境
> ip 192.168.145.8
> centos 6.7
> nodejs 8.9.3
> yarn 1.7.0
> npm 6.0.0
# 配置npm源
使用以下脚本(terminal或git bash):
```bash
curl -s http://gitlab.dev.daikuan.com/npm/install_env/raw/master/install.sh | sh
```
脚本会执行如下操作:
* 安装yarn
* 配置npm/yarn淘宝源
* 清空已有npm/yarn缓存
\ No newline at end of file
This diff is collapsed.
# VUE组件编码规范
### 相关文档
* vue 1.x: [http://v1.vuejs.org/api/]
* vue-ressource 1.x: [https://github.com/pagekit/vue-resource/blob/develop/docs/http.md]
* vue-router 0.x: [https://github.com/vuejs/vue-router/tree/1.0/docs/zh-cn]
`请注意区分项目使用的库版本及相关文档,以上三个包都在vue.dll.js依赖包里`
### 项目通过组件来规划
```
// 示例项目aaa
aaa/
components/ : 项目内组件
pages/ : 项目视图存放目录
html/: 项目页面存放目录
index.hbs
index.js: 项目入口文件
// index.hbs , 尽量只用一个标记,无其他内容
<div id="main">
// 如果有seo相关内容,凡在里面,作为slot插入组件内
<div class="banner" slot="banner"></div>
</div>
// index.js
// 若项目不复杂,可直接使用template
new Vue({
el: '#main',
template: `
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
`,
components: {componentA,componentB,componentC}
})
// 相对复杂的项目或使用路由的项目,建立页面级别的组件
new Vue({
el : '#main',
template: `<index></index>`,
components: {Index}
})
// pages/index.vue
<template>
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
<template>
<script>
export default {
name: 'index'
}
</script>
```
### 目录划分
* libs/vue-components : 用于存放全项目公用的vue组件
* xxx/components: 比如xinche.m/components, 用于存放单一项目公用的vue组件, 或跟此单一项目业务强相关的vue组件
* xxx/yyy/components: 比如xinche.m/about/components, 用于存放子项目自己使用的vue组件,一般不提供给外部其他项目使用
### 公用组件目录结构
```
xxx/
index.vue : 主组件文件
*.png/*.gif : 组件使用的图片(公用组件尽量不要使用大于10k的图片)
README.md: 组件使用说明文档
```
### 组件命名
* 有意义的, 简短,具有可读性。2-3个单词
* 符合自定义元素规范,使用-连字符分隔单词, 如app-header
### 组件单一原则
* 每一个vue组件专注于解决单一的问题,独立,可复用
* 一个组件尽量不要超过100行,如果组件太臃肿,需要拆分成更小的组件
### props原子化
组件的props尽量使用原始数据类型,避免使用复杂对象
```
// 不适用复杂对象
const option = {title:'xxx', inApp: true}
<app-header :option="option"></app-header>
// 使用原始数据类型
// 注意inApp驼峰的props书写在组件标记内需要改成in-app类型
// 注意props值传入的如果不是字符串,需要v-bind:props来绑定
<app-header title="xxx" :in-app="true"></app-header>
```
### 验证组件的props
```
// 尽量不使用简写props
export default {
props: ['title', 'isApp']
}
// 验证props
export default {
props: {
title: {
type: String,
default: ,
required: true
},
isApp: {
type: Boolean,
default: false
}
}
}
```
### 合理使用this
```
// 组件内不要出现如下之类
const self = this
// 充分利用es6特性,使用this
created(){
this.title = 123
}
```
### 组件使用name
```
// 单一组件的导出不建议指定名称, 直接使用default导出
export default {}
// 组件建议添加name属性
export default {
name: 'appHeader"
}
```
### 组件不要使用双向绑定的props
```
// 不要使用.sync类型的props
<app-header :title.sync="title"></app-header>
export default {
props: {
type: String,
twoway: true
}
}
// 子组件通知父级数据变更,应采用调用父级传入的函数型props回调,或者事件通知的方式
```
### 避免使用this.$parent
直接访问上下文降低了组建的复用性,应避免使用,尽量通过事件通知
### 尽量使用this.$http而不是jquery.ajax
```
vue组件应尽量使用自己的resource插件,符合promise规范
// 最外层需要将插件引入
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
```
### 组件内尽量不要直接使用window上的全局变量
```
// 不要使用window上的全局变量,降低组件复用性和增加维护成本
this.$http.get(APIURL, {})
// 通过props传入组件的所有外部依赖
<app-header api="xxx/yyy/to/path"></app-header>
this.$http.get(this.api, {})
```
### props向下传递,事件向上传递
### 当必须要操作dom时,才使用this.$refs, 而不是jQuery
### 组件顶级class规范化,建议component-xxx开头命名
```
<template>
<div class="component-xxx">
xxx
</div>
</template>
```
### 提供api文档
建议组件api文档写到组件同目录README.md里
\ No newline at end of file
# 分支开发规范
### master分支
* 大部分项目都不要直接在master下直接开发
* master分支需要确保是完全同步线上的状态, 任何时间点打包master分支都可以直接上线
### 分支创建规范
* `feature/xxx`: 新需求,功能性开发
* `hotfix/xxx`: bug修复
### 分支生命周期
* 分支上线前merge master, 上线后第一时间将分支合并入master
* 分支开发完成并合入master之后, 说明该分支生命周期已经完结,请删除分支
### 关于删除分支
* 方法一: gitlab中删除
* 方法二: 命令行执行`git push origin --delete [branch_name]`
### 分支删除后本地查看仍然可以看到
* 方法一: sourcetree pull/fetch操作时有个选项,勾选同步远程分支
* 方法二: 命令行执行`git remote prune origin`
* 方法三: 任意分支下执行`git pull -p`
### 日志
* 严禁使用空日志提交项目
* 不要使用没有任何内容的日志, 比如 'up' 'update' '更新' 'nomessage' 等等
* 日志体现相关项目及改动内容
# 项目相关
\ No newline at end of file
[Airbnb React/JSX 编码规范](https://github.com/JasonBoy/javascript/blob/master/react/README.md)
### 踩坑手记 ###
- this.setState是异步的,所以在this.setState之后不能立刻得到最新的state,如果想设置完直接去拿修改过的state代码如下:
```javascript
this.state = {foo: 2};
this.setState({foo: 123}, ()=> {
console.log(foo);
// 123
});
```
- antd组件默认属性(例如initialValue、defaultValue、defaultFileList)只会被初始化一次),直接修改不会重新渲染,如果需要重新渲染则需要修改另外的属性值(例如setFieldsValue、value、fileList)
- setState直接修改数组或者对象的某个值是不会导致渲染的(深复制,浅复制的问题)代码入下:
```javascript
//❌
//获取父组件的数据
var arr = this.state.tags;
//子组件中传来的数据数组
for(var i=0; i<rows.length; i++){
//isAddData方法是判断数据存不存在
if(this.isAddData(arr, rows[i])){
arr.unshift(rows[i]);
}
}
this.setState({ tags: arr });
```
```javascript
//✅
var arr = this.state.tags;
//子组件中传来的数据数组
for(var i=0; i<rows.length; i++){
//isAddData方法是判断数据存不存在
if(this.isAddData(arr, rows[i])){
arr.unshift(rows[i]);
}
}
this.setState({ tags: [...arr] });
```
- 同一个页面多个子组件调用同一个接口,数据可能会导致出错问题
**解决方案**: 用 state 定义一个 name: 设置 true/false,等待第一个接口加载完毕,再进行 第二次请求(建议设计组件的时候数据可以传入)
- 同一个接口需要点击多次,以最后一次请求为准,因为没有用 loading 才会 出现的数据回来了但是界面没有刷新数据
**解决方案**:fetch 添加一个 type:’takeLatest’,(takeEvery(默认),takeLatest,throttle,watcher)代码如下:
```
effects: {
fetch: [function* ({payload}, { call, put }) {
yield put({
type: 'changeLoading',
payload: true,
});
const response = yield call(calendarMonth,payload);
if(response){
yield put({
type: 'save',
payload: response,
});
}
}, {type: 'takeLatest'}]
}
```
注意:
watcher是指传入的任务函数就是一个watcher直接fork就好
throttle还要传入一个ms配置,这个ms代表着在多少毫秒内只触发一次同一类型saga任务
而takeEvery是不会限制同一类型执行次数
takeLatest只能执行一个同一类型任务,有执行中的再次执行就会取消
- 一个页面由多个组件组成 如何清空表单
如果通过emit分别触发各个组件,是可以实现的,但感觉代价太大
**解决方案**:不需要emit,this.props.dispatch(),dispatch 是根据你里面设置的type内容 然后转发到指定的model的,所以你这边 要设置正确以后,在model那边才能接收到你发送的这条action,model中reducers 处理数据(同步),effects接收数据(异步逻辑都要在effects里),subscriptions 监听数据,代码如下
```javascript
this.props.dispatch({
type: 'global/clearNotices',
payload: type,
});
//models
export default {
namespace: 'global',
reducers: {
clearNotices(state, action) {
return {
...state,
list: action.payload,
};
},
},
};
```
- 单页面应用不要使用location.href这种方式会导致整页刷新,写类似a的跳转可以使用Link组建,如果js控制跳转,代码如下:
```javascript
import { routerRedux } from 'dva/router';
this.props.dispatch(routerRedux.push({
pathname: '/user/register-result',
state: {
account,
},
}));
```
- 一个页面由多个组件组成,跨组件校验问题现在是通过Modal弹窗自己实现的 ,当组件保存按钮在别的组件里,需要带标识实现,实现特别复杂费劲(任务跟进是这样实现的)
- TABLE翻页 selectRow一定要清空
- 页面级的数据尽量不放store中,放在本文件state中,这种类似于session的 会带来bug
- 变量在不通层级中尽量不要重复,析构时候会指向不明
- this问题 箭头函数this是成员this,普通函数this指向函数本身,可以在钩子函数中赋值给自定义的_this
- route.js定义的组件中不要遗忘model的配置,否则dispatch的type的model没有配置则无法生效
代码如下:
```javascript
//dynamicWrapper(app,[model],() =>import('router路径'))
const routerConfig = {
'/': {
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
},
```
- render中改state容易死循环
**解决方案**:建议只有在componentWillMount,componentDidMount,componentWillReceiveProps方法中可以修改state值,在componentWillUpdate和componentDidUpdate中修改也可能导致无限循环调用
### 开发建议 ###
- 文件拆分和建文件夹归类 有的文件好几千行代码
- 文件组件化,现在很多文件都是为了实现自己的功能
- 根据是否需要高度的复用性,把组件划分为 Dumb 和 Smart 组件,约定俗成地把它们分别放到 components 和 containers 目录下。
Dumb 基本只做一件事情 —— 根据 props 进行渲染。而 Smart 则是负责应用的逻辑、数据,把所有相关的Dumb(Smart)组件组合起来,通props 控制它们。
Smart 组件可以使用 Smart、Dumb 组件;而 Dumb 组件最好只使用 Dumb 组件,否则它的复用性就会丧失。
要根据应用场景不同划分组件,如果一个组件并不需要太强的复用性,直接让它成为 Smart 即可;否则就让它成为 Dumb 组件。
还有一点要注意,Smart 组件并不意味着完全不能复用,Smart 组件的复用性是依赖场景的,在特定的应用场景下是当然是可以复用 Smart 的。而 Dumb 则是可以跨应用场景复用,Smart 和 Dumb 都可以复用,只是程度、场景不一样。
### 后端合作建议 ###
- 文档问题: 文档不提前给,文档基本只能看出来接口地址,参数返回全靠猜
- 有些适合后端处理的,都交给了前台。比如后端不知道怎么解析数组,前台需要把数组合并成a|b|c之类的字符串,还有可能是个多维数据。
- cas的权限管理是个坑,这块按理说应该后端解决, 对前端是透明的,现在都需要前端做大量适配工作
- 后端大量不友好的原子接口,前端展示某一块数据都要很多接口同时拿到获取数据,这种的后端代理这一层最好
| | 启动伺服器 | 伺服器默认端口 | 只编译不生成zip | 编译并生成上线zip包|
| -------- | -------- |-------- | -------- |-------- |
| gulp | npm run server | 20000 | npm run dist | npm run release |
| webpack (xxx为项目名) | npm start xxx | 8080 | npm run build xxx | npm run release xxx |
gulp项目编译压缩以已经打入zip包中文件和当前未提交文件为准
webpack项目编译压缩以项目名为准
\ No newline at end of file
# 老feprogram项目文档
### 开发环境
`
npm i
`
### 目录结构
* src 源码
* MWeb 移动站源码
* Web 主站源码
* html 本地开发测试页面
* mock 接口mock目录
* bin 辅助脚本
### 命令
* gulp server 本地开发服务器
* npm run dist 编译不压缩zip
* npm run release 上线包
* gulp prod-pc 主站自动构建(不再建议使用)
* gulp prod-m 移动站自动构建(不再建议使用)
* gulp prod 全部自动构建(不再建议使用)
### 测试/上线包
* npm run release(尚未commit)编译并打成[当前分支].zip压缩包, 存放目录,前端项目上一级目录release文件夹下。第一次使用如果没有release文件夹,自己建一个
* 如果已经存在同名zip文件,会自动包含该zip的文件,并加上当前未提交的文件一起重新编译打包。
* 打包后dist目录存有已经编译后的文件,供发测试使用
### server
#### 启动说明
* 默认20000端口, 使用npm run server -p 8080 来更改服务端口
* 后端web项目appsetting中StaticResourceUrl设为http://localhost:20000/Web/ 或http://localhost:20000/MWeb/
* 远端联调localhost设为本机ip
#### 实现功能
* server提供/Web及/MWeb下静态资源的访问
* scss及css随改动即时编译
* 提供接口mock功能, 支持post/get/jsonp
* 提供本地测试页面服务
* livereload
#### 说明 (以测试m站首页为例)
* 访问测试页面: 如m站首页 http://localhost/html/MWeb/home/index , m站路径开始都是/html/MWeb, pc站都是/html/Web/, 后面的路径根据html目录下页面位置而定,无需加.html后缀
* 访问接口: 接口放在mock目录下,与真实提供接口的相对路径一致, 如后端提供接口/api/test, 存放位置为mock下api目录,文件名为test.json,必须.json格式。js访问时直接写真实接口路径即可
* 编写测试页面: Web和MWeb中layout.html为外层模板,除此外的模板都无需写外层通用相关内容,跟后端模板同理。模板支持@Url.PublicStaticResource函数,静态资源可以不用写本地路径,直接用@Url.PublicStaticResource, 本地测试完后直接放到后端对应模板里提交
# npm依赖版本管理
### 内部公共依赖地址
> http://gitlab.dev.daikuan.com/groups/npm
### semver版本管理
a.b.c
> a: 主版本号
> b: 次版本号
> c: 修订号
### 使用`npm version` cli管理npm包版本
> npm version [majoir|minor|patch]
```bash
# 当前版本 1.2.3
# 升级主版本号 1.2.3 -> 2.0.0
# 主版本号代表不兼容以前版本的改动
npm version major
# 升级次版本号 1.2.3 -> 1.3.0
# 次版本号代表兼容性的新特性添加
npm version minor
# 升级修订号 1.2.3 -> 1.2.4
# 修订号代表修复上一版的bug
npm version patch
```
### 流程
1. npm包的修改迭代,并commit/push
2. 使用`npm version`改动版本
3. git push
4. git push --tags
5. 调用方更改依赖版本
### 内部依赖使用(git+http或git+ssh)
```json
"dependencies": {
"href": "git+http://gitlab.dev.daikuan.com/npm/href.git#v1.0.0",
...
}
```
### 参考
* semver: https://semver.org/lang/zh-CN/
\ No newline at end of file
# yarn vs npm vs cnpm
测试均采用公司网络,网速极好时进行。taoche项目。网络有限制时npm安装成功率较低。
| | npm v3.x | npm v5.x | cnpm(5.x) | yarn|
| -------- | -------- |-------- | -------- |-------- |
| 是否锁依赖版本 | 否(手动) | 是 | 否(手动) | 是 |
|版本锁文件|无|package-lock.json|无|yarn.lock|
|版本锁机制|无|package-lock.json优先|无|yarn.lock优先|
|安装依赖速度|极慢|慢|极快|快|
|依赖目录结构|平铺|平铺|软链|平铺|
|初次安装(非淘宝源)|failed|failed|34s|failed|
|初次安装(node-sass源)|11m+|5m56s|34s|66s|
|重复安装|2m+|25s|19s|24s|
|项目兼容性|好|好|差|好|
|是否可更新依赖|手动|手动|否|是|
### 说明
* 完全使用`cnpm`会有以下问题:
- 本地项目构建会将vue/react等dll模块构建进去
- 公司内部模块升级需要手动删除node_modules下模块目录和软链接,重新cnpm
* `node-sass` 依赖包在不配源的情况下,非cnpm版本都极容易安装不了failed
* 版本锁定机制的不同,导致npm5.x一旦安装需要手动升级,才能更新lock文件, yarn执行后会同步当前package.json到yarn.lock并更换为与package.json中不同的依赖包
### 自动配置npm及yarn源[推荐]
将如下代码在命令行中执行(不支持windows cmd)
`curl -s http://gitlab.dev.daikuan.com/npm/install_env/raw/master/install.sh | sh`
### 手动配置淘宝源
yarn:
`yarn config set registry https://registry.npm.taobao.org`
npm:
`npm config set registry https://registry.npm.taobao.org `
### 手动配置node-sass源
yarn:
`yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass`
npm:
`npm config set sass-binary-site http://cdn.npm.taobao.org/dist/node-sass`
### 更多请参考
https://sebastianblade.com/the-truly-way-to-install-upgrade-npm-dependency-in-china/
# 上线流程
### `npm run build` 与 `npm run release`
* `npm run build` 为本地开发使用,本地构建
* `npm run release` 供灰度/上线使用,远程构建
### [taoche项目]流程
1. 本地开发完成,将最新master分支合并到当前分支
2. 执行`npm run release xxx`远端构建并发布到灰度环境
3. gitlab提merge request(pr), 申请将开发分支合并到master
4. 管理员review代码,之后accept该次pr到master
5. 管理员根据该次pr最后一次release(build)上线
### 其他项目与taoche主项目区别
* 部分项目如crm等项目是全量构建,无需管理员手工上线,pr合并入master即会自动进行远端构建及上线
* 部分敏捷开发项目,如act, 不锁定master权限,开发人员release后即上线
### gitlab中操作pr
1.申请pr:
![](../resources/pr.png)
2.填写pr说明:
![](../resources/pr2.png)
3.仓库负责人review pr, 确认合并
![](../resources/pr3.png)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment