Vue Jsx Render开发规范

Vue开发规范

1. Vue render页面格式

import xx from "../xxx";

export default {
  name: "xxx", //名称
  inject: ["xxx"],//注入
  mixins: [xxx], //混入
  props: {  //接入参数
    propsXx: {
      type: [Object...],
      default: null,
      require: true,
      validator: t => {
      ....
      }
    }
  },
  data: () => ({ //属性
    xx: null
  }),
  computed: { //计算属性
    computedXx() {
    ...
    }
  },
  watch: { //监听
    xxx: {
      immediate: false,
      handler: (nv, ov) => {
      ...
      }
    }
  },
  methods: { //方法
    renderXx(h) {
    ...
    }
  },
  mounted() { //生命周期勾子
  ...
  },
  render(h) { //render入口
  ...
  }
}

2. 命名规范

  1. 文件夹名称,多个单词时,使用-连接,如:app-base-config
  2. Vue可复用组件文件名,前缀:Comp,如:CompAppBaseInfoCard
  3. Vue基础组件文件名,前缀:BaseComp,如:BaseCompErrorCard
  4. Vue页面入口文件名,后缀:index,如:AppBaseInfoIndex
  5. Vue api接口方法名,前缀:ajax,如:ajaxGetAppBaseinfo
  6. Vue props属性名,前缀:props,如:propsAppId
  7. Vue computed计算属性名,前缀:computed,如:computedAppId
  8. Vue emit事件名,前缀:emit,如:emitInput

2.1 Vue组件命名

2.1.1 一般组件

组件名应该始终是多个单词的,根组件 App 除外。

正例:

export default {
     
  name: 'CompTodoItem',
  // ...
}

反例:

export default {
     
  name: 'CompTodo',
  // ...
}

单文件组件的文件名应该始终是单词大写开头 (PascalCase)

正例:

components/
|- CompMyComponent.js

反例:

components/
|- myComponent.js
|- mycomponent.js

组件名应该倾向于完整单词而不是缩写。

正例:

components/
|- CompStudentDashboardSettings.js
|- CompUserProfileOptions.js
复制代码

反例:

components/
|- SdSettings.js
|- UProfOpts.js

2.1.2 基础组件

【强烈建议】应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。

正例:

components/
|- BaseCompButton.js
|- BaseCompTable.js
|- BaseCompIcon.js

反例:

components/
|- MyButton.js
|- VueTable.js
|- Icon.js

2.1.3 单例组件

【强烈建议】只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。

正例:

components/
|- TheHeading.js
|- TheSidebar.js

反例:

components/
|- Heading.js
|- MySidebar.js

2.1.4 紧密耦合的组件名

【强烈建议】和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。

正例:

components/
|- CompTodoList.js
|- CompTodoListItem.js
|- CompTodoListItemButton.js
components/
|- CompSearchSidebar.js
|- CompSearchSidebarNavigation.js
复制代码

反例:

components/
|- SearchSidebar.js
|- NavigationForSearchSidebar.js

2.2 javascript变量、方法命名

【强制】语义化、功能化。常量全大写,用下划线连接

// 普通变量      
let arrayIndex = 0;
// 常量      
const HOURS_PER_DAY = 24; 
/**
 * 同步id获取ddl详情
 *
 * @param id
 * @returns {object}
 */
ajaxGetDdlOptionsById(id) {
     
   return ddl;
}

文件命名参照项目命名规则

正例:DateFormaUtils.js

2.3 枚举

枚举定义在单独的文件中,例如:ProgrammingLanguageTypeEnum.js

// good
export const ProgrammingLanguageTypeEnum = {
  Java: {
    label: 'Java',
    value: 1,
    icon: 'mdi-language-java',
    bgColor: 'bg-primary'
  },
  NodeJS: {
    label: 'Node.js',
    value: 2,
    icon: 'mdi-nodejs',
    bgColor: 'bg-secondary'
  },
  Static: {
    label: 'Static',
    value: 3,
    icon: 'mdi-language-html5',
    bgColor: 'bg-positive'
  }
}

export const ProgrammingLanguageTypeEnumForNumber = {
  1: ProgrammingLanguageTypeEnum.Java,
  2: ProgrammingLanguageTypeEnum.NodeJS,
  3: ProgrammingLanguageTypeEnum.Static,
}

export const ProgrammingLanguageTypeOptions = Object.keys(ProgrammingLanguageTypeEnumForNumber).map(key => (
  {
    label: ProgrammingLanguageTypeEnumForNumber[key].label,
    value: ProgrammingLanguageTypeEnumForNumber[key].value,
    icon: ProgrammingLanguageTypeEnumForNumber[key].icon,
  }
))

