Vue前端开发规范(转载)

基于模块开发

始终基于模块的方式来构建你的 app,每一个子模块只做一件事情。
Vue.js 的设计初衷就是帮助开发者更好的开发界面模块。一个模块是应用程序中独立的一个部分。

怎么做?

每一个 Vue 组件(等同于模块)首先必须专注于解决一个单一的问题,独立的、可复用的、微小的 和 可测试的。

如果你的组件做了太多的事或是变得臃肿,请将其拆分成更小的组件并保持单一的原则。

一般来说,尽量保证每一个文件的代码行数不要超过 100 行

也请保证组件可独立的运行。

比较好的做法是增加一个单独的 demo 示例。

组件

组件的命名需遵从以下原则:

  • 有意义的: 不过于具体,也不过于抽象
  • 简短: 2 到 3 个单词
  • 具有可读性: 以便于沟通交流

同时还需要注意:

  • 必须符合自定义元素规范: 使用连字符分隔单词,切勿使用保留字。
  • app- 前缀作为命名空间: 如果非常通用的话可使用一个单词来命名,这样可以方便于其它项目里复用。

为什么?

  • 组件是通过组件名来调用的。所以组件名必须简短、富有含义并且具有可读性。

如何做?

<!-- 推荐 -->
<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> <!-- 与自定义元素规范不兼容 -->

组件命名规则

组件的命名需遵从以下原则:

  1. vue 文件代表着页面的名字
  2. 放在模块文件夹之下
  3. 只有一个文件的情况下不会出现文件夹,而是直接放在目录下面,如 Login Home
  4. 尽量是名词
  5. 大写开头,开头的单词就是所属模块名字
CarDetail.vue
CarEdit.vue
CarList.vue
  1. 简短,2~3个单词
  2. 常用结尾单词有:
**Detail.vue
***Edit.vue
***List.vue
***Info.vue
***Report.vue
  1. 以 Item 结尾的代表着组件
CarListItem.vue
CarInfoItem.vue

这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。

基础组件名

  • 基础组件名

应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 BaseAppV

好例子

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue

单例组件名

  • 单例组件名

只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。

//好例子

components/
|- TheHeading.vue
|- TheSidebar.vue

紧密耦合的组件名

  • 紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。

//好例子

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue

组件名中的单词顺序

  • 组件名中的单词顺序

组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。

//好例子

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

组件文件夹命名规则

  • 文件夹命名

  1. 文件夹代表着模块的名字
  2. 由名词组成
car、order、cart
  1. 单词只能有一个
good: car、order、cart

bad: carInfo、carpage
  1. 尽量是名词
good: car

bad: greet、good
  1. 以小写开头
good: car

bad: Car

method方法

methods方法命名规则

  1. 动宾短语
//good:

jumpPage、openCarInfoDialog

//bad:

go、nextPage、show、open、login
  1. 尽量使用常用单词开头
set、get、open、close、jump
  1. 小驼峰命名
good: getListData
bad: get_list_data、getlistData

组件结构化

按照一定的结构组织,使得组件便于理解。

为什么?

  • 导出一个清晰、组织有序的组件,使得代码易于阅读和理解。同时也便于标准化。
  • 按首字母排序 properties、data、computed、watches 和 methods 使得这些对象内的属性便于查找。
  • 合理组织,使得组件易于阅读。(name; extends; props, data 和 computed; components; watch 和 methods; lifecycle methods 等)。
  • 使用 name 属性。借助于 vue devtools 可以让你更方便的测试。
  • 合理的 CSS 结构,如 BEMrscss - 详情?
  • 使用单文件 .vue 文件格式来组件代码。

怎么做?

组件结构化

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

<script type="text/javascript">
  export default {
    // 不要忘记了 name 属性
    name: 'RangeSlider',
    // 使用组件 mixins 共享通用功能
    mixins: [],
    // 使用其它组件
    components: {},    
    // 组成新的组件
    extends: {},
    // 组件属性、变量
    props: {
      bar: {}, // 按字母顺序
      foo: {},
      fooBar: {},
    },
    // 变量
    data() {
      return {}
    },
    creted () {},
    mounted () {},
    computed: {},
    // 使用其它组件
    components: {},
    // 方法
    watch: {},
    methods: {},
    // 生命周期函数
    beforeCreate() {},
    mounted() {}
  };
