[译] VueJs 最佳实践✓

627 阅读3分钟

原文链接

开发者们,你们好。

经过网上的一段搜索以及查阅Vue.js的文档,我写下了本文中关于Vue的最佳实践以及风格指南,从而可以更正确,更优雅的使用Vue.js。

下面的要点指出了其中一些功能/优化相关,其他是VueJs命名约定和元素排序。 更详细的信息可以在链接中找到。

题图

在组件销毁之后使用$off清除事件监听器

当我们在使用$on监听事件的时候,总是需要在事件销毁(destroyed())的时候使用$off清除事件监听,这样可以有效防止内存泄漏。

事件名称使用短横线式命名(kebab-case)

在派发/监听事件的时候,我们应该始终使用短横线式命名(kebab-case),这是因为事件最终会被自动转换为该命名方式。我们监听的时间格式不能是驼峰式以及Pascal式,因此在声明时间的时候,最好就讲时间命名为短横线式。例如:

// Emitting
this.$emit('my-event') // instead of myEvent
// Listening
v-on:my-event

避免在created以及watch中调用相同的method

如果我们需要触发组件初始化和属性更改的方法,通常的做法是执行以下操作:

watch: {
  myProperty() {
    this.doSomething();
  }
},
created() {
  this.doSomething();
},
methods: {
  doSomething() {
     console.log('doing something...');
  }
},

尽管这样看起来挺正确的,但是这里对于created()的使用是多余的。我们本可以将所有的功能放入watch,从而避免在created()里面写重复的代码,这样同样可以在生成组件实例的时候触发。例如:

watch: {
  myProperty: {
    immediate: true, // forcing handler on initial status
    handler() {
      this.doSomething();
    }
  }
},
methods: {
  doSomething() {
     console.log('doing something...');
  }
},
// Even better solution
watch: {
  myProperty: {
    immediate: true, // forcing handler on initial status
    handler() {
      console.log('doing something...'); // No need to declare a function on methods for 1 use case
    }
  }
},

总是在v-for循环中使用 :key

通常来说,在模板的循环中添加:key是一个最佳实践,不包含:keyv-for循环会导致很难以查出的bug,尤其是在动画效果里面。

为混入属性(mixins properties)使用$_符号标记

Mixins 是是将重复代码放入一个块并将其导入多次的好方法,但很多情况下,这可能会导致一些问题。 在这一点上,我们将解决重叠属性的问题。

当我们讲一个mixin导入到我们的组件当中时,实际上是在吧minxin的代码和组件中原本的代码合并(merge)起来,那么同名的属性会呈现什么样呢?一般来说,组件的优先级更高,并且会覆盖mixin。

那么我要是需要mixin有更高的优先级,该怎么办呢?开发过程中并不能声明优先级,但是你可以避免属性的叠加,并且使用合适的命名方式来规避属性的重写。

In order to differentiate mixin properties from Component properties we use $_. Why these symbols? Well, several reasons: 为了将Mixin的属性与组件的属性相区分,我们使用$_,原因如下:

  1. 这是Vuejs传统风格
  2. _在Vuejs中表示私有属性
  3. $属于Vue的保留字

风格指南可以看到官方推荐的Mixin命名:$_myMixin_updateUser

我发现添加mixin名称会产生比可读性更多的混乱。 但这也取决于mixin,情况和开发人员。

通过在Mixin之前添加$_,例如$_updateUser,我发现代码更具可读性,可以轻松区分Component和Mixin。

在Mixin中使用的属性必须全部包含在Mixin之中

继上一点之后,mixins还有另外一个问题:mixin不够独立。

如果我们创建一个使用的mixin,比方说,this.language并没有从mixin中的store中定义或获取此属性,那么定义mixin的Component必须包含language属性。

正如您已经知道的那样,这非常容易出错。 为了避免这些错误,我们在mixin里面获取所有需要的数据。 不要担心,如果我们两次获取数据,VueJs是聪明的,如果检测到从store获取到相同的东西,将不会做双重工作(因为大多数情况下会从Vuex获取数据)

对单文件组件使用PascalCase或kebab-case

PascalCase与编辑器具有更好的集成,并允许在常用IDE中实现更好的自动完成/导入功能。

如果我们想要避免使用不区分大小写的文件系统的问题,那么就应该使用kebab-case。

