Vue 3.0 风格指南 2

#元素 attribute 的顺序推荐

元素 (包括组件) 的 attribute 应该有统一的顺序。

这是我们为组件选项推荐的默认顺序。它们被划分为几大类,所以你也能知道新添加的自定义 attribute 和指令应该放到哪里。

  1. 定义 (提供组件的选项)
    • is
  2. 列表渲染 (创建多个变化的相同元素)
    • v-for
  3. 条件渲染 (元素是否渲染/显示)
    • v-if
    • v-else-if
    • v-else
    • v-show
    • v-cloak
  4. 渲染修饰符 (改变元素的渲染方式)
    • v-pre
    • v-once
  5. 全局感知 (需要超越组件的知识)
    • id
  6. 唯一的 Attributes (需要唯一值的 attribute)
    • ref
    • key
  7. 双向绑定 (把绑定和事件结合起来)
    • v-model
  8. 其他 Attributes (所有普通的绑定或未绑定的 attribute)
  9. 事件 (组件事件监听器)
    • v-on
  10. 内容 (覆写元素的内容)
    • v-html
    • v-text

#组件/实例选项中的空行推荐

你可能想在多个 property 之间增加一个空行,特别是在这些选项一屏放不下,需要滚动才能都看到的时候。

当你的组件开始觉得密集或难以阅读时,在多个 property 之间添加空行可以让其变得容易。在一些诸如 Vim 的编辑器里,这样格式化后的选项还能通过键盘被快速导航。

好例子

 
 
  1. props: {
  2. value: {
  3. type: String,
  4. required: true
  5. },
  6. focused: {
  7. type: Boolean,
  8. default: false
  9. },
  10. label: String,
  11. icon: String
  12. },
  13. computed: {
  14. formattedValue() {
  15. // ...
  16. },
  17. inputClasses() {
  18. // ...
  19. }
  20. }

 
 
  1. // 没有空行在组件易于阅读和导航时也没问题。
  2. props: {
  3. value: {
  4. type: String,
  5. required: true
  6. },
  7. focused: {
  8. type: Boolean,
  9. default: false
  10. },
  11. label: String,
  12. icon: String
  13. },
  14. computed: {
  15. formattedValue() {
  16. // ...
  17. },
  18. inputClasses() {
  19. // ...
  20. }
  21. }

#单文件组件的顶级元素的顺序推荐

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

反例

 
 
  1. <style>/* ... */</style>
  2. <script>/* ... */</script>
  3. <template>...</template>

 
 
  1. <!-- ComponentA.vue -->
  2. <script>/* ... */</script>
  3. <template>...</template>
  4. <style>/* ... */</style>
  5. <!-- ComponentB.vue -->
  6. <template>...</template>
  7. <script>/* ... */</script>
  8. <style>/* ... */</style>

好例子

 
 
  1. <!-- ComponentA.vue -->
  2. <script>/* ... */</script>
  3. <template>...</template>
  4. <style>/* ... */</style>
  5. <!-- ComponentB.vue -->
  6. <script>/* ... */</script>
  7. <template>...</template>
  8. <style>/* ... */</style>

 
 
  1. <!-- ComponentA.vue -->
  2. <template>...</template>
  3. <script>/* ... */</script>
  4. <style>/* ... */</style>
  5. <!-- ComponentB.vue -->
  6. <template>...</template>
  7. <script>/* ... */</script>
  8. <style>/* ... */</style>

#优先级 D 的规则:谨慎使用 (潜在风险)

#scoped 中的元素选择器谨慎使用

元素选择器应该避免在 scoped 中出现。

在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。

详解
为了给样式设置作用域,Vue 会为元素添加一个独一无二的 attribute,例如 data-v-f3f3eg9。然后修改选择器,使得在匹配选择器的元素中,只有带这个 attribute 才会真正生效 (比如 button[data-v-f3f3eg9])。
问题在于大量的元素和 attribute 组合的选择器 (比如 button[data-v-f3f3eg9]) 会比类和 attribute 组合的选择器慢,所以应该尽可能选用类选择器。

