vue组件最佳实践

看了老外的一篇关于组件开发的建议(强烈建议阅读英文原版),感受不错翻译一下加深理解。javascript

这篇文章制定一个统一的规则来开发你的vue程序,以致于达到一下目的。
1.让开发者和开发团队更容易发现一些事情。
2.让你更好的利用你的IDE.
3.让你更加容易的使用打包工具
4.让你的代码更容易碎片化以达到复用的目的。css

基于模块开发

用一些功能单一的小模块来组织你的应用html

Why?

对于你本身和你团队的人来讲较小的模块更容易看懂 维护 复用和调试。vue

How?

每一个组件应该保持单一 独立 可复用 可测试
把你很大的组件拆分红功能单一的小组件,尽可能不让一个组件的代码超过100行,保持组件独立。最好是写个组件应用的小demojava

组件命名

组件命名应该听从如下几点原则jquery

  • 有意义: 名字不要太详细,也不要太抽象。
  • 短: 名字最好是2-3个单词。
  • 可读的:容易让人能读出来以便咱们能够更容易的讨论它。

vue组件也应该遵循如下原则git

  • 听从元素命名规范 包括连字符,不要使用保留字
  • 为了在其余项目中复用,应该以某个模块名字做为命名空间

Why?

  • 为了让咱们更好地经过名字来交流这个组件,这个组件必须 短 有意义 可读

How?

<!-- 建议这样 -->
<app-header></app-header>
<user-list></user-list>
<range-slider></range-slider>

<!-- 避免这样 -->
<btn-group></btn-group> <!-- 足够短可是不容易发音,使用`button-group`代替 -->
<ui-slider></ui-slider> <!-- 全部的组件都是ui元素,因此这样命名无心义 -->
<slider></slider> <!--不是咱们适应的风格 -->

保证组件模板中的表达式简短

vue的行内式表达式都是js。当着这些js颇有效,可是也很复杂。所以你应该保持行内表达式简洁github

Why?

  • 复杂的行内表达式可读性差
  • 这些行内表达式不能任意地方复用,这样会致使代码冗余
  • IDE不支持行内式js的语法校验

How?

把复杂的语法移动到methods或者计算属性中api

<!-- recommended -->
<template>
    <h1>
        {{ `${year}-${month}` }}
    </h1>
</template>
<script type="text/javascript">
  export default {
    computed: {
      month() {
        return this.twoDigits((new Date()).getUTCMonth() + 1);
      },
      year() {
        return (new Date()).getUTCFullYear();
      }
    },
    methods: {
      twoDigits(num) {
        return ('0' + num).slice(-2);
      }
    },
  };
</script>

<!-- avoid -->
<template>
    <h1>
        {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }}
    </h1>
</template>

保证组件的props简单

尽管vue支持经过props传递复杂的object,可是你要尽可能保持props传递的数据简单,尽可能只传递基本数据类型(strings, numbers, booleans)app

Why?

  • 简洁的props让你的接口api比较简单
  • props只传递简单类型数据和函数,让咱们组件的api看起来更像原生html的属性。
  • props只传递简单类型数据,让其余开发者容易明白传什么参数。
  • props传递复杂数据类型,让你的组件很难重构,也会形成代码冗余。

How?

vue component 只传递简单数据类型或者函数以下

<!-- recommended -->
<range-slider
  :values="[10, 20]"
  min="0"
  max="100"
  step="5"
  :on-slide="updateInputs"
  :on-end="updateResults">
</range-slider>

<!-- avoid -->
<range-slider :config="complexConfigObject"></range-slider>

对你组件的props作一些限制

vue 组件中props就是api,健壮且可预测的api让别人更容易使用你的组件
组件的props经过html属性来编写,这些值能够是vue的简答字符串(:attr="value" or v-bind:attr="value")也能够不写。你应该对props作一些限制

Why?

对props作一些限制保证你的组件正常工做,即便别人没有按照你预想的方式调用你的组件。

How?

  • 属性设置默认值
  • 属性设置数据类型校验
  • 使用组件以前检查props是否存在
<template>
  <input type="range" v-model="value" :max="max" :min="min">
</template>
<script type="text/javascript">
  export default {
    props: {
      max: {
        type: Number, // [1*] This will validate the 'max' prop to be a Number.
        default() { return 10; },
      },
      min: {
        type: Number,
        default() { return 0; },
      },
      value: {
        type: Number,
        default() { return 4; },
      },
    },
  };
</script>

将组件设定为this

在组件内部上下文中,this指的是vue组件实例,所以在其余上下文中使用它的时候保证'this'在组件中可使用
换句话说,不要这样写 const self = this;

Why?

  • 经过把this分配给会改变名字的组件,告诉开发者this是一个组件实例。

How?

组件结构

让你的组件代码按照必定的顺序编写

Why?

  • 用export导出一个清晰的对象,提升代码可读性,同时让开发着统一代码结构
  • 按一下顺序排列,让代码容易被找到 (name; extends; props, data and computed; components; watch and methods; lifecycle methods, etc.);
  • 增长name属性,这样再使用vue devtools时便于开发测试。
  • 按照必定的规则写css
  • 按照以下顺序组织代码template-script-style

How?

<template lang="html">
    <div class="Ranger__Wrapper">
        <!-- ... -->
    </div>
