1、安装element
npm i element-ui -S
2、引入
在main.js写入一下内容
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; Vue.use(ElementUI); new Vue({ el: '#app', render: h => h(App) });
3、按需引入
借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component:
npm install babel-plugin-component -D
然后,将 .babelrc 修改为:
{ "presets": [["es2015", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
4.main.js文件
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue'; import App from './App'; import 'element-ui/lib/theme-chalk/index.css'; import router from './router'; import ElementUI from 'element-ui'; Vue.config.productionTip = false Vue.use(ElementUI) /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
app.vue(添加导航条,及页面布局)
<template> <el-container> <el-header> <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect"> <el-menu-item index="1">项目搜索</el-menu-item> <el-menu-item index="2">简介</el-menu-item> <el-menu-item index="3">消息中心</el-menu-item> <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item> </el-menu> </el-header> <el-main>Main</el-main> <el-footer>Footer</el-footer> </el-container> </template> <script> export default{ name:'App', data(){ return{ msg:'vue', activeIndex:"1", // activeIndex2:"1", }; }, methods:{ handleSelect(key,keyPath){ console.log(key,keyPath) } } } </script> <style scoped> .el-header, .el-footer { background-color: #B3C0D1; color: #333; text-align: center; line-height: 60px; } .el-main { background-color: #E9EEF3; color: #333; text-align: center; line-height: 160px; } </style>
构建父子组件通讯
父子组件是单向数据流的,父级prop的更新会向下流动到子组件中,但反过来则不行。
注意:每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值。
表明不应该在一个子组件内部改变prop。否则会报错
组件基础
因为组件是可复用的 Vue 实例,所以它们与 new Vue
接收相同的选项,
例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
组件复用
你可以将组件进行任意次数的
复用:
<div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
注意当点击按钮时,每个组件都会各自独立维护它的 count
。因为你每用一次组件,就会有一个它的新实例被创建
data
必须是一个函数
当我们定义这个 <button-counter>
组件时,你可能会发现它的 data
并不是像这样直接提供一个对象:
data: { count: 0 }
而是:一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () { return { count: 0 } }
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织:
例如:可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。
至此,我们的组件都只是通过 Vue.component
全局注册的:
Vue.component('my-component-name', { // ... options ... })
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue
) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
优先级 A 的规则:必要的 (规避错误)
组件名规范
*组件名为多个单词,根组件App除外。
好处:这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
例如:
好: Vue.component('todo-item', { // ... }) export default { name: 'TodoItem', // ... }
反例:
Vue.component('todo', {
// ...
})
export default {
name: 'Todo',
// ...
}
组件数据
组件数据data必须是一个函数
当在组件中使用 data
属性的时候 (除了 new Vue
外的任何地方),它的值必须是返回一个对象的函数。
原因:
当 data 的值是一个对象时,它会在这个组件的所有实例之间共享。想象一下,假如一个 TodoList
组件的数据是这样的: data: { listTitle: '', todos: [] } 我们可能希望重用这个组件,允许用户维护多个列表 (比如分为购物、心愿单、日常事务等)。
这时就会产生问题。因为每个组件的实例都引用了相同的数据对象,更改其中一个列表的标题就会改变其它
每一个列表的标题。增删改一个待办事项的时候也是如此。 取而代之的是,我们希望每个组件实例都管理其自己的数据。为了做到这一点,每个实例必须生成一个独立的数据对象。在 JavaScript 中,在一个函数中返回这个对象就可以了: data: function () { return { listTitle: '', todos: [] } }
样本 反例 Vue.component('some-comp', { data: { foo: 'bar' } }) export default { data: { foo: 'bar' } } 好例 Vue.component('some-comp', { data: function () { return { foo: 'bar' } } }) // In a .vue file export default { data () { return { foo: 'bar' } } } // 在一个 Vue 的根实例上直接使用对象是可以的, // 因为只存在一个这样的实例。 new Vue({ data: { foo: 'bar' } })
Prop定义
Prop定义应该尽量详细
在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。
细致的 prop 定义有两个好处:
它们写明了组件的 API,所以很容易看懂组件的用法;
在开发环境下,如果向一个组件提供格式不正确的 prop,Vue 将会告警,以帮助你捕获潜在的错误来源。
样本: 反例: // 这样做只有开发原型系统时可以接受 props: ['status'] 好例子 props: { status: String } // 更好的做法! props: { status: { type: String, required: true, validator: function (value) { return [ 'syncing', 'synced', 'version-conflict', 'error' ].indexOf(value) !== -1 } } }
为v-for设置键值
总是用 key
配合 v-for
。
在组件上总是必须用 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> 好例 <ul> <li v-for="todo in todos" :key="todo.id" > {{ todo.text }} </li> </ul>
避免 v-if
和 v-for
用在一起
永远不要把 v-if
和 v-for
同时用在同一个元素上。
一般我们在两种常见的情况下会倾向于这样做:
-
为了过滤一个列表中的项目 (比如
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-for 比 v-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。
样例: 反例: <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> 好例: <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>
为组件样式设置作用域(scoped)
对于应用来说,顶级 App
组件和布局组件中的样式可以是全局的,但是其它所有组件都应该是有作用域的。
这条规则只和单文件组件有关。你不一定要使用 scoped
特性。设置作用域也可以通过 CSS Modules,
那是一个基于 class 的类似 BEM 的策略,当然你也可以使用其它的库或约定。
不管怎样,对于组件库,我们应该更倾向于选用基于 class 的策略而不是 scoped
特性。
这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。
详解: 如果你和其他开发者一起开发一个大型工程,或有时引入三方 HTML/CSS (比如来自 Auth0),
设置一致的作用域会确保你的样式只会运用在它们想要作用的组件上。 不止要使用 scoped 特性,使用唯一的 class 名可以帮你确保那些三方库的 CSS 不会运用在你自己的 HTML 上。
比如许多工程都使用了 button、btn 或 icon class 名,所以即便你不使用类似 BEM 的策略,
添加一个 app 专属或组件专属的前缀 (比如 ButtonClose-icon) 也可以提供很多保护。
样例: 反例: <template> <button class="btn btn-close">X</button> </template> <style> .btn-close { background-color: red; } </style> ------------------------------------------------------------------------
好例
1 <template> <button class="button button-close">X</button> </template> <!-- 使用 `scoped` 特性 --> <style scoped> .button { border: none; border-radius: 2px; } .button-close { background-color: red; } </style>
2 <template> <button :class="[$style.button, $style.buttonClose]">X</button> </template> <!-- 使用 CSS Modules --> <style module> .button { border: none; border-radius: 2px; } .buttonClose { background-color: red; } </style>
3 <template> <button class="c-Button c-Button--close">X</button> </template> <!-- 使用 BEM 约定 --> <style> .c-Button { border: none; border-radius: 2px; } .c-Button--close { background-color: red; } </style>
私有属性名($_)
在插件、混入等扩展中始终为自定义的私有属性使用 $_
前缀。
并附带一个命名空间以回避和其它作者的冲突 (比如 $_yourPluginName_
)。
详解:
Vue 使用 _ 前缀来定义其自身的私有属性,所以使用相同的前缀 (比如 _update) 有覆写实例属性的风险。
即便你检查确认 Vue 当前版本没有用到这个属性名,也不能保证和将来的版本没有冲突。
对于 $ 前缀来说,其在 Vue 生态系统中的目的是暴露给用户的一个特殊的实例属性,所以把它用于私有属性并不合适。
不过,我们推荐把这两个前缀结合为 $_,作为一个用户定义的私有属性的约定,以确保不会和 Vue 自身相冲突。
样例 反例 var myGreatMixin = { // ... methods: { update: function () { // ... } } } var myGreatMixin = { // ... methods: { _update: function () { // ... } } } var myGreatMixin = { // ... methods: { $update: function () { // ... } } } var myGreatMixin = { // ... methods: { $_update: function () { // ... } } } 好例子 var myGreatMixin = { // ... methods: { $_myGreatMixin_update: function () { // ... } } }
优先级 B 的规则:强烈推荐 (增强可读性)
组件文件
只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。
反例 Vue.component('TodoList', { // ... }) Vue.component('TodoItem', { // ... }) 好例子 components/ |- TodoList.js |- TodoItem.js components/ |- TodoList.vue |- TodoItem.vue
单文件组件文件的大小写
单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)。
单词大写开头对于代码编辑器的自动补全最为友好,因为这使得我们在 JS(X) 和模板中引用组件的方式尽可能的一致。
然而,混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题,这也是横线连接命名同样完全可取的原因。
反例 components/ |- mycomponent.vue components/ |- myComponent.vue 好例子 components/ |- MyComponent.vue components/ |- my-component.vue
基础组件名
应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头
,比如 Base
、App
或 V
。
详解: 这些组件为你的应用奠定了一致的基础样式和行为。它们可能只包括: HTML 元素 其它基础组件 第三方 UI 组件库 但是它们绝不会包括全局状态 (比如来自 Vuex store)。 它们的名字通常包含所包裹元素的名字 (比如 BaseButton、BaseTable),除非没有现成的对应功能的元素 (比如 BaseIcon)。
如果你为特定的上下文构建类似的组件,那它们几乎总会消费这些组件 (比如 BaseButton 可能会用在 ButtonSubmit 上)。 这样做的几个好处: 当你在编辑器中以字母顺序排序时,你的应用的基础组件会全部列在一起,这样更容易识别。 因为组件名应该始终是多个单词,所以这样做可以避免你在包裹简单组件时随意选择前缀 (比如 MyButton、VueButton)。 因为这些组件会被频繁使用,所以你可能想把它们放到全局而不是在各处分别导入它们。使用相同的前缀可以让 webpack 这样工作: var requireComponent = require.context("./src", true, /^Base[A-Z]/) requireComponent.keys().forEach(function (fileName) { var baseComponentConfig = requireComponent(fileName) baseComponentConfig = baseComponentConfig.default || baseComponentConfig var baseComponentName = baseComponentConfig.name || ( fileName .replace(/^.+//, '') .replace(/.w+$/, '') ) Vue.component(baseComponentName, baseComponentConfig) })
样例 反例 components/ |- MyButton.vue |- VueTable.vue |- Icon.vue 好例子 components/ |- BaseButton.vue |- BaseTable.vue |- BaseIcon.vue components/ |- AppButton.vue |- AppTable.vue |- AppIcon.vue components/ |- VButton.vue |- VTable.vue |- VIcon.vue
单例组件名
只应该拥有单个活跃实例的组件应该以 The
前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。
反例 components/ |- Heading.vue |- MySidebar.vue 好例子 components/ |- TheHeading.vue |- TheSidebar.vue
紧密耦合的组件名
和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。
因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。
详解 你可以试着通过在其父组件命名的目录中嵌套子组件以解决这个问题。比如: components/ |- TodoList/ |- Item/ |- index.vue |- Button.vue |- index.vue 或: components/ |- TodoList/ |- Item/ |- Button.vue |- Item.vue |- TodoList.vue 但是这种方式并不推荐,因为这会导致: 许多文件的名字相同,使得在编辑器中快速切换文件变得困难。 过多嵌套的子目录增加了在编辑器侧边栏中浏览组件所花的时间。
样例
反例 1 components/ |- TodoList.vue |- TodoItem.vue |- TodoButton.vue 2 components/ |- SearchSidebar.vue |- NavigationForSearchSidebar.vue 好例子 1 components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue 2 components/ |- SearchSidebar.vue |- SearchSidebarNavigation.vue
组件名的单词顺序
组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。
“为什么我们给组件命名时不多遵从自然语言呢?” 在自然的英文里,形容词和其它描述语通常都出现在名词之前,否则需要使用连接词。比如: Coffee with milk Soup of the day Visitor to the museum 如果你愿意,你完全可以在组件名里包含这些连接词,但是单词的顺序很重要。 同样要注意在你的应用中所谓的“高级别”是跟语境有关的。比如对于一个带搜索表单的应用来说,它可能包含这样的组件: components/ |- ClearSearchButton.vue |- ExcludeFromSearchInput.vue |- LaunchOnStartupCheckbox.vue |- RunSearchButton.vue |- SearchInput.vue |- TermsCheckbox.vue 你可能注意到了,我们很难看出来哪些组件是针对搜索的。现在我们来根据规则给组件重新命名: components/ |- SearchButtonClear.vue |- SearchButtonRun.vue |- SearchInputExcludeGlob.vue |- SearchInputQuery.vue |- SettingsCheckboxLaunchOnStartup.vue |- SettingsCheckboxTerms.vue 因为编辑器通常会按字母顺序组织文件,所以现在组件之间的重要关系一目了然。 你可能想换成多级目录的方式,把所有的搜索组件放到“search”目录,
把所有的设置组件放到“settings”目录。我们只推荐在非常大型 (如有 100+ 个组件) 的应用下才考虑这么做,因为: 在多级目录间找来找去,要比在单个 components 目录下滚动查找要花费更多的精力。 存在组件重名 (比如存在多个 ButtonDelete 组件) 的时候在编辑器里更难快速定位。 让重构变得更难,因为为一个移动了的组件更新相关引用时,查找/替换通常并不高效。
自闭合组件
在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。
自闭合组件表示它们不仅没有内容,而且刻意没有内容。其不同之处就好像书上的一页白纸对比贴有“本页有意留白”标签的白纸。而且没有了额外的闭合标签,你的代码也更简洁。
不幸的是,HTML 并不支持自闭合的自定义元素——只有官方的“空”元素。所以上述策略仅适用于进入 DOM 之前 Vue 的模板编译器能够触达的地方,然后再产出符合 DOM 规范的 HTML。
反例 <!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent></MyComponent> <!-- 在 DOM 模板中 --> <my-component/> 好例子 <!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component>
模板中组件名大小写
对于绝大多数项目来说,在单文件组件和字符串模板中组件名应该总是 PascalCase 的——但是在 DOM 模板中总是 kebab-case 的。
PascalCase 相比 kebab-case 有一些优势:
- 编辑器可以在模板里自动补全组件名,因为 PascalCase 同样适用于 JavaScript。
<MyComponent>
视觉上比<my-component>
更能够和单个单词的 HTML 元素区别开来,因为前者的不同之处有两个大写字母,后者只有一个横线。- 如果你在模板中使用任何非 Vue 的自定义元素,比如一个 Web Component,PascalCase 确保了你的 Vue 组件在视觉上仍然是易识别的。
不幸的是,由于 HTML 是大小写不敏感的,在 DOM 模板中必须仍使用 kebab-case。
还请注意,如果你已经是 kebab-case 的重度用户,那么与 HTML 保持一致的命名约定且在多个项目中保持相同的大小写规则就可能比上述优势更为重要了。在这些情况下,在所有的地方都使用 kebab-case 同样是可以接受的。
反例 <!-- 在单文件组件和字符串模板中 --> <mycomponent/> <!-- 在单文件组件和字符串模板中 --> <myComponent/> <!-- 在 DOM 模板中 --> <MyComponent></MyComponent> 好例子 <!-- 在单文件组件和字符串模板中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component> 或者 <!-- 在所有地方 --> <my-component></my-component>
JS/JSX 中的组件名大小写
JS/JSX 中的组件名应该始终是 PascalCase 的,尽管在较为简单的应用中只使用 Vue.component
进行全局组件注册时,可以使用 kebab-case 字符串。
详解 在 JavaScript 中,PascalCase 是类和构造函数 (本质上任何可以产生多份不同实例的东西)
的命名约定。Vue 组件也有多份实例,所以同样使用 PascalCase 是有意义的。额外的好处是,
在 JSX (和模板) 里使用 PascalCase 使得代码的读者更容易分辨 Vue 组件和 HTML 元素。 然而,对于只通过 Vue.component 定义全局组件的应用来说,我们推荐 kebab-case 作为替代。
原因是: 全局组件很少被 JavaScript 引用,所以遵守 JavaScript 的命名约定意义不大。 这些应用往往包含许多 DOM 内的模板,这种情况下是必须使用 kebab-case 的。
样例 反例 1 Vue.component('myComponent', { // ... }) 2 import myComponent from './MyComponent.vue' 3 export default { name: 'myComponent', // ... } 4 export default { name: 'my-component', // ... } 好例子 5 Vue.component('MyComponent', { // ... }) 6 Vue.component('my-component', { // ... }) 7 import MyComponent from './MyComponent.vue' 8 export default { name: 'MyComponent', // ... }
完整单词的组件名
组件名应该倾向于完整单词而不是缩写。
编辑器中的自动补全已经让书写长命名的代价非常之低了,而其带来的明确性却是非常宝贵的。不常用的缩写尤其应该避免。
反例 components/ |- SdSettings.vue |- UProfOpts.vue 好例子 components/ |- StudentDashboardSettings.vue |- UserProfileOptions.vue
Prop名大小写
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case。
我们单纯的遵循每个语言的约定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中则是 kebab-case。
反例 js props: { 'greeting-text': String }
html <WelcomeMessage greetingText="hi"/> 好例子 js props: { greetingText: String }
html <WelcomeMessage greeting-text="hi"/> ***html对大小写不敏感
多个特性的元素
多个特性的元素应该分多行撰写,每个特性一行。
在 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" />
模板中的简单的表达式
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
反例 html {{ fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }} 好例子 html <!-- 在模板中 --> {{ normalizedFullName }} js // 复杂表达式已经移入一个计算属性 computed: { normalizedFullName: function () { return this.fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') } }
简单的计算属性
应该把复杂计算属性分割为尽可能多的更简单的属性。
详解
更简单、命名得当的计算属性是这样的:
易于测试
当每个计算属性都包含一个非常简单且很少依赖的表达式时,撰写测试以确保其正确工作就会更加容易。
易于阅读
简化计算属性要求你为每一个值都起一个描述性的名称,即便它不可复用。这使得其他开发者
(以及未来的你) 更容易专注在他们关心的代码上并搞清楚发生了什么。
更好的“拥抱变化”
任何能够命名的值都可能用在视图上。举个例子,我们可能打算展示一个信息,
告诉用户他们存了多少钱;也可能打算计算税费,但是可能会分开展现,而不是作为总价的一部分。
小的、专注的计算属性减少了信息使用时的假设性限制,所以需求变更时也用不着那么多重构了。
样例 反例 js computed: { price: function () { var basePrice = this.manufactureCost / (1 - this.profitMargin) return ( basePrice - basePrice * (this.discountPercent || 0) ) } } 好例子 js computed: { basePrice: function () { return this.manufactureCost / (1 - this.profitMargin) }, discount: function () { return this.basePrice * (this.discountPercent || 0) }, finalPrice: function () { return this.basePrice - this.discount } }
带引号的特性值
非空 HTML 特性值应该始终带引号 (单引号或双引号,选你 JS 里不用的那个)。
在 HTML 中不带空格的特性值是可以没有引号的,但这样做常常导致带空格的特征值被回避,导致其可读性变差。
反例html <input type=text> <AppSidebar :style={sidebarWidth+'px'}> 好例子 html <input type="text"> <AppSidebar :style="{ sidebarWidth + 'px' }">
指令缩写
指令缩写 (用 :
表示 v-bind:
和用 @
表示 v-on:
) 应该要么都用要么都不用。
反例 <input v-bind:value="newTodoText" :placeholder="newTodoInstructions" > <input v-on:input="onInput" @focus="onFocus" > 好例子 <input :value="newTodoText" :placeholder="newTodoInstructions" > <input v-bind:value="newTodoText" v-bind:placeholder="newTodoInstructions" > <input @input="onInput" @focus="onFocus" > <input v-on:input="onInput" v-on:focus="onFocus" >
推荐使用
组件/实例选项中的空行
你可能想在多个属性之间增加一个空行,特别是在这些选项一屏放不下,需要滚动才能都看到的时候。
当你的组件开始觉得密集或难以阅读时,在多个属性之间添加空行可以让其变得容易。在一些诸如 Vim 的编辑器里,这样格式化后的选项还能通过键盘被快速导航。
props: { value: { type: String, required: true }, focused: { type: Boolean, default: false }, label: String, icon: String }, computed: { formattedValue: function () { // ... }, inputClasses: function () { // ... } }
注意:
在 scoped
样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。
反例 <template> <button>X</button> </template> <style scoped> button { background-color: red; } </style> 好例子 <template> <button class="btn btn-close">X</button> </template> <style scoped> .btn-close { background-color: red; } </style>
一个理想的 Vue 应用是 prop 向下传递,事件向上传递的。
全局组件:
注册方式:Vue.component(组件名,{方法})
为js代码,
注意点:全局组件必须写在Vue实例创建之前,才在该根元素下面生效。
<body> <div id="app"> <my-component></my-component> </div> <div id="app1"> <my-component></my-component> </div> <script> new Vue({ el: "#app" }); Vue.component("my-component", { template: "<h1>我是全局组件</h1>" }); new Vue({ el: "#app1" }) </script> </body>
这样只会渲染app1根元素下面的,并不会渲染app根下面的,并且会报错。