Vue 规范

vue 项目规范以 Vue 官方规范 中的 A、B、C 规范为基础,并根据实际项目特点略作调整,故应结合两者来执行规范。

重点强调

1、组件

(1)组件名

组件名应该始终是多个单词组成(大于等于 2),且命名规范为 PascalCase 格式,避免和 HTML 元素名称冲突。

// components/HeaderComponent.vue
export default {
  name: 'HeaderComponent',
  // ...
}
(2)组件文件名

组件文件名为 PascalCase 格式。如不指定组件名改组件会默认以文件名作为组件名称。

components/
|- MyComponents.vue
(3)组件文件夹名称和默认导出

一个组件可以被拆分成多个组件编写的应该建立目录并且建立 index.js 导出对象。禁止使用 index.vue 做默认导出。

components/
|- MyComponent/
|----index.js
|------MyComponent.vue
|------MyComponentList.vue
|------MyComponentListItem.vue
// index.js
import MyComponents from './MyComponent'
// 使用index.js作为默认导出
export default MyComponent

2、Template

(1)在 Template 模版中使用组件,应使用 烤串 kebab-case 模式
<div>
  <my-component></my-component>
</div>
(2)Template 中每行写一个属性元素,指令都使用缩写形式

指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)

<template class="area-wrap">
  <a-select
    :value="showVal"
    :disabled="isDisabled"
    :allowClear="allowClear"
    :mode="mode"
    :defaultActiveFirstOption="false"
    :showArrow="false"
    :filterOption="false"
    @search="onSearch"
    @change="onChange"
    placeholder="请输入关键字检索"
    notFoundContent="请输入"
    showSearch
    labelInValue
  >
    <a-select-option v-for="d in areaListData" :key="d.value">
      {{ d.fullName ? d.fullName : d.name }}
    </a-select-option>
  </a-select>
</template>
(3) Template 属性元素书写顺序

指令 -> 属性 -> 事件 -> class -> style -> html 属性 -> bool 值属性

(4) 标签顺序保持一致

单文件组件应该总是让标签顺序保持为

<template></template>
<script></script>
<style></style>

3、Script

标签内部结构顺序

<script>
  export default {
    name: ,
    components:,
    directives:,
    filters:,
    mixins:,
    props:,
    data,
    // 所有生命周期
    created() {},
    methods: {},
    computed: {},
    watch: {}
  }
</script>

4、Style

因为默认使用 ESLint 进行 Vue 文件格式化,所以会丧失对 style 内样式格式化的功能

故每个 Vue 组件在编写样式时应使用 src 引用方式使用样式,样式文件使用更强力的 stylelint 进行校验和格式化操作

<style lang="less" src="./login.less" scoped>

5、Data

(1) 组件的 data 必须是一个函数

不用方法返回对象的多个子组件之间会互相影响

export default {
  return {
    name: 'foo',
    list: ['banana','apple']
  }
}

(2) data 初始化时可使用 props 值做初始化

export default {
  props: {
    userData: Object,
  },
  data() {
    return {
      name: this.userData.name,
    }
  },
}

6、Props

Props 定义应该尽量详细
  • 使用 camelCase 驼峰命名
  • 指定类型
  • 加上注释,表明其含义
  • 没有 required 就要加 default 默认值,默认值是引用类型的需要使用函数返回新对象
  • 如果有业务需要,加上 validator 验证

以上内容为强制内容,非自愿

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

7、Methods

(1) 声明 methods 无需使用 function 关键字

export default {
  methods: {
    yourMethod(arg1, arg2) {},
  },
}

(2) methods 默认上下文是 Vue 实例对象无需使用箭头函数

(3) methods 绑定原生事件无需使用.bind(this)处理

export default {
  mounted() {
    this.$nextTick(() => {
      window.addEventListener('resize', this.handleResize)
    })
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    handleResize() {},
  },
}

8、Computed

使用 Computed 替换模版中的条件判断

