vue2-部分优化与理解

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

<div v-if="flag">
  正确内容
</div>
<div v-else>
  错误内容
</div>

vue会尽可能的高效更新DOM. 相同类型的元素之间切换时,会修补已存在的元素,而不是将旧的元素移除后,同一位置添加一个新元素。

解决路由切换组件不变的问题

cosnt routes = [
  {
    path: 'detail/:id',
    name: 'detail',
    component: Detail
  }
]

当页面切换到同一个路由但 不同的参数地址时, 组件的生命周期钩子不会重复处触发。

① 路由导航守卫 beforeRouteUpdate
vue-router提供了 导航守卫 beforeRouteUpdate, 当前路由改变 并 组件 复用 时调用。
所有只需要 把每次 切换路由时 需要 执行的 逻辑 放到 beforeRouteUpdate守卫中即可

② 观察 $route对象的变化
通过 watch 可以监听若有对象中的变化,从而对 路由变化做出响应

const User = {
  watch: {
    '$route' (to, from){
       // 对 路由变化做出 响应
    }
  }
}

③ 为 router-view 组件添加属性 key

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

有点事简单粗暴,改动小。 缺点是 ,每次切换 都会 被销毁并重新创建,很消耗性能。

为所有路由添加 query

如果路由上 的query 中有 一些 参数需要一直 传递下去,在每个跳转路由的地方设置会很麻烦。

①使用全局守卫 beforeEach
事实上,beforeEach 不具备修改query的方法,但可以使用next方法 中断当前导航,并切换到新导航,添加一些query进去。

刚进入新导航后,依然会被全局守卫 beforeEach拦截,然后再次开启新导航,从而导致死循环。 解决办法是 判断这个 全局添加的参数在路由中是否存在,如果存在,则不开启新导航

const query = {referer: 'test-hehehe'}
router.beforeEach(to, from, next) => {
  to.query.referer ? next() : next({...to, query: {...to.query, ...query}})
}

②使用函数劫持
原理是 通过拦截 router.history.transitionTo方法 ,在vue-router内切换路由之前 将参数 添加到query 中。

const query = {referer: 'test-hehehe'}
const transitioinTo = 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内部的 router.history.transitionTo方法 缓存到变量中。 然后使用新函数重新router.history.transitionTo方法, 通过在函数中修改参数达到全局 添加 query 参数的目的。当执行缓存的原始方法时,将修改后的参数传递进去。

vue中 key的作用和原理

src\core\vdom\patch.js 中的 updateChildren函数(遍历当前节点的所有 子节点更新)通过 key 判断是不是同一个节点。

可以知道
key的作用是: 为了高效的更新虚拟DOM

原理是: vue在patch过程中通过key可以精准判断两个节点是不是同一个,从而避免频繁更新不同的元素, 使得整个patch 过程更加高效,减少DOM操作量,提高性能

diff

  • 必要性: lificycle.js - mountComponent()
    在$mount的时候回调用 ,一个组件 会 有 一个 watcher.
    组件中 可能存在很多个data中 key的使用, 为了区分,使用diff

  • 执行 patch.js --- patchVnode()
    patchVnode是diff 发生的地方,整体策略试试:深度优先,同层比较

  • 高效性 patch.js --- updateChildren()

  1. diff算法是虚拟DOM技术的产品: 通过 新旧虚拟DOM对比(即diff),将变化的地方更新在真实DOM上,另外, 也需要diff高效的执行对比过程, 从而降低时间复杂度为O(n).

  2. vue2为了降低 watcher粒度, 每个组件只有一个watcher与之对应,引入diff才能精确的查找发生变化的地方。

  3. vue中执行diff的时刻是 组件实例执行 更新函数时,它会对比上一次渲染结果 oldVnode和新的渲染结果 newVnode,此过程称为 patch.

  4. diff 过程整体遵循深度优先、同层比较的策略。 两个 节点之间会根据它们时候拥有子节点或者文本节点做不同的操作。 比较两组子节点是 算法的重点。借助key通常可以精准的找到相同的节点,因此patch过程是高效的。

组件化的理解

