Skip to content

Latest commit

 

History

History
1232 lines (911 loc) · 32.6 KB

代码规范.md

File metadata and controls

1232 lines (911 loc) · 32.6 KB

编程规约

规范的好处

  1. 提高代码整体的可读性、可维护性、可复用性、可移植性和可靠性,会从根本上降低开发成本
  2. 保证代码的一致性,更加易于维护,团队内任何人都可以快速理解并修改
  3. 提升团队整体效率,尽早发现问题,甚至完全预防问题
  4. 减少争议,高效、高质高效完成的目的

格式化规范

使用``prettier`

  • 具体配置:

    1. 安装依赖

      npm install --save-dev --save-exact prettier 
      // or
      yarn add --dev --exact prettier
    2. 创建配置文件

      echo {}> .prettierrc.json
    3. 创建.prettierignore文件,是其不被格式化

      # Ignore artifacts:
      dist
      build
      coverage

命名规范

项目命名

  • 全部采用小写方式, 以-分隔

    mall-management-system

目录命名

  • 有复数结构时,要采用复数命名法, 缩写不用复数

    scripts/styles/components/images/utils/layouts/demo-styles/demo-scripts/img/doc

  • Vue项目中的目录,包括组件目录,都使用``kebab-case`命名

    head-search/page-loading/authorized/notice-icon

    page-one/shopping-car/user-management

文件命名

  • 全部采用小写方式, 以-分隔

    render-dom.js/signup.css/index.html/company-logo.png

命名严谨性

  • 严禁使用拼音与英文混合的方式,避免歧义

    henan/luoyang/rmb 等国际通用的名称,可视同英

HTML 规范

文档类型申明

  • 规定字符编码、IE 兼容模式、规定字符编码、doctype 大写

    <!DOCTYPE html>
    <html>
      <head> 
        <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> 
        <meta charset="UTF-8" /> 
        <title>Page title</title> 
      </head>
      <body> 
       <img src="images/company-logo.png" alt="Company">
     </body> 
    </html>

缩进

  • 缩进使用 2 个空格(一个 tab)嵌套的节点应该缩进

分块注释

  • 每个块状元素,列表元素和表格元素后,加上 注释

语义化标签

  • 优先使用语义化标签

    <header></header> 
    <footer></footer>

属性引号

  • 属性使用双引号

    <div class="box"></div>

CSS 规范

命名

  • 使用小写字母,-分隔

  • id 、class,scss 中的变量、函数、混合、placeholder 采用驼峰式命名

  • id 和 class 使用反应元素目的和用途的名称

    .heavy {
       font-weight: 800;
    }
    .important { 
      color: red; 
    }

选择器

  • 避免使用标签名

  • 使用直接子选择器

    .content > .title {
       font-size: 2rem;
    }

    不使用直接子选择器有时候可能会很耗性能

  • 避免使用 ID 及全局标签选择器,防止污染全局样式

  • 每个选择器及属性独占一行

缩写

  • 尽量使用缩写属性

    border-top: 0; 
    font: 100%/1.6 palatino, georgia, serif; /* font-size/line-height font-family */
    padding: 0 1em 2em;
  • 省略 0 后面的单位

    div {
        padding-bottom: 0; 
        margin: 0; 
    }

LESS、SCSS 规范

