Vue风格指南总结

Vue风格指南是官方推荐的代码规范,按照指南开发大型Vue应用,可以避免项目后期出现不可预料的问题或BUG。

官方把规范定义了四个级别:A级表示必要的,B级表示强烈推荐,C级表示推荐,D级表示谨慎使用。示例代码官方给了正例和反例,我只总结了正例的写法。就像开发API一样,正确的情况通常只有一种,而错误的情况会有很多种,所以只要记住正确的就行了

A级 必要的

自定义组件在命名时,应该使用多个单词,这样可以避免未来和HTML元素冲突

Vue.component('todo-item', {
  // ...
})
export default {
  name: 'TodoItem',
  // ...
}

组件中的data必须是一个函数,这样可以保证组件在复用时,每个组件实例都能管理自己的数据,避免数据的交叉感染

Vue.component('some-comp', {
  data: function () {
    return {
      foo: 'bar'
    }
  }
})
export default {
  data () {
    return {
      foo: 'bar'
    }
  }
}
// 在Vue根实例上可以直接使用对象,因为只存在一个这样的实例
new Vue({
  data: {
    foo: 'bar'
  }
})

定义Prop应该尽量详细,至少需要指定其类型,这样能更容易的看懂组件的用法

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

在组件上使用v-for必须和key配合,这样可以在更新 DOM 的时候,Vue 将会优化渲染,把可能的 DOM 变动降到最低

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

永远不要把 v-if 和 v-for 同时用在同一个元素上,因为这样做会导致每次条件判断,都需要重新遍历整个列表。可以把条件判断放到容器上

<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

组件的样式必须设置作用域,设置作用域的方式可以是使用scoped属性、CSS Modules或者基于 class 的类似 BEM 的策略

基于class的作用域策略是更值得推荐的,因为这样外部更容易覆写组件样式

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

<!-- 使用 `scoped` 特性 -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {
  background-color: red;
}
</style>
<template>
  <button :class="[$style.button, $style.buttonClose]">X</button>
</template>

<!-- 使用 CSS Modules -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {
  background-color: red;
}
</style>
<template>
  <button class="c-Button c-Button--close">X</button>
</template>

<!-- 使用 BEM 约定 -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

.c-Button--close {
  background-color: red;
}
</style>

在插件、混入等扩展中始终为自定义的私有属性使用 $_ 前缀,并附带一个命名空间以回避和其它作者的冲突 (比如 $yourPluginName)。

var myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update: function () {
      // ...
    }
  }
}

B级 推荐

单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)。

components/
|- MyComponent.vue
components/
|- my-component.vue

基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue

单例组件应该以 The 前缀命名,以示其唯一性

单例组件不是指只能用于一个单页面,而是指每个页面只使用一次,并且这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文

components/
|- TheHeading.vue
|- TheSidebar.vue

和父组件紧密耦合的子组件应该以父组件名作为前缀命名,因为编辑器通常会按字母顺序组织文件,这样做可以把相关联的文件排在一起

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的,但在 DOM 模板里永远不要这样做,因为HTML 并不支持自闭合的自定义元素

<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>

在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case

props: {
  greetingText: String
}
<WelcomeMessage greeting-text="hi"/>

JS/JSX 中的组件名应该始终是 PascalCase 的,尽管在较为简单的应用中使用 Vue.component 进行全局组件注册时,可以使用 kebab-case 字符串

Vue.component('MyComponent', {
  // ...
})
Vue.component('my-component', {
  // ...
})
import MyComponent from './MyComponent.vue'
export default {
  name: 'MyComponent',
  // ...
}

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

<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>

C级 推荐

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

<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

<!-- ComponentB.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>

D级 谨慎使用

官方把D级定义为谨慎使用,表示的是这样做可能有潜在的危险,我下面直接把推荐的做法总结了一下

如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个 <div> 元素)。

<div
  v-if="error"
  key="search-status"
>
  错误:{{ error }}
</div>
<div
  v-else
  key="search-results"
>
  {{ results }}
</div>
<p v-if="error">
  错误:{{ error }}
</p>
<div v-else>
  {{ results }}
</div>

隐性的父子组件通信

应该优先通过 prop 和事件进行父子组件之间的通信,而不是使用 this.\(parent 改变 prop。尽管this.\)parent 这种做法在很多简单的场景下可能会更方便,但这样做会牺牲数据流向的简洁性

Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: `
    <input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    >
  `
})

官方文档

posted @ 2021-09-30 15:17  wmui  阅读(283)  评论(0编辑  收藏  举报