资讯专栏INFORMATION COLUMN

vue总结

Youngs / 1436人阅读

摘要:用创建好的实例调用守卫中传给的回调函数。注册一个全局守卫。这和类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用仅代表个人见解,能力有限,如有错误会误人子弟的地方欢迎留言指出谢谢

原文地址

vue(前端框架)解决了什么问题?

现在的前端页面元素越来越多,结构也变得越来越复杂,当数据和视图混合在一起的时候对它们的处理会十分复杂,同时也很容易出现错误,而现代框架使用声明式语法,描述组件对象的嵌套关系,并自动生成与dom对象的对应关系
参考1

vue生命周期
vue生命周期 描述
beforeCreate 组件实力被创建,el和数据对象都为undefined,还未初始化
create 数据已经被初始化,并且初始化了Vue内部事件,但是DOM还未生成
befroeMount 完成了模板的编译。把data对象里面的数据和vue的语法写的模板编译成了虚拟DOM
mouted 执行了render函数,将渲染出来的内容挂载到了DOM节点上
beforeUpdate 组件更新之前:数据发生变化时,会调用beforeUpdate,然后经历DOM diff
updated 组件更新后
actived keep-alive组件被激活
deactivated keep-alive移除
beforeDestroy 组件销毁前
destroyed 组件销毁后
简述Vue的响应式原理
可以问数据变动如何和视图联系在一起?  
Vue是采用数据劫持结合发布者-订阅者模式的方式, Vue相应系统有三大核心:observe,dep,watcher;精简版Vue代码参考

Observe:当一个Vue实例创建时,initData阶段,vue会遍历data选项的属性(observe),用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖(dep),在属性被访问和修改时通知变化。

Compite:调用compile方法解析模版,当视图中有用到vue.data中数据的时候,会调用实例化watcher方法进行依赖收集

Watcher:是ObserverCompile之间通信的桥梁,当视图中遇到绑定的数据时,在watcher方法中会获取这个数据,此时会触发observe中的getter方法,

Dep:发布订阅模式,observe中数据的getter被触发时会收集依赖的watcher(dep.depend方法)

当有数据被改动时会触发observe中数据的setter,此时会调用dep.notify方法给所有订阅的watcher发通知(通过回掉方式)进行视图更新,此时会进行diff流程:

vue中data为什么必须要是一个函数
vue中的data为对象,是引用类型,当重用组件时,一个组件对data做了更改,那么另一个组件也会跟着改,而使用返回一个函数返回数据,则每次返回都是一个新对象,引用地址不用,所以就不会出现问题
Virtual DOM 是什么

虚拟DOM是一个JavaScript对象,包含了当前DOM的基本结构和信息,它的存在是为了减少对操作无用DOM所带来的性能消耗,在大量的、频繁的数据更新下能够对视图进行合理的高效的更新(细粒度的精准修改),同时也抽象了原来的渲染过程,实现了跨平台的能力

简述vue中的DOM DIFF算法

精简源码;当数据发生改变时,set方法会让调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁(两个重要函数patchVnodeupdateChildren):

先判断根结点及变化后的节点是否是sameVnode,如果不是的化,就会创建新的根结点并进行替换

如果是sameVnode,则进入patchVnode函数,其基本判断

如果两个节点是相等oldVnode === vnode则直接return

如果新节点是文本节点,则判断新旧文本节点是否一致,不一致(oldVnode.text !== vnode.text)则替换

如果新节点不是文本节点,则开始比较新旧节点的子节点oldChch

如果子节点都存在,则进行updateChildren计算(稍后讲)

如果只有新子节点存在,则如果旧节点有文本节点,则移除文本节点,然后将新子节点拆入

如果只有旧子节点存在,则移除所有子节点

如果均无子节点且旧节点是文本节点,则移除文本节点(此时新节点一定不是文本节点)

updateChildren函数做细致对比

start && oldStart对比

end && oldEnd对比

start && oldEnd对比

end && oldStart 对比