<template>
  <div>
    <!-- Bad -->
    <template v-for="item in list">
      <p v-if="item.name === 'foo'" key="item.name"></p>
    </template>
    <!-- Good -->
    <template v-for="item in fooList">
      <p key="item.name"></p>
    </template>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        list: [{name: 'foo'}, {name: 'bar'}]
      }
    },
    computed() {
      fooList() {
        return this.list.filter(item => item.name === 'foo')
      }
    }
  }
</script>

9、操作 DOM

(1)使用 ref 属性指定 DOM 引用,禁止使用 document.getElementId 一类的查询选择器

(2)Vue 在生命周期中、更新数据后操作实际 DOM 必须使用$nextTick 函数,禁止使用 setTimeout

<template>
  <div ref="dom" @click="handleClick">
    {{ text }}
  </div>
</template>
<script>
export default {
  data() {
    return {
      text: 'blue'
    }
  },
  mounted() {
    this.$nextTick(() => {
      console.log(this.$refs.dom.textContent)
    }),
  },
  methods: {
    handleClick() {
      this.color = 'red'
      console.log(this.$refs.dom.textContent)
      this.$nextTick(() => {
        console.log(this.$refs.dom.textContent)
      })
    }
  }
}
</script>

10、事件解绑定与定时器清理

组件对 window,document,实际 DOM 等对象进行事件绑定的要在组件卸载时解绑定事件

<template>
  <div ref="echart"></div>
</template>
<script>
import eCharts from 'echarts'
export default {
  data() {
    return {
      eChartInstance: null,
      timer: null,
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.timer = setInterval(() => {
        console.log(this.timer)
      }, 5000)
      this.eChartInstance = eCharts.init({})
      window.addEventListener('resize', this.handleResize)
      // 与beforeDestroy功能相同
      this.$once('hook:beforeDestroy', () => {
        clearInterval(this.timer)
        this.eChartInstance.dispose() // 释放图表实例
        window.removeEventListener('resize', this.handleResize)
      })
    })
  },
  beforeDestroy() {
    clearInterval(this.timer)
    this.eChartInstance.dispose() // 释放图表实例
    window.removeEventListener('resize', this.handleResize)
  },
  methods: {
    handleResize() {
      this.eChartInstance.resize()
    },
  },
}
</script>

Vue Router 规范

  • 路由名称需全局唯一,路由名称需要视图层全链路 PascalCase 命名
  • 路由跳转使用 name 参数跳转
  • 路由传参数据量大时使用 params 传递

Vuex 规范

  • 非必要数据不要放到 store 中
  • 模块多的开启 namespace
  • store 更新操作异步的应使用 action

项目目录规范

目录和静态资源使用烤串 kebab-case 命名法

功能文件使用小驼峰 camelCase 命名法

Vue 组件相关的文件和目录使用大驼峰 PascalCase 命名法

api 目录
  • api 中的方法名要按照动词+名词的命名形式来
  • api 中的每个方法要添加注释,描述清楚入参出参格式
  • api 中的每个方法都直接返回 Promise 对象
import request from '@/utils/request'
import store from '@/store'

/*
 * 获取字典
 * @type {{key:string, value: string}} dict
 * @param {string} 类型
 * @returns {dict[]}
 */
export function doGetDict(type) {
  return request.post('/management_cockpit/share/getAllBaseDefine', {
    requestParams: {
      procedure: { p_def_type: '' },
      sid: store.getters.sid,
    },
  })
}
assets 目录

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

|assets
|-- icons
|   |-- logo.svg
|-- images
|   |-- background-color.png
|   |-- upload-header.png
|-- fonts
components 目录

此目录存放全局通用组件,应按照组件进行目录划分,目录命名为 PascalCase,组件命名规则也为 PascalCase

|components
|-- AreaList.vue
|-- Particles
|   |-- index.js
|   |-- particles.json
|   |-- Particles.vue
|-- Echarts
|   |-- index.js
|   |-- Bar
|   |   |-- index.js
|   |   |-- Bar.vue
router 与 store 目录

这两个目录一定要将业务进行拆分,不能放到一个 js 文件里

views 目录

views 目录内 Vue 组件要使用 PascalCase 命名