代码组织

  • 将公共文件放置在``style/less/common`文件夹

  • 按以下顺序组织

    1. @import

    2. 变量声明

    3. 样式声明

    @import "mixins/size.less"; 
    @default-text-color: #333; 
    .page {
     width: 960px; 
     margin: 0 auto; 
    }
  • 避免嵌套层级过多

    将嵌套深度限制在 3 ~4 级,避免出现多于 20 行的嵌套规则出现

JS 规范

命名

  • 采用小驼峰命名,不以_开头,也不以_ or $结尾,

  • 方法名、参数名、成员变量、局部变量使用 lowerCamelCase 风 格,遵从驼峰形式

    localValue / getHttpMessage() / inputUserId

    saveShopCarData /openShopCarInfoDialog

    method 方法命名采用 动词 or 动词+名词 形式

    命名 含义 命名 含义 命名 含义
    get 获取 copy 复制 compress 压缩
    set 设置 paste 粘贴 decompress 解压缩
    add 增加 undo 撤销 pack 打包
    remove 删除 redo 重做 unpack 解包
    create 创建 insert 插入 parse 解析
    destory 销毁 delete 移除 emit 生成
    start 启动 add 加入 connect 连接
    stop 停止 append 添加 disconnect 断开
    open 打开 clean 清理 send 发送
    close 关闭 clear 清除 receive 接收
    read 读取 index 索引 download 下载
    write 写入 sort 排序 upload 上传
    load 载入 find 查找 refresh 刷新
    save 保存 search 搜索 synchronize 同步
    begin 开始 increase 增加 update 更新
    end 结束 decrease 减少 revert 复原
    backup 备份 play 播放 lock 锁定
    restore 恢复 pause 暂停 unlock 解锁
    import 导入 launch 启动 check out 签出
    export 导出 run 运行 check in 签入
    split 分割 compile 编译 submit 提交
    merge 合并 execute 执行 commit 交付
    inject 注入 debug 调试 push
    extract 提取 trace 跟踪 pull
    attach 附着 observe 观察 expand 展开
    detach 脱离 listen 监听 collapse 折叠
    bind 绑定 build 构建 enter 进入
    separate 分离 publish 发布 exit 退出
    view 查看 input 输入 abort 放弃
    browse 浏览 output 输出 quit 离开
    edit 编辑 encode 编码 obsolete 废弃
    modify 修改 decode 解码 depreciate 废旧
    select 选取 encrypt 加密 collect 收集
    mark 标记 decrypt 解密 aggregate 聚集
  • 常量命名大写,单词间用_

    MAX_STOCK_COUNT

  • 对上下文 this 的引用只能使用 ``self` 来命名。

代码格式

  • 使用 2 个空格缩进

  • 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来

语法规范

  • 字符串统一使用单引号''

  • 对象声明使用字面值创建对象

    let user = {}
    //不使用 new Object()
  • 使用ES6+

    如箭头函数、await/async , 解构, let , for…of 等等。

  • 下列关键字后必须有大括号(即使代码块的内容只有一行)

    ifelseforwhiledoswitchtrycatchfinallywith

  • 不要直接使用 undefined 进行变量判断

    if (typeof person === 'undefined') { ... }
  • 条件判断和循环最多3层

    三目运算符 和 逻辑运算符 代替条件判断

  • 慎用 console.log

对象

  • 不直接调用Object.prototype,如 hasOwnPropertypropertyIsEnumerableisPrototypeOfeslint: no-prototype-builtins

    在一些有问题的对象上,这些方法可能会被屏蔽掉,如:{ hasOwnProperty: false } 或空对象 Object.create(null)

    // bad
    object.hasOwnProperty(key)
    
    // good
    Object.prototype.hasOwnProperty.call(object, key)
    
    // best
    const has = Object.prototype.hasOwnProperty; // 在模块作用域内做一次缓存。
    has.call(object, key)
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    has(object, key)
  • 对象浅拷贝时,使用扩展运算符 ...,而不是 Object.assign。获取对象指定的属性时,用对象的 rest 解构运算符。eslint: prefer-object-spread

    const original = { a: 1, b: 2 };
    
    // very bad
    const copy = Object.assign(original, { c: 3 }); // 改了 `original` ಠ_ಠ
    delete copy.a; // so does this
    
    // bad
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
    
    // good es6 扩展运算符 ... 进行浅拷贝
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    
    // rest 解构运算符
    const { a, ...rest } = copy; // rest => { b: 2, c: 3 }

