vue 编码规范

为列表渲染设置属性key

切忌使用下标作为key,会失去虚拟Dom对比的优化

// v-for:key

// bad
<div v-for = '(item,i) in items' :key = 'i'>
<!--内容-->
</div>

// good
<div v-for = '(item,i) in items' :key = 'item.id'>
<!--内容-->
</div>

在v-if/v-if-else/v-else 中使用key

添加key,对比虚拟Dom时会认为是不同的节点,将旧元素直接移除并在相同位置添加新元素

// bad
<div v-if = 'error'>
{{error}}
</div>
<div v-else>
{{results}}
</div>

// good
<div v-if = 'error' key = 'search-status'>
{{error}}
</div>
<div v-else key = 'search-results'>
{{results}}
</div>

路由切换组件不变

路由的params参数改变不会重新触发组件的生命周期

解决方法

路由导航守卫 beforeRouteUpdate 拉取数据重新渲染视图,vue-router2.2+ 支持,推荐使用,观察 $route对象的变化,添加 watch,增加依赖追踪的内存开销


// bad
const user = {
  template:' ',
  watch:{
    '$route'(to,from){
      //...
    }
  }
}

// good
const user = {
  template:' ',
  watch: {
    '$route.query.id'(to,from){
      //...
    },
    '$route.query.page'(to,from){
      //...
    }
  }
}

为router-view组件添加属性key,利用虚拟dom渲染通过key对比节点的原理,不足之处在于切换路由组件会被销毁并重新创建

<router-view :key = '$route.fullPath'></router-view>

为所有路由统一添加 query

上级路由携带的 query 参数,需要在所有路由中携带,且不影响切换

解决方案

  • 使用全局守卫 beforeEach

// 缺点 全局守卫 beforeEach 会执行两次,且每次切换路由都会切换两次
const query = {refer: 'test'}
router.beforeEach((to,from,next)=>{
 to.query.referer ? next() : next({...to,query,...query})
})

  • 使用函数劫持(推荐使用)

const query = {refer: 'test'};
const transitionTo = router.history.transitionTo
 
router.history.transitionTo = function(location,onComplete,onAbout){
 location = typeof location === 'object' ? {...location,query:{...location.query,...query}} : {path:location,query}
 transitionTo.call(router.history,location,onComplete,onAbout)
}


区分 vuex 和 props 的使用边界

业务组件使用vuex维护状态,方便组件之间通信

通用组件使用 props 以及事件 进行父子组件通信,与业务解耦,在通用组件中定义props 尽可能详细,指定类型

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

推荐的做法

为过滤列表中的项目,可将循环列表替换为一个计算属性,返回过滤后的列表
为避免渲染本该隐藏的列表,可将v-if放到容器组件上

为组件样式设置作用域

通过scoped特性或者css Modules设置样式作用域,组件库使用class策略,使用容易理解的class名称且没有太高的选择器优先级,不容易导致冲突


// good
<style scoped>
.button{
 border:none
}
</style>
 
// good
<style module>
.button{
 border:none

}
</style>

避免在scoped中使用元素选择器

在scpoed样式中,类选择器优于元素选择器,大量使用元素选择器很慢

// bad
<style scoped>
button{
 border:none;
}
</style>
 
//good
<style scoped>
.btn{
 border:none;
}
</style>

避免隐性的父子组件通信

通过props和事件进行父子组件之间通信,不可使用this.$parent或改变prop

单文件组件命名

单文件组件名,单词首字母大写,或者始终是横线连接


// bad
components
|-mycomponent.vue
components
|-myComponent.vue
 
//good
components
|-MyComponent.vue
components
|-my-component.vue

基础组件名,以特定的前缀开头,组件不含Vuex store的全局状态

// bad
components
|-MyButton.vue
|-VueTable.vue
|-Icon.vue

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

单例组件名,以The前缀命名,表示唯一性,该组件不接受任何prop,非复用组件

// bad
components
|-Heading.vue
|-MySiderbar.vue

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

精密耦合的组件名,与父组件紧密耦合的组件应该以父组件为前缀命名

// bad
components
|-TodoList.vue
|-TodoItem.vue
|-TodoButton.vue
components
|-SearchSidebar.vue
|-NavigationForSearchSideBar.vue
 
//good
components
|-TodoList/
 |-Item/
  |-index.vue
  |-Button.vue
 |-index.vue

//better
components
|-TodoList.vue
|-TodoListItem.vue
|-TodoListItemButton.vue
components
|-SearchSidebar.vue
|-SearchSideBarNavigation.vue