2.3 事件名称

【强烈建议】在派发/监听事件的时候,事件最终会被自动转换为短横线式命名(kebab-case)。在声明时间的时候,命名可以为短横线式,但为增强可读性强烈建议使用带类型的驼峰格式,例如:

// Emitting
this.$emit('emitEvent') // instead of emitEvent
// Listening
on:emitEvent

3.代码规范

3.1 简单的计算属性

【强烈建议】保持计算属性的原子性

正例:

computed: {
     
  basePrice: function () {
     
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
     
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
     
    return this.basePrice - this.discount
  }
}

反例:

computed: {
     
  price: function () {
     
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}

3.2 props定义

【强制】Props 定义应该尽量详细,必须需要指定其类型。

【强烈建议】Props原子化:虽然 Vue.js 支持传递复杂的 JavaScript 对象通过 props 属性,但是你应该尽可能的使用原始类型的数据。尽量只使用 JavaScript 原始类型(字符串、数字、布尔值)和函数。尽量避免复杂的对象

正例:

props: {
     
  status: String
}
// 更好的做法!
props: {
     
  propsStatus: {
     
    type: String,
    required: true,
    validator: function (value) {
     
      return [
        'syncing',
        'synced',
        'versionConflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}

反例:

// 这样做只有开发原型系统时可以接受
props: ['status']

3.3 为多个子组件设置键值

【强烈建议】总是用 key 配合 .map(v-for)。
在多个重复子组件上必须用 key,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。

正例:

filterList.map(db => [
            this.renderDbCatalogItem(h, db),
            h('q-item-separator', {
     staticClass: 'q-ma-none'})
          ])])

renderDbCatalogItem(h, db) {
     
      return h('div', {
     
        staticClass: 'pp-selectable-bg q-pl-sm q-pr-sm flex no-wrap justify-between cursor-pointer',
        key: db.id,
      }, [])
    }

反例:

renderDbCatalogItem(h, db) {
     
      return h('div', {
     
        staticClass: 'pp-selectable-bg q-pl-sm q-pr-sm flex no-wrap justify-between cursor-pointer',
      }, [])
    }

3.4 Vue Router 规范

【强烈建议】页面跳转数据传递使用路由参数

页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex 的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。

let id = ' 123';
this.$router.push({
      path: '/user_center', query: {
      id: id } });
【强烈建议】使用路由懒加载(延迟加载)机制
    {
     
        path: '/uploadAttachment',
        name: 'uploadAttachment',
        meta: {
     
          title: '上传附件'
        },
        component: () => import('@/view/components/uploadAttachment/index.vue')
      },

3.4 括号

【强烈建议】下列关键字后必须有大括号(即使代码块的内容只有一行):

if, else, for, while, do, switch, try, catch, finally

// not good
if (condition)
    doSomething();

// good
if (condition) {
     
    doSomething();
}

3.5 undefined

【强烈建议】不要直接使用 undefined 进行变量判断;使用 typeof 和字符串’undefined’对变量进行判断。

// not good (person未定义时,以下语句会报错)
if (person === undefined) {
     
    ...
}

// good
if (typeof person === 'undefined') {
     
    ...
}

3.6 分号

【建议】语句以分号结束

这个是要引起注意的,比如:

// bad
a = b        // 赋值
(function(){
     
    //....
})()         // 自执行函数

// good
a = b;        // 赋值
(function(){
     
    //....
})()         // 自执行函数

未加分号,结果被解析成

a = b(function(){
     /*...*/})()  //将b()()返回的结果赋值给a

3.7 ===

【强制】值比较使用===, ==执行比较前会做类型转换

3.8 其他

【强制】

缩进:使用IDE默认格式化代码方法进行格式化

switch:逻辑分支必须包含default

4. 注释

【强烈建议】核心、复杂逻辑添加必要注释(单行)

// 获取用户上次选的oaBu
if (localStorage.getItem('oa_bu')) {
     
  this.model.oaBu = JSON.parse(localStorage.getItem('oa_bu'))
}

【强烈建议】方法注释参考JAVA规范, 以/**开头(多行)

/**
 * 获取两个时间戳的可读差值
 *
 * @param startTime
 * @param endTime
 * @returns {string}
 */
export const getTimeDiff = (startTime, endTime) => {
     
  let dateBegin = new Date(startTime.replace(/-/g, "/"))
  let dateEnd = endTime === null ? new Date() : new Date(endTime.replace(/-/g, "/"))

  let time = dateEnd.getTime() - dateBegin.getTime()
  let duration = (time / (60 * 60 * 1000)).toFixed(2)
  let display = duration < 24 ? `${
       duration} 小时` : `${
       (duration / 24).toFixed(2)} 天`
  return display
}

5. 基于模块开发

【强烈建议】始终基于模块的方式来构建你的工程,每一个子模块只做一件事情。

Vue.js 的设计初衷就是帮助开发者更好的开发界面模块。一个模块是应用程序中独立的一个部分。

每一个 Vue 组件(等同于模块)首先必须专注于解决一个单一的问题,独立的可复用的微小的可测试的

如果你的组件做了太多的事或是变得臃肿,请将其拆分成更小的组件并保持单一的原则。一般来说,尽量保证每一个文件的代码行数不要超过 500 行。也请保证组件可独立的运行。比较好的做法是增加一个单独的 demo 示例。

6. 使用Mixin(待定,目前不推荐使用)

使用场景:组件的行为和属性类似,例如:模态框

【强制】基础文件命名,例如:MixinBaseModal.js

【强制】mixin组件必须实现的方法前缀必须是abstract,例如:abstractRenderContents()

【强制】为了将Mixin的属性与组件的属性相区分,我们使用$_,原因如下:

  1. 这是Vuejs传统风格
  2. _在Vuejs中表示私有属性
  3. $属于Vue的保留字

在风格指南可以看到官方推荐的Mixin命名:

  data: () => ({
     
    $_myMixin_updateUser: false,
  }),
  methods: {
     
      $_hide() {
     
      this.loading = false;
      this.hide()
    },    
  }

使用注意事项:

避免写新的MixinBase

尽量避免同时mixin多个对象

引入单独的功能性方法,尽量使用import而不是mixin

Mixin注意事项:

合并:当混合对象与组件包含同名选项时,这些选项将以适当的策略合并。例如,同名钩子函数被并入一个数组,因而都会被调用。另外,混合的钩子将在组件自己的钩子之前调用。

冲突:值为对象的选项,如 methods, components 和 directives 将合并到同一个对象内。如果键冲突则组件的选项优先。

7. 前后端交互

【强烈建议】服务端发生错误时,返回给前端的响应信息必须包含 HTTP 状态码,errorCode、 errorMessage、用户提示信息四个部分。

【强烈建议】在前后端交互的 JSON 格式数据中,所有的 key 必须为小写字母开始的 lowerCamelCase 风格,符合英文表达习惯,且表意完整。

正例:errorCode / errorMessage / assetStatus / menuList / orderList / configFlag

反例:ERRORCODE / ERROR_CODE / error_message / error-message / errormessage / ErrorMessage / msg

【强烈建议】对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用 Long 类型。

说明:Java 服务端如果直接返回 Long 整型数据给前端,JS 会自动转换为 Number 类型(注:此类型为双 精度浮点数,表示原理与取值范围等同于 Java 中的 Double)。Long 类型能表示的最大值是 2 的 63 次方 -1,在取值范围之内,超过 2 的 53 次方 (9007199254740992)的数值转化为 JS 的 Number 时,有些数 值会有精度损失。扩展说明,在 Long 取值范围内,任何 2 的指数次整数都是绝对不会存在精度损失的,所 以说精度损失是一个概率问题。若浮点数尾数位与指数位空间不限,则可以精确表示任何整数,但很不幸, 双精度浮点数的尾数位只有 52 位。 反例:通常在订单号或交易号大于等于 16 位,大概率会出现前后端单据不一致的情况,比如,“orderId”: 362909601374617692,前端拿到的值却是: 362909601374617660。

【强制】HTTP 请求通过 URL 传递参数时,不能超过 2048 字节。

说明:不同浏览器对于 URL 的最大长度限制略有不同,并且对超出最大长度的处理逻辑也有差异,2048 字节是取所有浏览器的最小值。 Java 开发手册 27/59 反例:某业务将退货的商品 id 列表放在 URL 中作为参数传递,当一次退货商品数量过多时,URL 参数超长, 传递到后端的参数被截断,导致部分商品未能正确退货。

【强制】HTTP 请求通过 body 传递内容时,必须控制长度,超出最大长度后,后端解析会出错。

说明:nginx 默认限制是 1MB,tomcat 默认限制为 2MB,当确实有业务需要传较大内容时,可以通过调 大服务器端的限制。

8. 规范插件

ESLint - 支持jsx

参考规范附录

Vue官方风格指南

前端规范指南(鹅厂)

Vue.js 最佳实践

Java开发手册(阿里嵩山版)

前端规范

你可能感兴趣的:(开发规范,vue,代码规范)