2021-10-20 Vue official document style guide priority A summary

Official documents The code style guide is divided into four categories. For beginners or users who have used Vue.js for some time, some suggestions in Vue code are put forward. This article summarizes the rules of priority A, because these rules need to be strictly observed by users, otherwise there will be some code errors or practices that Vue does not want to see.

Priority - A - rule: necessary - error avoidance

  • The component name is more than one word

The component name should always be multiple words, except for the root component App and Vue built-in components such as < transition >, < component >.

This avoids conflicts with existing and future HTML elements, because all HTML element names are single words.

Counterexample:

Vue.component('todo', {
  // ...
})
export default {
  name: 'Todo',
  // ...
}

Good example:

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

The data of the component must be a function.

When using data property in a component (anywhere except new Vue), its value must be a function that returns an object.

Why?

When the value of data is an object, it is shared among all instances of this component. Imagine that the data of a TodoList component is as follows:

data: {
 listTitle: '',
 todos: []
}

We may want to reuse this component to allow users to maintain multiple lists (such as shopping, wish list, daily affairs, etc.). Problems arise. Because each component instance references the same data object, changing the title of one list will change the title of each other list. This is also true when adding, deleting or changing a to-do.

Instead, we want each component instance to manage its own data. To do this, each instance must generate a separate data object. In JavaScript, just return this object in a function:

data: function () {
 return {
   listTitle: '',
   todos: []
 }
}

Counterexample:

Vue.component('some-comp', {
  data: {
    foo: 'bar'
  }
})
export default {
  data: {
    foo: 'bar'
  }
}

Good example:

Vue.component('some-comp', {
  data: function () {
    return {
      foo: 'bar'
    }
  }
})
// In a .vue file
export default {
  data () {
    return {
      foo: 'bar'
    }
  }
}
// It is possible to use objects directly on the root instance of a Vue,
// Because there is only one such instance.
new Vue({
  data: {
    foo: 'bar'
  }
})
  • Prop definition

Prop definitions should be as detailed as possible.

In the code you submit, the definition of prop should be as detailed as possible, and at least its type needs to be specified.

A detailed definition of prop has two benefits:

  • They specify the API of the component, so it is easy to understand the usage of the component;
  • In the development environment, if you provide an incorrectly formatted prop to a component, Vue will alarm to help you capture potential error sources.

Counterexample:

// This is acceptable only when developing a prototype system
props: ['status']

Good example:

props: {
  status: String
}
// Better practice!
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}
  • Set key values for v-for

Always use key with v-for.

key must always be used with v-for on components to maintain the state of internal components and their subtrees. Even maintaining predictable behavior on elements, such as object constancy in animation, is a good practice.

Why?

Suppose you have a to-do list:

data: function () {
 return {
   todos: [
     {
       id: 1,
       text: 'Learn to use v-for'
     },
     {
       id: 2,
       text: 'Learn to use key'
     }
   ]
 }
}

Then you sort them alphabetically. When updating the DOM, Vue will optimize rendering to minimize possible DOM changes. It is possible to delete the first to-do element and then add it back to the end of the list.

The problem here is not to delete elements that will remain in the DOM. For example, you want to use < transition group > to add transition animation to the list, or you want to keep the focus when the rendered element is < input >. In these cases, adding a unique key value for each item (for example, key="todo.id") will let Vue know how to make the behavior easier to predict.

In our experience, it's best to always add a unique key value so that you and your team never have to worry about these extremes. In a few cases with strict performance requirements, you can deliberately do some unconventional processing in order to avoid object solidification.

Counterexample:

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

Good example:

<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>
  • Avoid using v-if and v-for together

Never use v-if and v-for on the same element at the same time.

We tend to do this in two common situations:

  • To filter items in a list (such as v-for="user in users" v-if="user.isActive"). In this case, replace users with a calculated attribute (such as activeUsers) to return the filtered list.

  • To avoid rendering lists that should have been hidden (such as v-for="user in users" v-if="shouldShowUsers"). In this case, move the v-if to the container element (such as ul, ol).

Detailed explanation:

When Vue processes instructions, v-for has higher priority than v-if, so this template:

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

The following calculation will be performed:

this.users.map(function (user) {
 if (user.isActive) {
   return user.name
 }
})

Therefore, even if we render only a small number of users' elements, we have to traverse the whole list every time we re render, regardless of whether the active users have changed or not.
By replacing it with traversal on one of the following calculated attributes:

computed: {
 activeUsers: function () {
   return this.users.filter(function (user) {
     return user.isActive
   })
 }
}
<ul>
 <li
   v-for="user in activeUsers"
   :key="user.id"
 >
   {{ user.name }}
 </li>
</ul>

We will get the following benefits:

  • The filtered list will be recalculated only when the users array changes, so the filtering is more efficient.
  • After using V-for = "user in active users", we only traverse active users during rendering, which makes rendering more efficient.
  • Decoupling the logic of the render layer makes it more maintainable (changes and extensions to the logic).

In order to obtain the same benefits, we can also put:

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

Updated to:

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

By moving the v-if to the container element, we will no longer check shouldShowUsers for each user in the list. Instead, we check it only once and do not calculate v-for when shouldShowUsers is No.

Counterexample:

<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="shouldShowUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Good example:

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

For applications, the styles in top-level App components and layout components can be global, but all other components should have scope.

This rule only applies to Single file component of You don't have to use it scoped attribute . You can also set the scope through CSS Modules , that's a class based similar BEM Of course, you can also use other libraries or conventions.

Anyway, for component libraries, we should prefer class based strategy to scoped attribute.

This makes it easier to override the internal style: it uses an understandable class name, does not have high selector priority, and is less likely to cause conflicts.

If you develop a large project with other developers, or sometimes introduce third-party HTML/CSS (such as from Auth0), setting a consistent scope will ensure that your style will only be used on the components they want to work on.

Not only should you use scoped attribute s, using a unique class name can help you ensure that the CSS of those third-party libraries will not be used on your own HTML. For example, many projects use button, btn or icon class names, so even if you do not use a BEM like strategy, adding an app specific or component specific prefix (such as buttonclose icon) can provide a lot of protection.

Counterexample:

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

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

Good example:

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

<!-- use `scoped` attribute -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

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

<!-- use 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>

<!-- use BEM appointment -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

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

Use the module scope to maintain the privacy of functions that do not allow external access. If this cannot be done, it will always be used for plug-ins, mixed INS, etc., regardless of the use of custom private properties as external public API s$_ Prefix. With a namespace to avoid conflicts with other authors (such as $_yourPluginName_).

Vue use_ Prefix to define its own private property, so using the same prefix (such as _update) risks overwriting the instance property. Even if you check and confirm that the current version of Vue does not use this property name, there is no guarantee that it will not conflict with future versions.

For the $prefix, its purpose in the Vue ecosystem is to expose a special instance property to users, so it is not appropriate to use it for private property.

However, we recommend combining these two prefixes into $, As a user-defined private property contract to ensure that it does not conflict with Vue itself.

Counterexample:

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

Good example:

var myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update: function () {
      // ...
    }
  }
}
// Even better!
var myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin

The above are all the rules of priority A. priority B, C and D are mainly to enhance readability and some suggestions for users to write code. You can stamp them if you need to read them here View official documentation.

Tags: Javascript Front-end Vue Vue.js

Posted on Thu, 21 Oct 2021 21:24:26 -0400 by mryno