生成map映射,(key:旧子节点上的key,value:旧子节点在自己点中的位置),根据key记录下老节点在新节点的位置(idxInOld
1) 如果找到了idxInOld,如果是相同节点则移动旧节点到新的对应的地方,否则虽然key相同但元素不同,当作新元素节点去创建
2) 如果没有找到idxInOld,则创建节点

如果老节点先遍历完,则新节点比老节点多,将新节点多余的插入进去

如果新节点先遍历完,则就节点比新节点多,将旧节点多余的删除

vue中key的作用

主要是为了复用节点,高效的更新虚拟DOM,另外,在使用标签元素过渡效果时也会用到key

computed的原理

vue对象初始化的同时对计算属性进行初始化initComputed,

computed会对初始化的Watcher传入lazy: true就会触发Watcher中的watcher.dirty=true(dirty决定了当前属性是否更新),

当视图中有对computed引用的时候会第一次执行计算属性,并将dirty设置为false,并将结果保存在this.value中进行缓存,

如果依赖没有更改,则下次获取computed会这直接返回this.value,只有当computed所依赖的属性发生变化时会将dirty设置为true,并重新计算

class Watcher{
  ……
  evaluate () {
    this.value = this.get()
    this.dirty = false
  }
  ……
}

class initComputed{
  …… 
  //计算属性的getter 获取计算属性的值时会调用
    createComputedGetter (key) {
      return function computedGetter () {
          //获取到相应的watcher
        const watcher = this._computedWatchers && this._computedWatchers[key]
        if (watcher) {
             //watcher.dirty 参数决定了计算属性值是否需要重新计算,默认值为true,即第一次时会调用一次
              if (watcher.dirty) {
                  /*每次执行之后watcher.dirty会设置为false,只要依赖的data值改变时才会触发
                  watcher.dirty为true,从而获取值时从新计算*/
                watcher.evaluate()
              }
              //获取依赖
              if (Dep.target) {
                watcher.depend()
              }
              //返回计算属性的值
              return watcher.value
        }
      }
    }
  ……
}
计算属性computed和watch的区别

计算属性顾名思义就是通过其他变量计算得来的,它的值是基于其所依赖的属性来进行缓存的,只有在其所依赖的属性发生变化时才会从新求值
watch是监听一个变量,当变量发生变化时,会调用对应的方法

对$nextTick的理解

vue实现响应式并不是数据一更新就立刻触发dom变化,而是按照一定的策略对dom进行更新,源码位置,原理:

首先会将所有的nextTick放到一个函数中,然后放在callbacks数组中,$nextTick没有传cb回掉,则返回一个promise

接下来就是callbacks的执行时机

首先如果浏览器是否兼容promise,则用promise.resolve().then来执行callbacks

如果浏览器兼容MutationObserver,则用实例化的MutationObserver监听文本变化来执行回掉,

如果兼容setImmediate,则用setImmediate(cb)来执行回掉

最后降级为用setTimeout(fn,0)来执行

vue2.5.X版本中对于像v-on这样的DOM交互事件,默认走macroTimerFunc,也就是,跳过第一步promise的判断,

子组件为何不可以修改父组件传递的 Prop,是如何监控并给出错误提示的

单向数据流,易于监测数据的流动,出现了错误可以更加迅速的定位到错误发生的位置

initProps时,会对props进行defineReactive操作,传入的第四个参数是自定义的set报错判断函数,该函数会在触发props的set方法时执行

