Vue风格指南小结
必要的
-
组件名为多个单词,避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
// in todo-item.vue export default { name: 'TodoItem', // ... }
-
组件的
data
必须是一个函数。(.vue中) -
props定义尽量详细,比如指定类型,是否必要,和数值验证等等
-
v-for要设置key
<li v-for="todo in todos" :key="todo.id" > {{ todo.text }} </li>
-
v-for和v-if不能一起使用,可以选择用计算属性来过滤数据
-
为组件的样式设置作用域
<style scoped>
-
私有property名 (不理解)
强烈推荐的
-
把每个组件单独分成文件(.vue)
-
命名:单文件组件的文件名要么始终为大驼峰,要么全小写横线链接
MyComponent.vue or my-component.vue
-
基础组件名 (无状态,无逻辑,展示用的)应该全部以一个特定的前缀开头,比如
Base
、App
或V
。好例子 components/ |- BaseButton.vue |- BaseTable.vue |- BaseIcon.vue -----or------ components/ |- AppButton.vue |- AppTable.vue |- AppIcon.vue ----反例--- components/ |- MyButton.vue |- VueTable.vue |- Icon.vue
-
每个页面只使用一次,不接收props的单例组件名以
The
开头,以示其唯一性。因为它们是为你的应用定制的,而不是它们在你的应用中的上下文(可能不太好理解)// 好例子 components/ |- TheHeading.vue |- TheSidebar.vu
-
紧密耦合的组件名应该以父组件作为前缀命名
// 反例 components/ |- TodoList.vue |- TodoItem.vue |- TodoButton.vue // 正例 components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue
-
组件名中的单词顺序应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。
components/ |- SearchButtonClear.vue |- SearchButtonRun.vue |- SearchInputQuery.vue ----反例 components/ |- ClearSearchButton.vue |- SearchInput.vue
-
自闭合组件:在单文件组件、字符串模板和 JSX 中自闭合,在DOM模板不自闭合
<!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component>
-
在单文件组件和字符串模板中大驼峰
<MyComponent/>
,Dom模板或者也可以在所有地方中小写+中划线分割<my-component></my-component>
-
JS/JSX中的组件名应该始终为大驼峰 PascalCase
import MyComponent from './MyComponent.vue' ... export default { name: 'MyComponent', // ... }
-
prop名定义的地方小驼峰camelCase,模板中使用到用小写+中划线分割kebab-case
props: { greetingText: String } ... <WelcomeMessage greeting-text="hi"/>
-
标签中多个属性分多行撰写
<MyComponent foo="a" bar="b" baz="c" />
-
组件模板中只包含简单的表达式,复杂的用计算属性
-
小的、专注的计算属性(将复杂的分割为简单的)
-
带引号的 attribute 值 `
-
指令缩写要么都有要么都不用 (用
:
表示v-bind:
、用@
表示v-on:
和用#
表示v-slot:
)<template #footer> <p>Here's some contact info</p> </template>
推荐的
-
组件/实例的选项顺序
- el
- name,parent 全局感知的
- functional 更改组件类型
- delimiters/comments 更改模板的编译方式
- components/directives/filters 模板依赖/模板内使用的资源
- extends,mixins (向选项里合并 property)
- inheritAttrs/mode/, props/propsData 组件的接口
- data/computed 本地状态
- watch 事件 通过响应式事件触发的回调
- 生命钩子
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
- 非响应式的property:methods
- 渲染:template/render
-
元素(包括组件)的attribute应该有统一的顺序
- 定义:is (提供组件的选项) :暂时没见过
- 列表渲染:v-for
- 条件渲染:v-if | v-else-if | v-else | v-show | v-cloak
- 渲染方式:v-pre | v-once
- 全局感知:id
- 唯一的attribute ref | key
- 双向绑定:v-model
- 其他普通attribute
- 事件:v-on
- 内容:v-html | v-text
-
单文件组件的顶级元素的顺序
<template>...</template> <script>/* ... */</script> <style>/* ... */</style>
谨慎使用
-
没有在 v-if/v-else-if/v-else 中使用 key,如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个
元素)。反例
<div v-if="error"> 错误:{{ error }} </div> <div v-else> {{ results }} </div>
好例子
<div v-if="error" key="search-status" > 错误:{{ error }} </div> <div v-else key="search-results" > {{ results }} </div>
-
元素选择器应该避免在 scoped 中出现。
在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。
反例
<template> <button>X</button> </template> <style scoped> button { background-color: red; } </style>
好例子
<template> <button class="btn btn-close">X</button> </template> <style scoped> .btn-close { background-color: red; } </style>
-
应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或变更 prop。
反例1
Vue.component('TodoItem', { props: { todo: { type: Object, required: true } }, template: '<input v-model="todo.text">' })
好例子1
Vue.component('TodoItem', { props: { todo: { type: Object, required: true } }, template: ` <input :value="todo.text" @input="$emit('input', $event.target.value)" > ` })
反例2
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> ` })
好例子2
Vue.component('TodoItem', { props: { todo: { type: Object, required: true } }, template: ` <span> {{ todo.text }} <button @click="$emit('delete')"> X </button> </span> ` })
-
应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。
好例子
// store/modules/todos.js export default { state: { list: [] }, mutations: { REMOVE_TODO (state, todoId) { state.list = state.list.filter(todo => todo.id !== todoId) } }, actions: { removeTodo ({ commit, state }, todo) { commit('REMOVE_TODO', todo.id) } } } <!-- TodoItem.vue --> <template> <span> {{ todo.text }} <button @click="removeTodo(todo)"> X </button> </span> </template> <script> import { mapActions } from 'vuex' export default { props: { todo: { type: Object, required: true } }, methods: mapActions(['removeTodo']) } </script>