</script>

<style scoped>
  .Ranger__Wrapper {
   <!-- ... -->
  }
</style>

组件事件命名规则

Vue.js 提供的处理函数和表达式都是绑定在 ViewModel 上的,组件的每一个事件都应该按照一个好的命名规范来,这样可以避免不少的开发问题,具体可见如下 为什么。

为什么?

  • 开发者可以随意给事件命名,即使是原生事件的名字,这样会带来迷惑性。
  • 过于宽松的事件命名可能与 DOM 模板不兼容

怎么做?

  • 事件名也使用连字符命名。
  • 一个事件的名字对应组件外的一组意义操作,加上前缀on-,如:
    on-upload-success、on-upload-error 、on- dropzone-upload-success、on-dropzone-upload-error
  • 事件命名应该以动词(如 client-api-load) 或是 名词(如 drive-upload-success)结尾。(出处

v-for与v-if

为 v-for 设置键值

总是用 key 配合 v-for

// 好例子

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

在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。

详解

假设你有一个待办事项列表:

data: function () {
  return {
    todos: [
      {
        id: 1,
        text: '学习使用 v-for'
      },
      {
        id: 2,
        text: '学习使用 key'
      }
    ]
  }
}

然后你把它们按照字母顺序排序。在更新 DOM 的时候,Vue 将会优化渲染把可能的 DOM 变动降到最低。即可能删掉第一个待办事项元素,然后把它重新加回到列表的最末尾。

这里的问题在于,不要删除仍然会留在 DOM 中的元素。比如你想使用 <transition-group> 给列表加过渡动画,或想在被渲染元素是 <input> 时保持聚焦。在这些情况下,为每一个项目添加一个唯一的键值 (比如 :key="todo.id") 将会让 Vue 知道如何使行为更容易预测。

根据我们的经验,最好始终添加一个唯一的键值,以便你和你的团队永远不必担心这些极端情况。也在少数对性能有严格要求的情况下,为了避免对象固化,你可以刻意做一些非常规的处理。

// 反例

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

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

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

//好例子

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

一般我们在两种常见的情况下会倾向于这样做:

  • 为了过滤一个列表中的项目 (比如 v-for="user in users" v-if="user.isActive")。在这种情形下,请将 users 替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。
  • 为了避免渲染本应该被隐藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。这种情形下,请将 v-if 移动至容器元素上 (比如 ul, ol)。

详解

当 Vue 处理指令时,v-forv-if 具有更高的优先级,所以这个模板:

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

将会经过如下运算:

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

因此哪怕我们只渲染出一小部分用户的元素,也得在每次重渲染的时候遍历整个列表,不论活跃用户是否发生了变化。
通过将其更换为在如下的一个计算属性上遍历:

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>

我们将会获得如下好处:

  • 过滤后的列表会在 users 数组发生相关变化时才被重新运算,过滤更高效。
  • 使用 v-for="user in activeUsers" 之后,我们在渲染的时候遍历活跃用户,渲染更高效。
  • 解藕渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。

为了获得同样的好处,我们也可以把:

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

更新为:

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

通过将 v-if 移动到容器元素,我们不会再对列表中的每个用户检查 shouldShowUsers。取而代之的是,我们只检查它一次,且不会在 shouldShowUsers 为否的时候运算 v-for

Prop

Prop命名规则

在声明 prop 的时候,其命名应该始终使用 camelCase(小驼峰)。

//好例子


props: {
 greetingText: String
}

WelcomeMessage greeting-text="hi"/>

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

//反例

props: {
 'greeting-text': String
}

WelcomeMessage greetingText="hi"/>

Prop定义

Prop 定义应该尽量详细。在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。

详解

细致的 prop 定义有两个好处:

  • 它们写明了组件的 API,所以很容易看懂组件的用法;
  • 在开发环境下,如果向一个组件提供格式不正确的 prop,Vue 将会告警,以帮助你捕获潜在的错误来源。
//好例子

props: {
  status: String
}

// 更好的做法!
props: {
  status: {
    type: String,
    required: true,
    validator: function (value) {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].indexOf(value) !== -1
    }
  }
}

避免 this.$parent

Vue.js 支持组件嵌套,并且子组件可访问父组件的上下文。访问组件之外的上下文违反了基于模块开发第一原则。因此你应该尽量避免使用 this.$parent