数组

  • 用扩展运算符做数组浅拷贝,类似上面的对象浅拷贝

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i += 1) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
  • ... 运算符而不是 Array.from 来将一个可迭代的对象转换成数组

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
  • Array.from 将一个类数组对象转成一个数组

    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    
    // bad
    const arr = Array.prototype.slice.call(arrLike);
    
    // good
    const arr = Array.from(arrLike);
  • Array.from 而不是 ... 运算符去做 map 遍历。 因为这样可以避免创建一个临时数组

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);

解构

  • 用对象的解构赋值来获取和使用对象某个或多个属性值。eslint: prefer-destructuring

    解构可以避免创建临时引用和重复引用对象,避免造成代码重复、增加阅读次数、提高犯错概率

    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(user) {
      const { firstName, lastName } = user;
      return `${firstName} ${lastName}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }
  • 用数组解构。eslint: prefer-destructuring

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
  • 多个返回值用对象的解构,而不是数组解构\

    在后期添加新的属性或者变换变量的顺序而不会破坏原有的引用

    // bad
    function processInput(input) {
      // 然后就是见证奇迹的时刻
      return [left, right, top, bottom];
    }
    
    // 调用者需要想一想返回值的顺序
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // oops,奇迹又发生了
      return { left, right, top, bottom };
    }
    
    // 调用者只需要选择他想用的值就好了
    const { left, top } = processInput(input);

字符串

  • 字符串应使用单引号 '' 。eslint: quotes

  • 不使用 eval(),该方法有太多漏洞。eslint: no-eval

  • 不使用不必要的转义字符。eslint: no-useless-escape

    反斜线可读性差,仅当必要时才使用它

  • 当需要动态生成字符串时,使用模板字符串,而不是字符串拼接。eslint: prefer-template template-curly-spacing

    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }

普通函数

  • 使用函数表达式而不是函数声明。eslint: func-style

    使用函数声明会发生提升(即在函数被声明之前就可以使用),使用匿名函数会导致难以追踪错误

    // bad
    function foo() {
      // ...
    }
    
    // bad
    const foo = function () {
      // ...
    };
    
    // good
    // lexical name distinguished from the variable-referenced invocation(s)
    // 函数表达式名和声明的函数名是不一样的
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };
    //简单写法 不用在意this指向
    const short = name => name
  • ECMA-262 中对块(block)的定义是: 一系列的语句。但是函数声明不是一个语句, 函数表达式是一个语句

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }
  • 不使用 arguments,用收集参数语法 ... 代替。eslint: prefer-rest-params

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
  • 用默认参数语法而不是在函数里对参数重新赋值

    // really bad
    function handleThings(opts) {
      // 1. 不该修改 arguments
      // 2. 如果 opts 的值为 false, 它会被赋值为 {}
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
  • 不要修改参数或重新赋值 eslint: no-param-reassign

    操作参数会导致意想不到的副作用。不要改参数的数据结构,保留参数原始值和数据结构

    // bad
    function f1(a) {
      a = 1;
      // ...
    }
    
    function f2(a) {
      if (!a) { a = 1; }
      // ...
    }
    
    // good
    function f3(a) {
      const b = a || 1;
      // ...
    }
    
    function f4(a = 1) {
      // ...
    }
    // bad
    function f1(obj) {
      obj.key = 1;
    };
    
    // good
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    };
  • 使用拓展运算符调用多参数的函数。eslint: prefer-spread

    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    
    // good
    new Date(...[2016, 8, 5]);

箭头函数

  • 在回调函数里使用箭头函数。 eslint: prefer-arrow-callback, arrow-spacing

    箭头函数中的 this 与定义该函数的上下文中的 this 一致,语法更简洁,如果函数逻辑较复杂,则把它单独写入一个命名函数里头

    // bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
  • 如果函数体由一个没有副作用的表达式语句组成,删除大括号和 return。eslint: arrow-parens, arrow-body-style

    当多个函数链在一起的时候好读

    // bad
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      `A string containing the ${nextNumber}.`;
    });
    
    // good
    [1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
    
    // good
    [1, 2, 3].map((number, index) => ({
      [index]: number,
    }));
    
    // 没有明显的 return 语句,可能存在副作用。
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // 当 callback 返回 true 时...
      }
    }
    
    let bool = false;
    
    // bad
    foo(() => bool = true);
    
    
    // good
    foo(() => {
      bool = true;
    });
  • 如果表达式涉及多行,把他包裹在圆括号里以提高可读性

    // bad
    ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod
      )
    );
    
    // good
    ['get', 'post', 'put'].map((httpMethod) => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod
      )
    ));

类与构造函数

  • 使用 class 语法。避免直接操作 prototype

    class 语法更简洁更易理解

    // good
    class Queue {
      constructor(contents = []) {
        this.queue = [...contents];
      }
      pop() {
        const value = this.queue[0];
        this.queue.splice(0, 1);
        return value;
      }
    }
  • extends 实现继承

  • 方法可以返回 this 来实现链式调用

    // good
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }
    
      setHeight(height) {
        this.height = height;
        return this;
      }
    }
    
    const luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
  • 类有默认的构造方法。一个空的构造函数或只是代表父类的构造函数是不需要写的。 eslint: no-useless-constructor

  • 避免重复定义类成员。eslint: no-dupe-class-members

  • 除非外部库或框架需要使用特定的非静态方法,否则类方法应该使用 this 或被写成静态方法。 作为一个实例方法表明它应该根据实例的属性有不同的行为。eslint: class-methods-use-this

模块

  • 使用(import/export)模块

  • 一个路径只 import 一次。eslint: no-duplicate-imports

    // bad
    import foo from 'foo';
    import { named1, named2 } from 'foo';
    
    // good
    import foo, { named1, named2 } from 'foo';
  • 避免导出可变的东西。eslint: import/no-mutable-exports

  • 在一个单一导出的模块里使用 export default 。eslint: import/prefer-default-export

  • import 放在所有语句之前。eslint: import/first

  • 多行 import 应该缩进。eslint: object-curly-newline

    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';
  • import 语句里不允许 Webpack loader 语法。eslint: import/no-webpack-loader-syntax

    一旦用 Webpack 语法在 import 里会把代码耦合到模块绑定器。最好是在 webpack.config.js 里写 webpack loader 语法

  • import JavaScript文件不用包含扩展名 eslint: import/extensions

迭代器与生成器

  • 不使用迭代器。使用 JS 高级函数代替 for-infor-of。eslint: no-iterator no-restricted-syntax

    用数组的这些迭代方法: map() / every() / filter() / find() / findIndex() / reduce() / some() / ... ,

    用对象的这些方法 Object.keys() / Object.values() / Object.entries() 去产生一个数组,就能遍历对象了

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    
    // good
    let sum = 0;
    numbers.forEach((num) => sum += num)
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0)
    
    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }
    
        // good
    const increasedByOne = [];
    numbers.forEach((num) => {
      increasedByOne.push(num + 1);
    });
    
    // best (keeping it functional)
    const increasedByOne = numbers.map((num) => num + 1);
  • 暂时不使用生成器

    生成器目前不能很好地转换为 ES5 语法

  • 如果要用生成器,确保函数标志空格是正确。eslint: generator-star-spacing

    function* 是同一概念关键字 - *不是function的修饰符,function* 是一个和function 不一样的独特结构。

    // good
    function* myGenerator() {
        yield 'Hello'
    	yield 'world'
    	return 'ending'
    }
    
    const MG  = myGenerator()
    
    MG.next() // {value:'Hello',done:false}
    MG.next() // {value:'world',done:false}
    MG.next() // {value:'ending',done:true}
    MG.next() // {value:'undefined',done:false}

属性

  • 访问属性时使用点符号,当使用变量获取属性时用方括号 []。eslint: dot-notation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    const isJedi = luke.jedi;
    
    function getProp(prop) {
      return luke[prop];
    }
    const isJedi = getProp('jedi');
  • 做幂运算时用幂操作符 ** 。eslint: no-restricted-properties.

    // bad
    const binary = Math.pow(2, 10);
    
    // good
    const binary = 2 ** 10;

变量

  • 使用 constlet 声明变量,并把它们分别放一起。eslint: no-undef prefer-const one-var

  • 变量定义在需要的地方

    // good
    function checkName(hasName) {
      if (hasName === 'test') {
        return false;
      }
    
      // 在需要的时候分配
      const name = getName();
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }
  • 不使用链式声明变量。 eslint: no-multi-assign

  • 不使用一元自增自减运算符(++--). eslint no-plusplus

    使用 num + = 1 而不是 num ++num ++ 语句也是含义清晰的,避免预料之外的预增/预减

  • 在赋值的时候避免在 = 前/后换行,如果赋值语句超出 max-len,就用小括号包起来再换行。eslint operator-linebreak.

  • 不能有未使用的变量。eslint: no-unused-vars

比较运算符与相等

  • ===!== 而不是 ==!=. eslint: eqeqeq
    • Object === true
    • Undefined === false
    • Null === false
    • Boolean
    • Number
      • +0, -0, NaN === false
      • others === true
    • String
      • '' === false
      • others === true

Vue 规范

  • 详见Vue笔记代码规范

目录规范

  • 所有命名一定要与后端命名统一,router , store, api 等都必须使用 privielege 单词

  • api 目录文件、变量命名要与后端保持一致

  • assets 为静态资源,里面存放 images, styles, icons 等静态资源,静态资源命名格式为 kebab-case

  • router 与 store 两个目录一定要将业务进行拆分,不能放到一个 js 文件里。

    • router 尽量按照 views 中的结构保持一致

    • store 按照业务进行拆分不同的 js 文件

  • views 目录要与后端、router、api 等保持一致

  • 必须加注释的地方

    • 公共组件使用说明
    • api 目录的接口 js 文件
    • store 中的 state, mutation, action 等
    • vue 文件中的 template 必须加注释,若文件较大添加 start end 注释
    • vue 文件的 methods,每个 method
    • vue 文件的 data, 非常见单词要加注释
    src                                  源码目录
    |-- api                              所有api接口
    |-- assets                           静态资源,images, icons, styles等
    	|-- icons
        |-- images
        |   |-- background-color.png
        |   |-- upload-header.png
        |-- styles
    |-- components                       公用组件
        |-- error-log
        |   |-- index.vue
        |   |-- index.less
        |-- markdown-editor
        |   |-- index.vue
        |   |-- index.js
        |-- kebab-case
    |-- config                           配置信息
    |-- constants                        常量信息,项目所有Enum, 全局常量等
        |-- index.js
        |-- role.js
        |-- employee.js
    |-- directives                       自定义指令
    |-- filters                          过滤器,全局工具
    |-- datas                            模拟数据,临时存放
    |-- lib                              外部引用的插件存放及修改文件
    |-- mock                             模拟接口,临时存放
    |-- plugins                          插件,全局使用
    |-- router                           路由,统一管理
    |-- store                            vuex, 统一管理
    |-- themes                           自定义样式主题
    |-- views                            视图目录
    |   |-- role                                role模块名
    |   |   |-- role-list.vue                   role列表页面
    |   |   |-- role-add.vue                    role新建页面
    |   |   |-- role-update.vue                 role更新页面
    |   |   |-- index.less                      role模块样式
    |   |   |-- components                      role模块通用组件文件夹
    |   |   |   |-- role-header.vue             role头部组件
    |   |   |   |-- role-modal.vue              role弹出框组件
    |   |-- employee                            employee模块
    |   |-- behavior-log                        行为日志log模块
    |   |-- code-generator                      代码生成器模块

组件规范

  • 组件名由多个单词组成(大于等于 2),命名规范为KebabCase格式

    export default {
      name: 'TodoItem'
      // ...
    };
  • 组件文件名为 pascal-case 格式

components/
|- my-component.vue
  • 基础组件文件名为 base 开头,使用完整单词而不是缩写
components/
|- base-button.vue
|- base-table.vue
|- base-icon.vue
  • 和父组件紧密耦合的子组件应该以父组件名作为前缀命名

    components/
    |- todo-list.vue
    |- todo-list-item.vue
    |- todo-list-item-button.vue
    |- user-profile-options.vue (完整单词)
  • 在 Template 模版中使用组件,应使用 PascalCase 模式,并且使用自闭合组件。

    <MyComponent />
    <Row><table :column="data"/></Row>
  • 组件的 data 必须是一个函数

  • Prop 定义应该尽量详细

    • 使用 camelCase 驼峰命名

    • 指定类型

    • 加上注释,表明其含义

    • 加上 required 或者 default

    • 有业务需要,加上 validator 验证

      props: {
        // 组件状态,用于控制组件的颜色
         status: {
           type: String,
           required: true,
           validator: function (value) {
             return [
               'succ',
               'info',
               'error'
             ].indexOf(value) !== -1
           }
         },
          // 用户级别,用于显示皇冠个数
         userLevel:{
            type: String,
            required: true
         }
      }
  • 为组件样式设置作用域

  • 特性元素较多,应该主动换行

模板规范

  • 模板中使用简单的表达式

    复杂的表达式则应该重构为计算属性或方法

  • 指令都使用缩写形式

    用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:

  • 标签顺序保持一致

  • 必须为 v-for 设置键值 key

  • v-show 与 v-if 选择

    运行时,需要非常频繁地切换,使用 v-show ;如果在运行时,条件很少改变,使用 v-if

  • script 标签内部结构顺序

    export default{
        components:{
        },
        props:{
        },
        data(){
        	return{
            }
        },
        computed:{
    	},
        watch:{
    	},
        filter:{
    	},
        //钩子函数(钩子函数按其执行顺序),
        methods:{
    	}
    }

VueRouter规范

  • 页面跳转数据传递使用路由参数

    let id = ' 123';
    this.$router.push({ name: 'userCenter', query: { id: id } });
  • 使用路由懒加载

    {
        path: '/uploadAttachment',
        name: 'uploadAttachment',
        meta: {
          title: '上传附件'
        },
        component: () => import('@/view/components/uploadAttachment/index.vue')
      },
  • path、childrenPoints 、name命名规范采用kebab-case命名规范,和component组件名保持一致

    // 动态加载
    export const reload = [
      {
        path: '/reload',
        name: 'reload',
        component: Main,
        meta: {
          title: '动态加载',
          icon: 'icon iconfont'
        },
        children: [
          {
            path: '/reload/smart-reload-list',
            name: 'SmartReloadList',
            meta: {
              title: 'SmartReload',
              childrenPoints: [
                {
                  title: '查询',
                  name: 'smart-reload-search'
                },
                {
                  title: '执行reload',
                  name: 'smart-reload-update'
                },
                {
                  title: '查看执行结果',
                  name: 'smart-reload-result'
                }
              ]
            },
            component: () =>
              import('@/views/reload/smart-reload/smart-reload-list.vue')
          }
        ]
      }
    ];

    要保持keep-alive特性,keep-alive按照component的name进行缓存,所以两者必须高度保持一致

  • path 以 / 开头

    {
        path: '/file',
        name: 'File',
        component: Main,
        meta: {
          title: '文件服务',
          icon: 'ios-cloud-upload'
        },
        children: [
          {
            path: '/file/file-list',
            name: 'FileList',
            component: () => import('@/views/file/file-list.vue')
          },
          {
            path: '/file/file-add',
            name: 'FileAdd',
            component: () => import('@/views/file/file-add.vue')
          },
          {
            path: '/file/file-update',
            name: 'FileUpdate',
            component: () => import('@/views/file/file-update.vue')
          }
        ]
      }

其他

  • 尽量不要手动操作 DOM
  • 删除无用代码