本书的最后一章,聊下Vue.js开发项目的最佳实践以及风格规范,
为列表渲染设置属性Key
key这个特殊属性主要用在Vue.js的虚拟DOM算法中,在对比新旧虚拟节点时辨识虚拟节点。
在v-if/v-if-else/v-else 中使用key
如果一组v-if+v-else的元素类型相同,最好使用属性key(比如两个
元素)// 不好的做法
<div v-if="error">
错误:{{ error }}
</div>
<div v-else>
{{ results }}
</div>
// 好的做法
<div v-if="error" key="search-status">
错误:{{ error }}
</div>
<div v-else key="search-results">
{{ results }}
</div>
路由切换组件不变
当页面切换到同一个路由但不同参数的地址时,组件的生命周期钩子并不会重新渲染
const routes = [
{
path:'/detail/:id',
name:'detail',
component:Detail
}
]
当我们从路由/detial/1切换到detail/2时,组件是不会发生任何变化的。这是因为vue-router会识别出两个路由使用的是同一个组件从而进行复用,并不会重新创建组件,因此组件的生命周期钩子自然也不会触发。
路由导航守卫beforeRouterUpdate
vue-router 提供了导航守卫beforeRouterUpdate,该守卫在当前路由改变且组件被复用时候调用,所以可以在组件内定义路由导航守卫来解决这个问题
观察$route对象的变化
通过watch可以监听到路由对象发生的变化,从而对路由变化作出响应
const User = {
template:'...',
watch:{
'$route'(to,from){
// 对路由变化作出响应
}
}
}
这种方式也可以解决上述问题,但是代价是组件内多了一个watch,这会带来依赖追踪的内存开销
这种做法应该可以更准确的去监听参数的变化
const User = {
template:'...'
watch:{
'$route.query.id'(){
// 请求个人描述信息
'$route.query.page'(){
//请求列表
为router-view 组件添加属性key
这种做法非常取巧,非常’暴力‘,但非常有效。
<router-view :key="$router.fullPath"></router-view>
这种方式每次切换路由组件都会被销魂并且重新创建
为所有路由统一添加query
如果是统一的query,那么我们每次在加上参数会麻烦。
在全局统一配置一个基础的query
使用全局守卫beforeEach
事实上,全局守卫beforeEach 并不具备修改query的能力,但可以在其中使用next方法来中断当前导航,并切换到新导航,添加一些新query方法 如果只这样会出现无限循环,因为会一直被全局守卫beforeEach拦截
const query = { referer:'hao360cm'}
router.beforeEach((to,from,next)=>{
to.query.referer?next():next({...to,query:{...to.query,...query}})
使用函数劫持
这种方式的原理是:通过拦截router.history.transitionTo方法,在vue-router内部再切换路由之前将参数添加到query中
const query = {referer:'hoa360cn'}
const transitiosnTo = router.history.transitionTo
router.history.transitionTo = function(location,onComplete,onAbort){
location = typeof location === 'object'?{...location,query:{...location.query,...query}}:{path:location,query}
transitionTo.call(router.history,location,onComplete,onAbort)
}
但修改vue-router内部方法实现目的,也是很危险的操作
区分Vuex 与props的使用边界
组件何时从Vuex的Store获取状态,何时使用props接收父组件传递进来的状态 通用组件要定义细致的prop,并且竟可能详细,至少需要指定其类型。
- 写明了组件的API,所有很容易看懂组件的用法;
- 在开发环境下,如果向一个组件提供格式不正确的prop,Vue.js将会在控制台发出警告,帮助我们捕获潜在的错误来源
避免v-if 和 v-for 一起使用
Vue.js官方强烈建议不要把v-if和v-for同时用在用一个元素上
<ul>
<li v-for="user in users" v-if="user.isActive" :key="user.id">
{{ user.name }}
</li>
</ul>
<!-- 可以换为计算属性过滤过的列表 -->
<script>
computed:{
activeUsers:function(){
return this.users.filter(function(user){
return user.isActive
})
}
}
</script>
<!-- 模板更改为 -->
<ul>
<li v-for="user in activeUsers" ::key="user.id">
{{ user.name }}
</li>
</ul>
<!-- 对于第二种情况 -->
<ul>
<li v-for="user in users" v-if="shouldShowUsers">
{{ user.name}}
</li>
</ul>
<!-- 更新为 -->
<ul v-if=”shouldShowUsers“>
<li v-for="user in users"> {{ user.name}}</li>
</ul>
为组件样式设置作用域
CSS 的规则都是全局的,任何一个组件的样式规则都对整个页面有效。
在Vue.js中,可以通过scoped 特性或或者CSS Modules(一个基于class的类似BEM的策略)来设置组件样式作用域
<template>
<button class="btn btn-close">X</button>
</template>
// 使用scoped特性
<style scoped>
.btn{
border:none;
border-radius: 2px;
}
</style>
<template>
<button :class="[$style.button,$style.buttonClose]">X</button>
</template>
// 使用CSSModules
<style module>
.button{
border:none
}
.buttonClose{
background-color: red;
}
</style>
避免在scoped中使用元素选择器
在scoded样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的
为了给样式设置作用域,Vue.js会为元素添加一个独一无二的特性,例如data-v-f3f3eg9 如果使用元素选择器如(button[data-v-f3f3eg9])
避免隐性的父子组件通信
我们应该优先通过prop和事件进行父子组件之间的通信,而不是使用this.$parent或改变prop。
一个理想的Vue.js应用是 ”prop向下传递,事件向上传递 “
prop的变更或this.$parent 能够简化连个深度耦合的组件 但这种做法不是很好
单文件组件如何命名
单文件组件的文件名的大小写
始终是单词首字母大写(PascalCase),或者始终是横线连接的(kebab-case)
// 不好的
mycomponent.vue
myComponent.vue
// 好的
MyComponent.vue
my-component.vue
基础组件名
应用特定样式和约定的基础组件(也就是展示类的,无逻辑的或无状态的组件)应该全部以一个特定的前缀开头,比如Base,App,或者V。这些组件可以为你的应用奠定一直的基础样式和行为
// 不好的例子
MyButton.vue
VueTable.vue
Icon.vue
// 好的例子
BaseButton.vue
BaseTable.vue
BaseIcon.vue
AppButton.vue
AppTable.vue
AppIcon.vue
VButton.vue
VTable.vue
VIcon.vue
- 方便排序,应用的基础组件都会列在一起
- 也可以方便引入,相同的前缀可以用webapck这样工作引入对应的组件
var requireComponent = ruquire.context("./src",true,/^Base[A-Z])
requireComponent.keys().forEach(funciton()fileName){
var baseComponentConfig = requireComponent(fileName)
baseComponentConfig = baseComponentConfig.default || baseComponentConfig
var baseComponentName = baseComponentConfig.name || (fileName.replace(/^.+\//,'').replace(/\.\w+$/,''))
Vue.component(baseComponentName,baseComponentConfig)
}
单例组件名
这些组件永远不接受prop
TheHeadeing.vue
TheSidebar.vue
紧密耦合的组件名
和组件紧密耦合的子组件应该以父组件作为前缀命名
通常,我们可以通过父组件命名的目录中嵌套子组件解决这个问题
components/
TodoList/
Item/
index.vue
Button.vue
index.vue
或者:
component/
TodoList/
Item/
Button.vue
Item.vue
TodoList.vue
- 这样导致许多文件名字相同,
- 多层嵌套也增加了子目录结构,查找所花的时间
这里我们可以这样做
components/
TodoList.vue
TodeListItem.vue
TodeListItemButton.vue
components/
SearchSidebar.vue
SearchSidebarNavigation.vue
非常不好的例子
components/
TodoList.vue
TodoItem.vue
TodoGutton.vue
components/
SearchSidebar.vue
NavigationForSearchSidebar.vue
完整单词的组件名
SdSettings.vue
UProfOpts.vue
推荐的例子
StudentDashbordSettings.vue
UserProfileOptions.vue
组件名为多个单词
组件名应该始终由多个单词组成,但是根组件App除外。这样作可以避免与现在以及未来的HTML元素冲突,因为所有的HTML元素名称都是单个单词的
不好例子
Vue.component('todo',{})
export default{ name:'Todo' }
推荐的例子:
Vue.component('todo-item',{})
export default{ name:'TodoItem' }
模板中的组件名大小写
在单文件组件和字符串模板中的组件名应该总是单词首字母大写,但是在DOM模板中总是横线连接的
// 在单文件组件和字符串模板中
<MyComponent/>
// 在DOM模板中
<my-component></my-component>
或者:
// 在所有敌方
<my-component></my-component>
prop 名的大小写
不好的例子
props:{
'greeting-text':String
}
<welcome-message gereetingText = "hi"/>
推荐的例子
props:{
'greetingText':String
}
<welcome-message gereeting-text = "hi"/>
组件/实例的选项的顺序
- name
- components directives filters
- extends mixins
- props/propsData
- data computed
- watch 生命周期钩子
- methods
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!