// src/core/instance/state.js 源码路径
function initProps (vm: Component, propsOptions: Object) {
  ...
  for (const key in propsOptions) {
    if (process.env.NODE_ENV !== "production") {
      ...
      defineReactive(props, key, value, () => {
        // 如果不是跟元素并且不是更新子元素
        if (!isRoot && !isUpdatingChildComponent) {
          warn(
            `Avoid mutating a prop directly since the value will be ` +
            `overwritten whenever the parent component re-renders. ` +
            `Instead, use a data or computed property based on the prop"s ` +
            `value. Prop being mutated: "${key}"`,
            vm
          )
        }
      })}
    ...
  }
}
// src/core/observer/index.js
export function defineReactive (obj,key,val,customSetter,shallow) {
  const property = Object.getOwnPropertyDescriptor(obj, key)
  
  const getter = property && property.get
  const setter = property && property.set
  
  Object.defineProperty(obj, key, {
    ...
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      if (process.env.NODE_ENV !== "production" && customSetter) {
        customSetter()
      }
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}
父子组件的生命周期执行顺序

加载过程:父组件beforeCreate => 父组件created => 父组件beforeMount => 子组件beforeCreate => 子组件created => 子组件 beforeMount => 子组件mounted => 父组件mounted
更新过程:父组件beforeUpdate => 子组件beforeUpdate => 子组件updated => 父组件updated
销毁过程:父组件beforeDestroy => 子组件 beforeDestroy => 子组件 destoryed => 父组件 destoryed

vue-router的导航解析流程

官网

导航被触发。

在失活的组件里调用离开守卫。

调用全局的 beforeEach 守卫。

在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

在路由配置里调用 beforeEnter

解析异步路由组件。

在被激活的组件里调用 beforeRouteEnter

调用全局的 beforeResolve 守卫 (2.5+)。

导航被确认。

调用全局的 afterEach 钩子。

触发 DOM 更新。

用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

仅代表个人见解,能力有限,如有错误会误人子弟的地方欢迎留言指出;谢谢

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105599.html

相关文章

  • Java学习路线总结,搬砖工逆袭Java架构师(全网最强)

    摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...

    Scorpion 评论0 收藏0
  • 基于vue项目的知识总结

    摘要:前言用有一段时间了,从用搭建项目一步步配置,到之后的研究动效这些,一直想写些东西记录一下做个总结,刚好趁着有空就整理一下。结语有新的知识点会更新到知识体系中,总结和心得体会会单独写文章详述,努力填坑 前言 用vue有一段时间了,从用vue-cli搭建项目、一步步配置axios、vuex、vue-router,到之后的研究canvas、动效这些,一直想写些东西记录一下、做个总结,刚好趁着...

    tianlai 评论0 收藏0
  • VUE实践总结

    摘要:前言本文主要总结了自己实际开发项目当中遇到的一些常见问题以及解决方案组件的是当一个组件被定义,必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。实在要比较只能比较对象的具体值了。 前言 本文主要总结了自己vue实际开发项目当中遇到的一些常见问题以及解决方案 VUE组件的data是function 当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为...

    channg 评论0 收藏0
  • Vue.js SSR 内容总结

    摘要:本文只是对官方文档和对官方的个人学习总结,说得不够完整的请见谅本文主要对以下几方面内容对的内容进行分析总结出现的原因的总体原理当中的数据预取在编写代码时候的限制的构建原理出现的原因单页应用有一个很大的缺点就是问题,搜索引擎目前只能对同步的进 本文只是对Vue.js官方SSR文档和对官方hackernews demo的个人学习总结,说得不够完整的请见谅 本文主要对以下几方面内容对Vue....

    曹金海 评论0 收藏0
  • 标注图+部分举例聊聊Vue生命周期

    摘要:天王盖地虎钩子事件得到的结果是小总结实例创建完成后,我们能读取到数据的值,但是还没生成,挂载属性还不存在。此时的阶段解读为挂载完毕阶段我们再打印下此时看看钩子事件得到的结果是可见,已经成功渲染成里面对应的值天王盖地虎了。 你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。 现在项目中遇到了,好好回头总结一波Vue生命周期,以后用到的时候再来翻翻。 啥叫V...

    Aceyclee 评论0 收藏0
  • vue-cli 3.0 源码分析

    摘要:写在前面其实最开始不是特意来研究的源码,只是想了解下的命令,如果想要了解命令的话,那么绕不开写的。通过分析发现与相比,变化太大了,通过引入插件系统,可以让开发者利用其暴露的对项目进行扩展。 showImg(https://segmentfault.com/img/bVboijb?w=1600&h=1094); 写在前面 其实最开始不是特意来研究 vue-cli 的源码,只是想了解下 n...

    yiliang 评论0 收藏0

发表评论

0条评论

Youngs

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<