深入浅出vue.js 最佳实战

聊下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. p a r e n t 或 改 变 p r o p 。 一 个 理 想 的 V u e . j s 应 用 是 ” p r o p 向 下 传 递 , 事 件 向 上 传 递 “ p r o p 的 变 更 或 t h i s . parent或改变prop。 一个理想的Vue.js应用是 ”prop向下传递,事件向上传递 “ prop的变更或this. parentpropVue.jsproppropthis.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

如果有帮助,希望给个赞和关注

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ronghua_yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值