还在担心不会常用的 Vue2.x 代码规范吗?看这篇就够了。

Vue 2.x 规范

组件 data 必须是一个函数

当在组件中使用 data 的时候 (除了 new Vue 外的任何地方),它的值必须是一个返回对象的函数,这样做可以规避一些组件复用时的 bug

不推荐

export default {
    data: {
        foo: 'bar'
    }
}
复制代码

推荐

export default {
    data () {
        return {
          	foo: 'bar'
        }
    }
}
复制代码

Prop 定义尽量详细

Prop 的定义应该尽量详细,至少需要指定其类型,这样可以避免一些潜在的类型错误

不推荐

// 来源:src\components\chart\embedexcel\dataFilterModal.vue
props: ["position", "spread"]
复制代码

推荐

props: {
    strProp: {
        type: String,
        default: ''
    },
    arrProp: {
        type: Array,
        default: () => []
    },
    objProp: {
        type: Object,
        default: () => ({})
    }
}
复制代码

v-for 设置唯一键值

使用 v-for 时必须设置唯一的 key,以便 Vue 在渲染时把可能的 DOM 变更降到最低

不推荐

<!-- 来源:src\components\easy-more\easyShowMoreToolTip.vue -->
<p v-for="(item,index) in arr">
  	{{item[keyVal]}}
</p>
复制代码

推荐

<ul>
    <li
      	v-for="todo in todos"
      	:key="todo.id"
    >
      	{{ todo.text }}
    </li>
</ul>
复制代码

避免 v-for 和 v-if 同时使用(一)

当过滤一个列表中的项目时,永远不要把 v-for 和 v-if 同时用在同一个元素上,取而代之的是使用计算属性

不推荐

<div
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
>
  	{{ user.name }}
</div>
复制代码

推荐

<div
  	v-for="user in activeUsers"
  	:key="user.id"
>
  	{{ user.name }}
</div>
复制代码
computed: {
    activeUsers: function () {
      	return this.users.filter(() => user.isActive)
    }
}
复制代码

避免 v-for 和 v-if 同时使用(二)

当需要隐藏一个本应该被隐藏的列表时,永远不要把 v-for 和 v-if 同时用在同一个元素上,取而代之的是添加一个父元素并在父元素上使用 v-if

不推荐

<!-- 来源:src\components\toolBarComponent\liquidfill\liquidfillNumericalSet.vue -->
<div v-if="!numericalSet.configs.length" class="noInfo">
</div>
<div v-for="(field,indexs) in numericalSet.configs" :key="field.columnId" v-else>
</div>
复制代码

推荐

<template v-if="shouldShowUsers">
    <div
        v-for="user in users"
        :key="user.id"
    >
      	{{ user.name }}
    </div>
</template>
复制代码

Mixin 中使用私有属性名

为避免混入时属性相冲突,建议对插件、混入等不考虑作为公共 API 的自定义私有属性使用 $_ 前缀

不推荐

// 来源:src\views\Pages\Dashboard\mixins\embedexcelFuncs.js
export const embedexcelFuncs = {
    data () {
        return {
          	styleTemp: {}
        }
    },
      methods: {
          handleSpaceList() {}
      }
}
复制代码

推荐

export const myGreatMixin = {
    data () {
        return {
          	$_myGreatMixin_title: ''
        }
    },
    methods: {
      	$_myGreatMixin_update: function () {}
    }
}
复制代码

组件命名应由多单词组成

组件名应该始终是多个单词的(根组件 App 以及 Vue 内置组件除外)且命名风格为大驼峰,这样做可以避免跟现有或未来的 HTML 元素相冲突

不推荐

Vue.component('todo', {
  	// ...
})

// 来源:src\components\modal\confirm.vue
export default {
  	name: 'confirm',
  	// ...
}
复制代码

推荐

Vue.component('TodoItem', {
  	// ...
})

export default {
  	name: 'BaseConfirm',
  	// ...
}
复制代码

为组件的样式设置作用域

除特殊情况(如 element 部分组件的 dom 会被 transfer 到 body 下)外,单文件组件应该对样式设置作用域,以免当前组件的样式影响到其他组件的样式

不推荐

<!-- 来源:src\components\chart\slicertabs\relevanceCharts.vue -->
<template>
  	<div class="common_bottom_20"></div>
</template>

<style>
.common_bottom_20 {
  	margin-bottom: 20px;
}
</style>
复制代码

推荐

<template>
  	<button class="button">X</button>
</template>

<style scoped>
.button {
    border: none;
    border-radius: 2px;
}
</style>
复制代码

单文件组件的文件命名

单文件组件的文件命名风格应保持一致,统一为大驼峰

不推荐

components/
|- table-page.vue
|- dragRightIcon.vue
|- UserInfoModal.vue
复制代码

推荐

components/
|- TablePage.vue
|- DragRightIcon.vue
|- UserInfoModal.vue
复制代码

模板中的组件名大小写