为什么?

  • 组件必须相互保持独立,Vue 组件也是。如果组件需要访问其父层的上下文就违反了该原则。
  • 如果一个组件需要访问其父组件的上下文,那么该组件将不能在其它上下文中复用。

怎么做?

  • 通过 props 将值传递给子组件。
  • 通过 props 传递回调函数给子组件来达到调用父组件方法的目的。
  • 通过在子组件触发事件来通知父组件。

谨慎使用 this.$refs

Vue.js 支持通过 ref 属性来访问其它组件和 HTML 元素。并通过 this.$refs 可以得到组件或 HTML 元素的上下文。在大多数情况下,通过 this.$refs来访问其它组件的上下文是可以避免的。在使用的的时候你需要注意避免调用了不恰当的组件 API,所以应该尽量避免使用 this.$refs

为什么?

  • 组件必须是保持独立的,如果一个组件的 API 不能够提供所需的功能,那么这个组件在设计、实现上是有问题的。
  • 组件的属性和事件必须足够的给大多数的组件使用。

怎么做?

  • 提供良好的组件 API。
  • 总是关注于组件本身的目的。
  • 拒绝定制代码。如果你在一个通用的组件内部编写特定需求的代码,那么代表这个组件的 API 不够通用,或者你可能需要一个新的组件来应对该需求。
  • 检查所有的 props 是否有缺失的,如果有提一个 issue 或是完善这个组件。
  • 检查所有的事件。子组件向父组件通信一般是通过事件来实现的,但是大多数的开发者更多的关注于 props 从忽视了这点。
  • Props向下传递,事件向上传递!。以此为目标升级你的组件,提供良好的 API 和 独立性。
  • 当遇到 props 和 events 难以实现的功能时,通过 this.$refs来实现。
  • 当需要操作 DOM 无法通过指令来做的时候可使用 this.$ref 而不是 JQuerydocument.getElement*document.queryElement
<!-- 推荐,并未使用 this.$refs -->
<range :max="max"
       :min="min"
       :step="1"     
       @current-value="currentValue"
></range>
<!-- 使用 this.$refs 的适用情况-->
<modal ref="basicModal">
  <h4>Basic Modal</h4>
  <button class="primary" @click="$refs.basicModal.hide()">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>
<!-- 如果可通过 emited 来做则避免通过 this.$refs 直接访问 -->
<template>
  <range :max="max"
         :min="min"
         :step="1"
          ref="range"
></range>
</template>

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

隐性的父子组件通信

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

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

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

好例子

Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: `
    <input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    >
  `
})

Vue.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  template: `
    <span>
      {{ todo.text }}
      <button @click="$emit('delete')">
        X
      </button>
    </span>
  `
})

元素

元素特性的顺序

  1. is
  2. v-for
  3. v-if
  4. v-else-if
  5. v-else
  6. v-show
  7. v-cloak
  8. v-pre
  9. v-once
  10. id
  11. ref
  12. key
  13. slot
  14. v-model
  15. v-on
  16. v-html
  17. v-text

详解

  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. 唯一的特性 (需要唯一值的特性)
    • ref
    • key
    • slot
  7. 双向绑定 (把绑定和事件结合起来)
    • v-model
  8. 其它特性 (所有普通的绑定或未绑定的特性)
  9. 事件 (组件事件监听器)
    • v-on
  10. 内容 (覆写元素的内容)
*   `v-html`
*   `v-text`

多个特性的元素摆放规则

多个特性的元素应该分多行撰写,每个特性一行。
在 JavaScript 中,用多行分隔对象的多个属性是很常见的最佳实践,因为这样更易读。模板和 JSX 值得我们做相同的考虑。

//反例

<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
//好例子
<img
  src="https://vuejs.org/images/logo.png"
  alt="Vue Logo"
>
<MyComponent
  foo="a"
  bar="b"
  baz="c"
/>

单文件组件的顶级元素的顺序

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

简化代码

模板中简单的表达式

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。

复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。

   //反例
   
   {{
     fullName.split(' ').map(function (word) {
       return word[0].toUpperCase() + word.slice(1)
     }).join(' ')
   }}
//好例子

// 在模板中 
{{ normalizedFullName }}