</template>

<script type="text/javascript">
  export default {
        // Do not forget this little guy
    name: 'RangeSlider',
    // compose new components
    extends: {},
    // component properties/variables
    props: {
            bar: {}, // Alphabetized
            foo: {},
            fooBar: {},
        },
    // variables
    data() {},
    computed: {},
    // when component uses other components
    components: {},
    // methods
    watch: {},
    methods: {},
    // component Lifecycle hooks
    beforeCreate() {},
    mounted() {},
};
</script>

<style scoped>
  .Ranger__Wrapper { /* ... */ }
</style>

组件事件命名

vue提供的vue处理函数和表达式是严格绑定在vm上的。每一个组件事件应该遵循一个良好的命名规范从而避免开发中出现的问题。

Why?

  • 开发者任意使用事件名称会致使混乱,例如用了原生的事件名。
  • 随意命名事件会致使dom模板不协调。

How?

  • 事件命名按照kebab-cased(不用驼峰法)规范(例如download-success)
  • 一个事件名称对应惟一的事件
  • 事件名应该已动词(例如client-api-load)或名词(例如 drive-upload-success)结尾

避免使用this.$patent

vue支持组件嵌套,子组件得到父组件上下文,可是得到外部上下文违反了组件独立的规定,全部不要使用this.$patent

Why?

  • 就像其余组件同样vue组件也应该独立工做
  • 若是组件依赖他的父组件那么他将难以复用。

How?

  • 经过attribute/properties将数据从父组件传递给子组件
  • 在属性表达式中把在父组件中定义的会掉函数传递到子组件
  • 从子组件emit事件到父组件

谨慎使用this.$refs

vue 支持组件经过 this.$refs来得到组件或者dom元素的上下文,大部分状况下这中用法应该被禁止。当你用他的时候也应该谨慎防止错误的组件api。

Why?

  • 就像其余组件同样,vue的组件应该是独立的,不能适应全部应用场景的组件是一个很差的组件
  • 大部分状况下属性和事件已经足够用了

How?

  • 设计好的组件api
  • 多考虑一些组件在其他业务场景下的重用
  • 不要写一些特殊的代码,若是你须要些说明你须要设计一个新的组件
  • 检查是否有props缺失,若是是的话补全这些缺陷。
  • 检查全部的事件(event)大多数时候开发者只记得经过props实现父子组件通讯吗,而忘记经过自定义事件。
  • 以设计好的api和组件独立性为目的来更新你的组件
  • 当props和自定义事件实在达不到目的再用this.$refs
  • 当元素不能用数据绑定或者指令操做时,用this.$refs是比jquery和document.getElement*好一些的选择
<!-- good, no need for ref -->
<range :max="max"
  :min="min"
  @current-value="currentValue"
  :step="1"></range>
<!-- good example of when to use this.$refs -->
<modal ref="basicModal">
  <h4>Basic Modal</h4>
  <button class="primary" @click="$refs.basicModal.close()">Close</button>
</modal>
<button @click="$refs.basicModal.open()">Open modal</button>

<!-- Modal component -->
<template>
  <div v-show="active">
    <!-- ... -->
  </div>
</template>

<script>
  export default {
    // ...
    data() {
        return {
            active: false,
        };
    },
    methods: {
      open() {
          this.active = true;
      },
      hide() {
          this.active = false;
      },
    },
    // ...
  };
</script>
<!-- avoid accessing something that could be emitted -->
<template>
  <range :max="max"
    :min="min"
    ref="range"
    :step="1"></range>
</template>

<script>
  export default {
    // ...
    methods: {
      getRangeCurrentValue() {
          return this.$refs.range.currentValue;
      },
    },
    // ...
  };
</script>

使用组件名称做为css做用域

vue 组件的名字做为css根做用域类名是极好的。

Why?

  • css在style标签加上scoped能有效的防止组件内css污染外部组件的css
  • css根做用域类名和组件名相同,让开发者容易理解他们是一个组件中的。

How?

把组件名做为css命名空间依赖BEM和OOCSS(面向对象css)。在style标签上加scoped。加了scoped告诉vue在编译时给每一个类名都加一个后缀,从而避免污染其他组件或者全局样式。

<style scoped>
    /* recommended */
    .MyExample { }
    .MyExample li { }
    .MyExample__item { }

    /* avoid */
    .My-Example { } /* not scoped to component or module name, not BEM compliant */
</style>

为你的组件写api文档

一个vue实例经过实例化应用中的组件而来。这个实例经过组件属性配置而来。若是组件要提供给其余开发者使用,这些定制的属性也就是组件的api应该写在readme.md中。

Why?

  • 文档提供给开发者一个关于组件的概要,使开发者不须要看组件的源码。这样组件比较容易让人接受和使用。
  • 组件的api是使用组件须要配置项的指导。特别是对于那些只使用这个组件的开发者。
  • 组件正式的文档告诉开发者当组件代码变化了怎么去作兼容
  • README.md 是一个文档应该先被阅读的。github等代码仓库经过README.md 来展现代码内容

How?

给一个组件增长README.md

range-slider/
├── range-slider.vue
├── range-slider.less
└── README.md

其他还包括给你的组件写小demo,对组件作eslint代码审查。。

相关文章
相关标签/搜索