在 Vue 模板中,统一使用烤肉串命名法(不强制

不推荐

<mycomponent/>
<myComponent/>
<MyComponent></MyComponent>
复制代码

推荐

<my-component></my-component>
复制代码

自闭合组件

在 Vue 模板中,组件统一自闭合

不推荐

<my-component></my-component>
复制代码

推荐

<my-component/>
复制代码

完整单词的组件名

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

不推荐

components/
|- SdSettings.vue
|- UProfOpts.vue
复制代码

推荐

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
复制代码

Prop 名大小写

在声明 prop 的时候,其命名应该始终使用小驼峰命名,而在 Vue 模板中应该始终使用烤肉串命名

不推荐

props: {
  	'greeting-text': String
}
复制代码
<!-- 来源:src\views\Pages\Workbench\selfSupportTemplete\header.vue -->
<easy-select searchWidth="278px"></easy-select>
复制代码

推荐

props: {
    greetingText: {
      	type: String,
      	default: '',
    }
}
复制代码
<welcome-message greeting-text="hi"/>
复制代码

多个 attribute 的元素

多个 attribute 的元素应该分多行撰写,每个 attribute 一行,因为这样更易读

不推荐

<Icon type="ios-search" @click="changeSearchStatus" v-if='!info.isSearch'></Icon>
复制代码

推荐

<my-component
    foo="a"
    bar="b"
    baz="c"
></my-component>
复制代码

模板中简单的表达式

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法,因为计算属性和方法直观且可复用

不推荐

<!-- 来源:src\views\Pages\Authority\basicSet\ocAutoConfig.vue -->
{{item.split('-status:')[0].split('/')[0]}}
复制代码

推荐

{{ normalizedFullName }}
复制代码
computed: {
    normalizedFullName: function () {
        return this.fullName.split(' ').map(function (word) {
          	return word[0].toUpperCase() + word.slice(1)
        }).join(' ')
    }
}
复制代码

计算属性 SRP

应该把复杂计算属性分割为尽可能多的更简单的 property,一个属性只做一件事(即单一职责原则),这样易于测试、阅读以及更好的拥抱变化

不推荐

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

推荐

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

带引号的 attribute 值

非空 attribute 的值应该始终带引号(推荐双引号),增加可读性

不推荐

<!-- 来源:src\components\chart\slicertabs\slicertabs.vue -->
<el-date-picker
  	:type=timeFilterType[item.columnFilterType]
  	:format=timeFormat[item.columnFilterType]
>
</el-date-picker>
复制代码

推荐

<input type="text">
<app-side-bar :style="{ width: sidebarWidth + 'px' }"></app-side-bar>
复制代码

指令缩写统一

指令缩写(用 : 表示 v-bind:,用 @ 表示 v-on:,和用 # 表示 v-slot:)应该要么都用要么都不用,推荐缩写

推荐

<template #footer>
    <div @click="divClick">
      	<div :someProp="propData"></div>
    </div>
</template>
复制代码

组件/实例的选项顺序统一

组件/实例的选项应该有统一的顺序

  1. 副作用 (触发组件外的影响)
    • el
  2. 全局感知 (要求组件以外的知识)
    • name
    • parent
  3. 组件类型 (更改组件的类型)
    • functional
  4. 模板修改器 (改变模板的编译方式)
    • delimiters
    • comments
  5. 模板依赖 (模板内使用的资源)
    • components
    • directives
    • filters
  6. 组合 (向选项里合并 property)
    • extends
    • mixins
  7. 接口 (组件的接口)
    • inheritAttrs
    • model
    • props/propsData
  8. 本地状态 (本地的响应式 property)
    • data
    • computed
  9. 事件 (通过响应式事件触发的回调)
    • watch
  10. 生命周期钩子 (按照它们被调用的顺序)
    • beforeCreate
    • created
    • beforeMount
    • mounted
    • beforeUpdate
    • updated
    • activated
    • deactivated
    • beforeDestroy
    • destroyed
  11. 非响应式的 property (不依赖响应系统的实例 property)
    • methods
  12. 渲染 (组件输出的声明式描述)
    • template/render
    • renderError

常用组件选项示例

new Vue({
    el: '',
    name: '',
    components: {},
    directives: {},
    filters: {},
    mixins: [],
    props: {},
    data () {},
    computed: {},
    watch: {},
    beforeCreate () {},
    created () {},
    beforeMount () {},
    mounted () {},
    beforeDestroy () {},
    destroyed () {},
    methods: {},
    template: ``,
    render () {}
})
复制代码

元素 attribute 的顺序统一

元素 (包括组件) 的 attribute 应该有统一的顺序(不强制

  1. 定义 (提供组件的选项)
    • is
  2. 列表渲染 (创建多个变化的相同元素)
    • v-for
  3. 条件渲染 (元素是否渲染/显示)
    • v-if
    • v-else-if
    • v-else
    • v-show
    • v-cloak
  4. 渲染方式 (改变元素的渲染方式)
    • v-pre
    • v-once
  5. 全局感知 (需要超越组件的知识)
    • id
  6. 唯一的 attribute (需要唯一值的 attribute)
    • ref
    • key
  7. 双向绑定 (把绑定和事件结合起来)
    • v-model
  8. 其它 attribute (所有普通的绑定或未绑定的 attribute)
  9. 事件 (组件事件监听器)
    • v-on
  10. 内容 (覆写元素的内容)
    • v-html
    • v-text

常用 attribute 示例

<input
    v-for=""
    v-once
    id=""
    ref=""
    :key=""
    v-model=""
    class=""
    style=""
    v-on=""
    v-html=""
/>
复制代码

单文件组件的顶级元素顺序

单文件组件应该总是让 <template><script><style> 标签的顺序保持一致,且 <style> 要放在最后,因为另外两个标签至少要有一个

不推荐

<style>/* ... */</style>
<template>...</template>
<script>/* ... */</script>
复制代码

推荐

<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
复制代码

scoped 中慎用元素选择器

元素选择器应该避免在 scoped 中出现,因为在 scoped 样式中,类选择器比元素选择器更快

不推荐

<style scoped>
/* 来源:src\layouts\SiderMenu.vue */
button span {
  	color: #447ee7;
}
</style>
复制代码

推荐

<template>
  	<button class="btn btn-close">X</button>
</template>

<style scoped>
.btn-close {
  	background-color: red;
}
</style>
复制代码

避免父子组件隐式通信

应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或变更 prop

不推荐

Vue.component('TodoItem', {
    props: {
        todo: {
            type: Object,
            required: true
        }
    },
    template: '<input v-model="todo.text">'
})
复制代码
Vue.component('TodoItem', {
    props: {
        todo: {
            type: Object,
            required: true
        }
    },
    methods: {
        removeTodo () {
            var vm = this
            vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
              	return todo.id !== vm.todo.id
            })
        }
    },
    template: `
        <span>
            {{ todo.text }}
            <button @click="removeTodo">
              	X
            </button>
        </span>
    `
})
复制代码

推荐

Vue.component('TodoItem', {
    props: {
        todo: {
            type: Object,
            required: true
        }
    },
    template: `
        <input
            :value="todo.text"
            @input="$emit('input', $event.target.value)"
        >
    `
})
复制代码
Vue.component('TodoItem', {
    props: {
        todo: {
            type: Object,
            required: true
        }
    },
    template: `
        <span>
            {{ todo.text }}
            <button @click="$emit('delete')">
              	X
            </button>
        </span>
    `
})
复制代码

通过 commit 修改状态

应当通过 commit 显式地修改状态而不是直接给状态赋值,这样可以更明确地追踪到状态的变化,也能让一些调试工具记录每次状态的改变(不强制

不推荐

// 来源:src\views\Pages\Workbench\selfSupportTemplete\setMenu\crossTable.vue
this.$store.state.selfOrderLimit = item.nodeData.selfOrderLimit
复制代码

推荐

this.store.commit('changeSelfOrderLimit', item.nodeData.selfOrderLimit)
复制代码

善用修饰符

大多数事件中,Vue 都提供了修饰符,使用可提高开发效率

不推荐

<!-- 来源:src\views\Pages\Workbench\electronicForm\tableData.vue -->
<div @click="stopPropagation($event)">
复制代码
stopPropagation($event) {
  	$event.stopPropagation();
}
复制代码

推荐

<div @click.stop>
复制代码

请求写在 created 中

除特殊情况(比如动态组件使用了 keep-alive)外,在 created 中处理请求是最佳实践

不推荐

mounted () {
    api.getAuthTreeAjax()
      	.then(() => {})
      	.catch(() => {})
}
复制代码

推荐

created () {
    api.getAuthTreeAjax()
      	.then(() => {})
      	.catch(() => {})
}
复制代码

公共组件应附上 README

公共组件的编写应随之附上 README,README 中应详细描述 props、插槽、事件和对外暴露的方法的使用说明,做到“箱说齐全”

公共组件 README 模板

### 组件描述

这里是组件描述

### props

| 属性 | 类型 | 默认值 | 描述 |
| -- | -- | -- | -- |
| disabled | Boolean | false | 是否禁用组件 |

### 插槽

| 插槽名 | slotProps | 描述 |
| -- | -- | -- |
| default | `{ userName: 'John', userAge: 24 }` | 默认插槽 |

### 事件

| 事件名 | 返回值 | 返回值类型 | 描述 |
| -- | -- | -- | -- |
| on-select | 当前选中项 | String | 当选中选项时触发该事件 |

### 暴露的方法

| 方法名 | 参数 | 参数类型 | 描述 |
| -- | -- | -- | -- |
| resetForm | - | - | 重置表单 |
复制代码

猜你喜欢

转载自juejin.im/post/7055578160116531237