基础组件名称之前加前缀

装饰性、基础组件应该有一个前缀,以区别于其他复杂组件。 这大大提高了项目的可读性以及团队和开发人员之间的合作效率。

JS组件需以PascalCase 命名

在JavaScript中,类和原型构造方法一般使用PascalCase 命名,并且Vue组件也需要按此方式命名。

如果我们只通过Vue.component使用全局组件,那可以使用kebab-case。

Prop 在声明时需要按照CamelCase命名,但是在模板中需要改成kebab-case

HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名。

按照风格指南设置组件内部选项顺序

这看起来没什么意义,但是按此规则写成的组件更适合于大型多人开发项目,并且方便日后的扩展。

详情在[风格指南]vuejs.org/v2/style-gu…)

不在同一个元素上同时使用v-if和v-for

这是一个性能杀手,列表越长,这种不良做法会带来越多的性能损失。

让我们用代码解释一下,想象一下以下案例场景:

<ul>
  <li
    v-for="game in games"
    v-if="game.isActive"
    :key="game.slug"
  >
    {{ game.title }}
  <li>
</ul>

与下面这种写法相比较:

this.games.map(function (game) {
  if (game.isActive) {
    return game.title
  }
})

不论games是否改变其活动状态,我们每一次都需要遍历整个games列表。

在Angular等其他框架中,这样写不能通过编译:

(**ngIf* can't go in the same element where there is an **ngFor*)*。

Actions必须要有返回值

这是Vuex的actions和async/await的冲突造成的,请看这个例子:

// Store
[SOME_ACTION] () {
   // Doing stuff that takes a while
   console.log('Action done');
}
// Consuming action
async doSomething() {
  await dispatch(SOME_ACTION);
  console.log('Do stuff now');
}
This will output:
// Do stuff now
// Action done

发生这种情况是因为await不知道要等待什么,相反,如果我们实际返回Promise.resolve(),则await将等待解析然后才继续。

// Store
[SOME_ACTION] () {
   // Doing stuff that takes a while
   console.log('Action done');
   Promise.resolve();
}
// Consuming action
async doSomething() {
  await dispatch(SOME_ACTION);
  console.log('Do stuff now');
}
This will output:
// Action done
// Do stuff now

在actions和getters内部使用选择器

我们创建选择器是不仅要在app过程中使用,还要在Vuex的store中使用。

例如:

// We have this selector
export const language = (state) => state.userConfig.language;
// In one of our actions, we need language:
// Bad
[GET_GAMES]({ commit, rootState }) {
   const lang = rootState.userConfig.language;
   // Do stuff...
}
// Good
[GET_GAMES]({ commit, rootState }) {
   const lang = language(rootState);
   // Do stuff...
}

总结

  1. 在组件销毁之后使用$off清除事件监听器 source
  2. 事件名称使用短横线式命名(kebab-case) source
  3. 避免在created以及watch中调用相同的method source
  4. **总是在v-for循环中使用 :keysource
  5. 为混入属性(mixins properties)使用$_符号标记 source
  6. 在Mixin中使用的属性必须全部包含在Mixin之中
  7. 对单文件组件使用PascalCase或kebab-case source
  8. 基础组件名称之前加前缀 source
  9. JS组件需以PascalCase 命名 source
  10. **Prop 在声明时需要按照CamelCase命名,但是在模板中需要改成kebab-casesource
  11. 按照风格指南设置组件内部选项顺序 source
  12. 不在同一个元素上同时使用v-if和v-for source
  13. Actions必须要有返回值
  14. 在actions和getters内部使用选择器

参考文献

后记

这篇文章是在使用VueJs之后完成的。 遵循这些风格指南和最佳实践有助于让每个新开发者都有宾至如归的感觉,并立即投入到工作中!

翻译后记

这篇文章着重于代码风格,良好的代码风格是优秀代码的必要条件,也是多人合作过程中必不可少的一部分,之前阅读过阿里的Java手册,深感一个庞大的项目,除了语法之外,也必须在开发之前对于全体开发者的代码风格进行约束,虽然目前有了Eslint之类的风格检查工具,但是诸如命名等还是需要统一约束。

文章还对一些会影响性能以及容易报错的写法进行了纠正。总体来说值得一读,也值得翻译过来给大家看看😉