Vue编码风格指南

636 阅读7分钟

Vue 编码风格指南

推荐细读

什么是组件?

  • 组件是可复用的 Vue 实例,且带有一个名字。

组件衡量维度:

  • 现在被很多地方使用

  • 将来有很大可能性被复用

组件命名:

  • 有意义的:见名知意

  • 简短: 1 到 3 个单词(不包含组件前缀命名空间)

  • 具有可读性: 组件名应该倾向于完整单词而不是缩写,以便于沟通交流

  • SH 前缀作为命名空间(前缀可自定义):这样可以防止命名冲突,方便其它项目复用

  • 多个单词必须符合自定义元素规范 vue code style: 对于绝大多数项目来说,在单文件组件文件名应该总是 PascalCase的 —— 但是在模板中引用应该是 kebab-case

为什么?

  • 组件是 Vue 主要功能之一,用的地方多,所以命名需要简短、见名知意(具有可读性)

组件分类

  • 基础组件—无状态el-button、el-icon

    • 只是展示类的

    • 无业务、无第三方依赖

    • 无状态,只接受props,无 data () {}

    • 基础组件根据不同的props展现出不同的样式,并且会抛出事件来通知父级组件。

  • 基础组件—有状态:vue-lazyload、el-upload

    • 有自己维护的 data 数据(状态)

    • 可复用的逻辑组件

  • 业务组件van-address-list(地址列表)、van-submit-bar(提交订单栏)、print-net(网络打印)

    • 根据项目类型封装定制化组件

  • 二次封装组件

    • 基于第三方 UI 组件库再次封装的组件

  • 紧密耦合的组件命名规则:如:SideBar、SideBarItem

    • 和父组件紧密耦合的子组件应该以父组件名作为前缀命名

组件表达式简单化

组件内的表达式非常便利,但是设计它们的初衷是用于简单运算的。

  • 复杂行内表达式可读性差,不利于二次开发

  • 不能复用,可能导致重复编码

所以,对于任何复杂逻辑,都应当使用计算属性。

<!-- 避免 --><template>  <div id="example">    {{ message.split('').reverse().join('') }}  </div></template><!-- 推荐 --><template>  <div id="example">    <p>{{ reversedMessage }}</p>  </div></template><script type="text/javascript">  export default {      data: {        message: 'Hello'      },      computed: {        reversedMessage () {          return this.message.split('').reverse().join('')        },    },  }</script>

props 定义应该尽量详细

  • 更容易的看懂组件的用法

  • 在开发环境下,如果向一个组件提供格式不正确的 prop,Vue 将会告警,以帮助捕获潜在的错误来源

    // 避免props: ['status']// 推荐props: {  status: {    type: String,  },}

  • props 名大小写

    在声明 prop 的时候,其命名应该始终使用 camelCase

    我们单纯的遵循每个语言的约定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中则是 kebab-case。

    // 避免props: {  'greeting-text': String,}<welcome-message greetingText="hi"></welcome-message>// 推荐props: {  greetingText: String,}<welcome-message greeting-text="hi"></welcome-message>

避免 v-if 和 v-for 用在一起

永远不要把 v-if 和 v-for 同时用在同一个元素上

<!-- 避免 --><ul>  <li    v-for="user in users"    v-if="user.isActive"    :key="user.id"  >    {{ user.name }}  </li></ul><ul>  <li    v-for="user in users"    v-if="isShowUsers"    :key="user.id"  >    {{ user.name }}  </li></ul><!-- 推荐 --><ul>  <li    v-for="user in activeUsers"    :key="user.id"  >    {{ user.name }}  </li></ul><script>  data () {    return {      users: [...],    }  },  computed: {    activeUsers () {      return this.users.filter(user => user.isActive)    }  },</script><ul v-if="isShowUsers">  <li    v-for="user in users"    :key="user.id"  >    {{ user.name }}  </li></ul>

组件结构化

按照一定的结构组织,组件易于团队阅读、理解