组件名中的单词顺序 高级别单词开头+描述性修饰词结尾

//bad
components
|-ClearSearchButton.vue
|-RunSearchButton.vue
|-SearchInput.vue
|-TermsCheckbox.vue
 
// good
components
|-SearchButtonClear.vue
|-SearchButtonRun.vue
|-SearchInputQuery.vue
|-SettingsCheckboxTerms.vue

完整单词的组件名

//bad
components
|-SdSettings.vue
|-UProfOpts.vue


// good
components
|-StudentDashboardSettings.vue
|-UserProfileOptions.vue

模板中的组件名大小写 组件名除根组件App外应始终由多个单词组成

//bad
vue.component('todo',{
 // ...
})
export default{
 name:'Todo',
 // ...
}
 
// good
vue.component('todo-item',{
 // ...

})
export default{
 name:'TodoItem',
 // ...

}

模板中的组件名大小写 本身html对大小写不敏感,尽量使用横线连接


// bad
<!-- 在单文件组件和字符串模板中 -->
<mycomponent />
<!-- 在单文件组件和字符串模板中 -->
<myComponent />
<!-- 在DOM 模板中-->
<MyComponent></MyComponent>
 
// good
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在DOM 模板中 -->
<my-component></my-component>

JS/JSX中的组件名大小写

// bad
Vue.component('myComponent',{
 //...
})
import myComponent from './MyComponent.vue'
export default {
 name: 'myComponent',
 // ...
}
export default {
 name: 'my-component',
 // ...
}
 
// good
Vue.component('MyComponent',{
 //...
})
Vue.component('my-component',{
 //...
})
import myComponent from './MyComponent.vue'
export default {
 name: 'MyComponent',
 // ...
}

自闭合组件

// bad
<!-- 在单文件组件和字符串模板和JSX中 -->
<MyComponent></MyComponent>
<!-- 在DOM 模板中 -->
<my-component/>
 
// good
<!-- 在单文件组件和字符串模板和JSX中 -->
<MyComponent />
<!-- 在DOM 模板中 -->
<my-component></my-component>

prop名的大小写

// bad
props:{
 'greeting-text':String
}
<WelcomeMessage greetdingText='hi'/>
 
//good
props:{
 greetingText:String
}
<WelcomeMessage greetding-text='hi'/>

多个特性的元素

多行分隔对象的多个属性

// bad
< img src='https://vuejs.org' alt='vue logo'>
<MycComponent foo='a' bar='b' baz='c' />
 
//good
<MyComponent
 foo="a"
 bar="b"
 baz="c"
/>

模板中简单的表达式

// bad
{{
 fullName.split(' ').map(function(word){
  return word[0].toUpperCase() + word.slice(1)
 }).join(' ')
}}
// good
<!-- 模板中 -->
{{ normalizedFullName}}
computed:{
 normalizedFullName:function(){
  return this.fullName.split(' ').map(function(word){
   return word[0].toUpperCase()+word.slice(1)
  }).join(' ')
 }

简单的计算属性

复杂的计算属性应尽可能分为更多简单的属性,易于测试,易于阅读,低耦合

// bad
computed:{
 price:()=>{
  let basePrice = this.manufactureCost / (1 - this.profitMargin)
  return (
   basePrice -
   basePrice * (this.discountPrecent || 0)
  )
 }
}
 
// good
computed:{
 basePrice:()=>{
  return this.manufactureCost / (1 - this.profitMargin)
 }
 discount:()=>{
  return this.basePrice * (this.discountPrecent || 0)
 }
 finalPrice()=>{
  return this.basePrice - this.discount
 }
}

指令缩写

指令缩写保持统一,用 :标识 v-bind,@表示 v-on

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 本文档摘自Vue官方的编码规范,结合实际项目给出如下规范建议 1、组件名为多个单词 组件名应该始终是多个单词的,根...
    China第一程序员阅读 4,249评论 0 5
  • vue 编码规范 1.数据渲染: 渲染数据时,必须使用“Mustache”语法 (双大括号),否则无法在页面显示 ...
    叶赫icon阅读 1,817评论 0 1
  • 这里是官方的 Vue 特有代码的风格指南。如果在工程中使用 Vue,为了回避错误、小纠结和反模式,该指南是份不错的...
    youins阅读 5,737评论 0 5
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,207评论 0 6
  • 一、了解Vue.js 1.1.1 Vue.js是什么? 简单小巧、渐进式、功能强大的技术栈 1.1.2 为什么学习...
    蔡华鹏阅读 3,319评论 0 3