// 复杂表达式已经移入一个计算属性
computed: {
  normalizedFullName: function () {
    return this.fullName.split(' ').map(function (word) {
      return word[0].toUpperCase() + word.slice(1)
    }).join(' ')
  }
}

简单的计算属性

应该把复杂计算属性分割为尽可能多的更简单的属性。

//好例子

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

详解

更简单、命名得当的计算属性是这样的:

  • 易于测试

    当每个计算属性都包含一个非常简单且很少依赖的表达式时,撰写测试以确保其正确工作就会更加容易。

  • 易于阅读

    简化计算属性要求你为每一个值都起一个描述性的名称,即便它不可复用。这使得其他开发者 (以及未来的你) 更容易专注在他们关心的代码上并搞清楚发生了什么。

  • 更好的“拥抱变化”

    任何能够命名的值都可能用在视图上。举个例子,我们可能打算展示一个信息,告诉用户他们存了多少钱;也可能打算计算税费,但是可能会分开展现,而不是作为总价的一部分。

    小的、专注的计算属性减少了信息使用时的假设性限制,所以需求变更时也用不着那么多重构了。

//反例

computed: {
  price: function () {
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}

指令缩写

指令缩写 (用 : 表示 v-bind: 和用 @ 表示 v-on:) 。

//例子

<input
  @input="onInput"
  @focus="onFocus"
>
<input
  v-on:input="onInput"
  v-on:focus="onFocus"
>

文件引用路径

css的文件引用路径如下,用“~@”替换之前的"../../":

<style lang="less">
@import '~@/styles/common.less';
@import '~@/styles/table.less';
</style>

vue组件引用路径如下,用“@”直接引用src目录下的文件

import ajaxTree from '@/components/tree/ajaxTree'
import VmTable from '@/components/table/vm-table'

其他注意

组件数据

组件的 data 必须是一个函数。
当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。

//好例子

// In a .vue file
export default {
  data () {
    return {
      foo: 'bar'
    }
  }
}

将 this 赋值给 component 变量

在 Vue.js 组件上下文中,this指向了组件实例。因此当你切换到了不同的上下文时,要确保 this 指向一个可用的 component 变量。
换句话说,如果你正在使用 ES6 的话,就不要再编写 var self = this; 这样的代码了,您可以安全地使用 Vue 组件。

为什么?

  • 使用 ES6,就不再需要将 this 保存到一个变量中了。
  • 一般来说,当你使用箭头函数时,会保留 this 的作用域。(译者注:箭头函数没有它自己的 this 值,箭头函数内的 this 值继承自外围作用域。)
  • 如果你没有使用 ES6,当然也就不会使用 箭头函数 啦,那你必须将 “this” 保存到到某个变量中。这是唯一的例外。
  • 如果必须要使用的地方,定义为var _this = this

怎么做?

<script type="text/javascript">
export default {
  methods: {
    hello() {
      return 'hello';
    },
    printHello() {
      console.log(this.hello());
    },
  },
};
</script>

<!-- 避免 -->
<script type="text/javascript">
export default {
  methods: {
    hello() {
      return 'hello';
    },
    printHello() {
      const self = this; // 没有必要
      console.log(self.hello());
    },
  },
};
</script>

对组件文件进行代码校验

代码校验可以保持代码的统一性以及追踪语法错误。.vue 文件可以通过使用 eslint-plugin-html插件来校验代码。你可以通过 vue-cli 来开始你的项目,vue-cli 默认会开启代码校验功能。

为什么?

  • 保证所有的开发者使用同样的编码规范。
  • 更早的感知到语法错误。

怎么做?

为了校验工具能够校验 *.vue文件,你需要将代码编写在 <script>标签中,并使组件表达式简单化,因为校验工具无法理解行内表达式,配置校验工具可以访问全局变量 vue 和组件的 props

ESLint

ESLint 需要通过 ESLint HTML 插件来抽取组件中的代码。

通过 .eslintrc 文件来配置 ESlint,这样 IDE 可以更好的理解校验配置项:

{
  "extends": "eslint:recommended",
  "plugins": ["html"],
  "env": {
    "browser": true
  },
  "globals": {
    "opts": true,
    "vue": true
  }
}

运行 ESLint

eslint src/**/*.vue

JSHint

JSHint 可以解析 HTML(使用 --extra-ext命令参数)和抽取代码(使用 --extract=auto命令参数)。
通过 .jshintrc 文件来配置 ESlint,这样 IDE 可以更好的理解校验配置项。

{
  "browser": true,
  "predef": ["opts", "vue"]
}

运行 JSHint

jshint --config modules/.jshintrc --extra-ext=html --extract=auto modules/

注:JSHint 不接受 vue 扩展名的文件,只支持 html

尽可能使用 mixins

为什么?

Mixins 封装可重用的代码,避免了重复。如果两个组件共享有相同的功能,则可以使用 mixin。通过 mixin,你可以专注于单个组件的任务和抽象的通用代码。这有助于更好地维护你的应用程序。

怎么做?

假设你有一个移动端和桌面端的菜单组件,它们共享一些功能。我们可以抽象出这两个组件的核心功能到一个 mixin 中,例如:

const MenuMixin = {
  data () {
    return {
      language: 'EN'
    }
  },

  methods: {
    changeLanguage () {
      if (this.language === 'DE') this.$set(this, 'language', 'EN')
      if (this.language === 'EN') this.$set(this, 'language', 'DE')
    }
  }
}

export default MenuMixin

要使用 mixin,只需将其导入到两个组件中(我只展示移动组件)。

<template>
  <ul class="mobile">
    <li @click="changeLanguage">Change language</li>
  </ul>
</template>

<script>
  import MenuMixin from './MenuMixin'

  export default {
    mixins: [MenuMixin]
  }
</script>

非 Flux 的全局状态管理

应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。
通过 this.$root 和/或全局事件总线管理状态在很多简单的情况下都是很方便的,但是并不适用于绝大多数的应用。Vuex 提供的不仅是一个管理状态的中心区域,还是组织、追踪和调试状态变更的好工具。

//反例

// main.js
new Vue({
  data: {
    todos: []
  },
  created: function () {
    this.$on('remove-todo', this.removeTodo)
  },
  methods: {
    removeTodo: function (todo) {
      var todoIdToRemove = todo.id
      this.todos = this.todos.filter(function (todo) {
        return todo.id !== todoIdToRemove
      })
    }
  }
})
//好例子

// store/modules/todos.js
export default {
  state: {
    list: []
  },
  mutations: {
    REMOVE_TODO (state, todoId) {
      state.list = state.list.filter(todo => todo.id !== todoId)
    }
  },
  actions: {
    removeTodo ({ commit, state }, todo) {
      commit('REMOVE_TODO', todo.id)
    }
  }
}
<!-- TodoItem.vue -->
<template>
  <span>
    {{ todo.text }}
    <button @click="removeTodo(todo)">
      X
    </button>
  </span>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  methods: mapActions(['removeTodo'])
}
</script>