反例

 
 
  1. <template>
  2. <button>×</button>
  3. </template>
  4. <style scoped>
  5. button {
  6. background-color: red;
  7. }
  8. </style>

好例子

 
 
  1. <template>
  2. <button class="btn btn-close">×</button>
  3. </template>
  4. <style scoped>
  5. .btn-close {
  6. background-color: red;
  7. }
  8. </style>

#隐性的父子组件通信谨慎使用

应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或变更 prop。

一个理想的 Vue 应用是 prop 向下传递,事件向上传递的。遵循这一约定会让你的组件更易于理解。然而,在一些边界情况下 prop 的变更或 this.$parent 能够简化两个深度耦合的组件。

问题在于,这种做法在很多简单的场景下可能会更方便。但请当心,不要为了一时方便 (少写代码) 而牺牲数据流向的简洁性 (易于理解)。

反例

 
 
  1. app.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. template: '<input v-model="todo.text">'
  9. })

 
 
  1. app.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. methods: {
  9. removeTodo() {
  10. this.$parent.todos = this.$parent.todos.filter(todo => todo.id !== vm.todo.id)
  11. }
  12. },
  13. template: `
  14. <span>
  15. { { todo.text }}
  16. <button @click="removeTodo">
  17. ×
  18. </button>
  19. </span>
  20. `
  21. })

好例子

 
 
  1. app.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. template: `
  9. <input
  10. :value="todo.text"
  11. @input="$emit('input', $event.target.value)"
  12. >
  13. `
  14. })

 
 
  1. app.component('TodoItem', {
  2. props: {
  3. todo: {
  4. type: Object,
  5. required: true
  6. }
  7. },
  8. template: `
  9. <span>
  10. { { todo.text }}
  11. <button @click="$emit('delete')">
  12. ×
  13. </button>
  14. </span>
  15. `
  16. })

#非 Flux 的全局状态管理谨慎使用

应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。

通过 this.$root 和/或全局事件总线管理状态在很多简单的情况下都是很方便的,但是并不适用于绝大多数的应用。

Vuex 是 Vue 的官方类 flux 实现,其提供的不仅是一个管理状态的中心区域,还是组织、追踪和调试状态变更的好工具。它很好地集成在了 Vue 生态系统之中 (包括完整的 Vue DevTools 支持)。

反例

 
 
  1. // main.js
  2. import { createApp } from 'vue'
  3. import mitt from 'mitt'
  4. const app = createApp({
  5. data() {
  6. return {
  7. todos: [],
  8. emitter: mitt()
  9. }
  10. },
  11. created() {
  12. this.emitter.on('remove-todo', this.removeTodo)
  13. },
  14. methods: {
  15. removeTodo(todo) {
  16. const todoIdToRemove = todo.id
  17. this.todos = this.todos.filter(todo => todo.id !== todoIdToRemove)
  18. }
  19. }
  20. })

好例子

 
 
  1. // store/modules/todos.js
  2. export default {
  3. state: {
  4. list: []
  5. },
  6. mutations: {
  7. REMOVE_TODO (state, todoId) {
  8. state.list = state.list.filter(todo => todo.id !== todoId)
  9. }
  10. },
  11. actions: {
  12. removeTodo ({ commit, state }, todo) {
  13. commit('REMOVE_TODO', todo.id)
  14. }
  15. }
  16. }

 
 
  1. <!-- TodoItem.vue -->
  2. <template>
  3. <span>
  4. { { todo.text }}
  5. <button @click="removeTodo(todo)">
  6. X
  7. </button>
  8. </span>
  9. </template>
  10. <script>
  11. import { mapActions } from 'vuex'
  12. export default {
  13. props: {
  14. todo: {
  15. type: Object,
  16. required: true
  17. }
  18. },
  19. methods: mapActions(['removeTodo'])
  20. }
  21. </script>

猜你喜欢

转载自blog.csdn.net/2201_75866484/article/details/129966315