<template lang="html">  <div class="todo-list">    <!-- ... -->  </div></template><script>  export default {    // name 属性,全局感知    name: 'todo-list',    // 使用组件 mixins 共享通用功能    mixins: [],    // 禁用子组件根元素 继承 父组件属性(不影响 class 和 style 绑定)    inheritAttrs: false,    // 组件属性、变量    props: {      // 按字母顺序      bar: {},      foo: {},      fooBar: {},    },    // 变量    data() {},    computed: {},    // 模板依赖 (模板内使用的资源)    // 使用其它组件    components: {},    directives: {},    filters: {},    // 事件 (通过响应式事件触发的回调)    watch: {},    // 生命周期钩子 (按照它们被调用的顺序)    beforeCreate() {},    created() {},    beforeMount() {},    mounted() {},    beforeUpdate() {},    updated() {},    activated() {},    deactivated() {},    beforeDestroy() {},    destroyed() {},    // 非响应式的属性 (不依赖响应系统的实例属性)    methods: {},    // 渲染 (组件输出的声明式描述)    template: ``,    render (h) {},    renderError (h, err) {},  }</script><style scoped>  .todo-list { /* ... */ }</style>

代码注释

  • 单行注释 尽量独占一行。// 后跟一个空格,缩进与下一行被注释说明的代码一致。

便于编辑器 快捷键 删除、修改

// 避免if (status === 1) { // status: 1 成功,0 失败}// 推荐// status: 1 成功,0 失败if (status === 1) {}

CSS 作用域

  • 什么是 CSS 作用域?

<style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素,也就是说,该样式只能适用于当前组件元素,也就实现了组件之间 CSS 样式隔离

  • 原理

    Vue 中的 scoped 属性的效果主要通过PostCSS转译实现,PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性,然后在CSS选择器中添加一个对应值的属性选择器,这样就实现了组件之间的样式隔离

    <!-- PostCSS 转译前 --><template>  <div class="not-found">    <div class="not-found__text">404</div>  </div></template><style scoped>.not-found__text {  color: red;}</style><!-- PostCSS 转译后 --><div data-v-32a7c634 class="not-found">  <div data-v-32a7c634 class="not-found__text">404</div></div><style>.not-found__text[data-v-32a7c634] {  color: red;}</style>

父组件层叠(覆盖)子组件样式

  • 全局样式

    • 缺点:容易污染其他组件样式

      <style>/* 全局样式 */</style>

  • 深度作用选择器

    <!-- PostCSS 转译前 --><template>  <div class="not-found">    <svg-icon name="404" class="not-found__svg"></svg-icon>  </div></template><style scoped>/* 深度作用选择器 */.not-found >>> .not-found__svg {  font-size: 3.6rem;  color: #fff;}.not-found .not-found__svg {  font-size: 3.6rem;  color: #fff;}</style><!-- PostCSS 转译后 --><template>  <div data-v-32a7c634 class="not-found">    <svg data-v-6ba02d72 data-v-32a7c634 name="404" class="not-found__svg">        <use data-v-6ba02d72>...</use>    </svg>  </div></template><style scoped>/* 深度作用选择器 */.not-found[data-v-32a7c634] .not-found__svg {  font-size: 3.6rem;  color: #fff;}/* 非深度作用选择器 */.not-found .not-found__svg[data-v-32a7c634] {  font-size: 3.6rem;  color: #fff;}</style>

动态生成的内容

通过v-html创建的DOM内容不受作用域内的样式影响,但是你仍然可以通过深度作用选择器来为他们设置样式。

元素(标签)选择器应该避免在 CSS 中出现

类选择器比元素选择器更好,因为大量使用元素选择器很慢!

单文件组件的顶级元素顺序(所有项目应保持统一)

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

元素(包括组件)特性应该有统一的顺序【非必须】

  • 定义(提供组件的选项)

    • is

  • 列表渲染(创建多个变化的相同元素)

    • v-for

  • 条件渲染 (元素是否渲染/显示)

    • v-if

    • v-else-if

    • v-else

    • v-show

    • v-cloak

  • 渲染方式 (改变元素的渲染方式)

    • v-pre

    • v-once

  • 唯一的特性 (需要唯一值的特性)

    • ref

    • key

    • slot

  • 双向绑定 (把绑定和事件结合起来)

    • v-model

  • 其它特性 (所有普通的绑定或未绑定的特性 calss style)

  • 事件 (组件事件监听器)

    • v-on

  • 内容 (覆写元素的内容)

    • v-html

    • v-text

参考