只在需要时创建组件

为什么?

Vue.js 是一个基于组件的框架。如果你不知道何时创建组件可能会导致以下问题:

  • 如果组件太大, 可能很难重用和维护;
  • 如果组件太小,你的项目就会(因为深层次的嵌套而)被淹没,也更难使组件间通信;

怎么做?

  • 始终记住为你的项目需求构建你的组件,但是你也应该尝试想到它们能够从中脱颖而出(独立于项目之外)。如果它们能够在你项目之外工作,就像一个库那样,就会使得它们更加健壮和一致。
  • 尽可能早地构建你的组件总是更好的,因为这样使得你可以在一个已经存在和稳定的组件上构建你的组件间通信(props & events)。

规则

  • 首先,尽可能早地尝试构建出诸如模态框、提示框、工具条、菜单、头部等这些明显的(通用型)组件。总之,你知道的这些组件以后一定会在当前页面或者是全局范围内需要。
  • 第二,在每一个新的开发项目中,对于一整个页面或者其中的一部分,在进行开发前先尝试思考一下。如果你认为它有一部分应该是一个组件,那么就创建它吧。
  • 最后,如果你不确定,那就不要。避免那些“以后可能会有用”的组件污染你的项目。它们可能会永远的只是(静静地)待在那里,这一点也不聪明。注意,一旦你意识到应该这么做,最好是就把它打破,以避免与项目的其他部分构成兼容性和复杂性。

最后

原文章来源地址: https://www.kancloud.cn/donaf/vue/633892

posted @ 2020-12-27 15:40  DAmarkday  阅读(1676)  评论(0编辑  收藏  举报