vue实例化时自上而下的,但是 挂载是自下而上的。

  1. 组件 是独立可 复用的 代码组织单元。 组件系统是 vue 核心特性之一, 它使 开发者使用小型、独立和通常可以复用的 组件 构建大型应用。
  2. 组件化开发能大幅提高应用开发效率、测试性、复用性等;
  3. 组件使用按分类有: 页面组件、 业务组件、 通用组件
  4. vue的组件是基于配置的,同名通常编写的组件配置 而非组件, 框架 后续会生产其 构造函数,它们基于 VueComponent,扩展Vue;
  5. vue中常见的组件化技术有: 属性prop,自定义事件、插槽等,它们主要用于组件通信、扩展等;
  6. 合理的划分组件,有利于提升应用性能(比如某一块经常更新,把它提为组件,组件有单独的watcher。这样更新,就不会影响其他的)
  7. 组件应该高内聚、低耦合
  8. 遵循单向数据流的原则

vue性能优化方法

  1. 路由懒加载
routes:[
  {path: '/foo', component: ()=> import('./Foo.vue')}
]
  1. keep-alive 缓存页面
  2. v-show 复用DOM (频繁显示,组件比较重的情况,渲染时间比较长)
  3. v-for 遍历避免同时 使用 v-if (用computed计算属性处理)
  4. 长列表性能优化。
    如果列表是纯粹的展示,不需要改变,就不需要做响应式
data: () =>({ user: []}),
async cteated(){
 const user = await axios.get('/api/users');
 this.user = Object.freeze(user) // 冻结 数据 ,不会变成响应式
}

如果是大数据列表,采用 虚拟滚动,只渲染少部分区域的内容。
vue-virtual-scroller
只显示 可视区的内容,滚动后加载其他

  1. 事件的销毁
    vue组件销毁时, 会自动解绑它的全部指令及事件监听器。但仅限于组件本身的事件。 我们自己比如setInterval的定时器,需要我们在beforeDestroy的时候手动clearInterval
  2. 图片懒加载 vue-lazyload
  3. 第三方插件按需引入
    比如element-ui这样第三方组件库 按需引入, 避免体积太大。
  4. 无状态的展示型组件 ,使用函数式组件 (没有自己的状态实例)
<template functional>
      <div>
            <p v-for="(item,index) in props.items" :key="index" @click="props.itemClick(item)" />
      </div>
</template>
  1. 子组件分割 : 比较复杂的组件,切割出来,自己管自己。不会影响其他。避免整个页面都重新渲染
  2. SSR

vuex的使用与理解

定义:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化

解决的问题:
解决不同组件之间状态共享问题。 利用各个组件通信方式,虽然也能做到状态共享,当时旺旺需要在多个组件之间保持状态的一致性。这种模式很容易出问题,程序逻辑也更复杂。 vuex将组件的共享状态抽取出来,以全局单例模式管理,这样 任何组件都能用一致的方式获取和修改状态, 响应式的数据也能保证简洁的单向数据流动,我们的代码也变得更结构化且易于维护。

使用场景:vuex 并非必须的, 它帮我们管理共享状态,当却带来更多的概念和框架。 如果我们不打算开发大型单页应用,或者我们的应用并没有大量全局的状态需要维护,完全没有用vuexd 必要。

vuex的使用:
首先对核心概念的理解和应用,
将全局状态放入state对象中,它本身是一棵状态树, 组件中使用store实例的state访问这些状态; 然后又配套的mutation方法修改这些状态, 并且只能用mutation修改状态, 在组件中调用commit 方法提交mutation;
如果应用中有异步操作或复杂逻辑组合,我们需要编写action,执行结束如果有状态修改仍然需要提交mutation, 组件中调用action 使用dispatch方法派发。
最后模块化, 通过modules 选项组织 拆分出去各个 子模块, 在访问状态时注意添加子模块名称, 如果子模块 有设置 namespace,那么提交mutation和派发action时 还需要额外的 命名空间前缀。

原理:
https://www.jianshu.com/p/86dc8b5d004d
vuex实现单项数据流时需要做到数据的响应式, 借用了vue的数据响应式特性实现的, 它会利用vue将state 作为data 对其进行响应式处理,从而使得这些状态发生改变,能够导致组件重新渲染。

vue中组件之间的通信方式

  • props
  • $emit/$on
  • $children/$parent
  • $attrs/$listeners
  • ref
  • $root
  • eventbus (事件总线)
  • vuex

父子组件之间通信

  • props
  • $emit/$on
  • $children/$parent
  • $attrs/$listeners
  • ref
    兄弟组件
  • $parent
  • $root
  • eventbus
  • vuex
    跨层级关系
  • eventbus
  • vuex
  • provide/inject

EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。https://zhuanlan.zhihu.com/p/72777951

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

推荐阅读更多精彩内容