• 中高级前端开发需要掌握的vue知识点


    keep-alive 使用场景和原理

    keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

    • 常用的两个属性 include/exclude,允许组件有条件的进行缓存。
    • 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。
    • keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。

    理解Vue运行机制全局概览

    全局概览

    首先我们来看一下笔者画的内部流程图。

    大家第一次看到这个图一定是一头雾水的,没有关系,我们来逐个讲一下这些模块的作用以及调用关系。相信讲完之后大家对Vue.js内部运行机制会有一个大概的认识。

    初始化及挂载

    new Vue() 之后。 Vue 会调用 _init 函数进行初始化,也就是这里的 init 过程,它会初始化生命周期、事件、 props、 methods、 data、 computed 与 watch 等。其中最重要的是通过 Object.defineProperty 设置 settergetter 函数,用来实现「 响应式 」以及「 依赖收集 」,后面会详细讲到,这里只要有一个印象即可。

    初始化之后调用 $mount 会挂载组件,如果是运行时编译,即不存在 render function 但是存在 template 的情况,需要进行「 编译 」步骤。

    编译

    compile编译可以分成 parseoptimizegenerate 三个阶段,最终需要得到 render function。

    1. parse

    parse 会用正则等方式解析 template 模板中的指令、class、style等数据,形成AST。

    2. optimize

    optimize 的主要作用是标记 static 静态节点,这是 Vue 在编译过程中的一处优化,后面当 update 更新界面时,会有一个 patch 的过程, diff 算法会直接跳过静态节点,从而减少了比较的过程,优化了 patch 的性能。

    3. generate

    generate 是将 AST 转化成 render function字符串的过程,得到结果是 render 的字符串以及 staticRenderFns 字符串。

    • 在经历过 parseoptimizegenerate 这三个阶段以后,组件中就会存在渲染 VNode 所需的 render function 了。
    响应式

    接下来也就是 Vue.js 响应式核心部分。

    这里的 gettersetter 已经在之前介绍过了,在 init 的时候通过 Object.defineProperty 进行了绑定,它使得当被设置的对象被读取的时候会执行 getter 函数,而在当被赋值的时候会执行 setter 函数。

    • render function 被渲染的时候,因为会读取所需对象的值,所以会触发 getter 函数进行「 依赖收集 」,「 依赖收集 」的目的是将观察者 Watcher 对象存放到当前闭包中的订阅者 Depsubs 中。形成如下所示的这样一个关系。

    在修改对象的值的时候,会触发对应的 settersetter 通知之前「 依赖收集 」得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些 Watcher 就会开始调用 update 来更新视图,当然这中间还有一个 patch 的过程以及使用队列来异步更新的策略,这个我们后面再讲。

    Virtual DOM

    我们知道,render function 会被转化成 VNode 节点。Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。

    比如说下面这样一个例子:

    {
       
        tag: 'div',                 /*说明这是一个div标签*/
        children: [                 /*存放该标签的子节点*/
            {
       
                tag: 'a',           /*说明这是一个a标签*/
                text: 'click me'    /*标签的内容*/
            }
        ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    渲染后可以得到

    <div>
        <a>click me</a>
    </div>
    
    • 1
    • 2
    • 3

    这只是一个简单的例子,实际上的节点有更多的属性来标志节点,比如 isStatic (代表是否为静态节点)、 isComment (代表是否为注释节点)等。

    更新视图

    • 前面我们说到,在修改一个对象值的时候,会通过 setter -> Watcher -> update 的流程来修改对应的视图,那么最终是如何更新视图的呢?
    • 当数据变化后,执行 render function 就可以得到一个新的 VNode 节点,我们如果想要得到新的视图,最简单粗暴的方法就是直接解析这个新的 VNode 节点,然后用 innerHTML 直接全部渲染到真实 DOM 中。但是其实我们只对其中的一小块内容进行了修改,这样做似乎有些「 浪费 」。
    • 那么我们为什么不能只修改那些「改变了的地方」呢?这个时候就要介绍我们的「 patch 」了。我们会将新的 VNode 与旧的 VNode 一起传入 patch 进行比较,经过 diff 算法得出它们的「 差异 」。最后我们只需要将这些「 差异 」的对应 DOM 进行修改即可。
    再看全局

    回过头再来看看这张图,是不是大脑中已经有一个大概的脉络了呢?

    用VNode来描述一个DOM结构

    虚拟节点就是用一个对象来描述一个真实的DOM元素。首先将 template (真实DOM)先转成 ast ast 树通过 codegen 生成 render 函数, render 函数里的 _c 方法将它转为虚拟dom

    Vue中key的作用

    vue 中 key 值的作用可以分为两种情况来考虑:

    • 第一种情况是 v-if 中使用 key。由于 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。因此当使用 v-if 来实现元素切换的时候,如果切换前后含有相同类型的元素,那么这个元素就会被复用。如果是相同的 input 元素,那么切换前后用户的输入不会被清除掉,这样是不符合需求的。因此可以通过使用 key 来唯一的标识一个元素,这个情况下,使用 key 的元素不会被复用。这个时候 key 的作用是用来标识一个独立的元素。
    • 第二种情况是 v-for 中使用 key。用 v-for 更新已渲染过的元素列表时,它默认使用“就地复用”的策略。如果数据项的顺序发生了改变,Vue 不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处的每个元素。因此通过为每个列表项提供一个 key 值,来以便 Vue 跟踪元素的身份,从而高效的实现复用。这个时候 key 的作用是为了高效的更新渲染虚拟 DOM。

    key 是为 Vue 中 vnode 的唯一标记,通过这个 key,diff 操作可以更准确、更快速

    • 更准确:因为带 key 就不是就地复用了,在 sameNode 函数a.key === b.key对比中可以避免就地复用的情况。所以会更加准确。
    • 更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

    参考:前端vue面试题详细解答

    computed 和 watch 的区别和运用的场景?

    computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;

    watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

    运用场景:

    • 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
    • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

    Vue.extend 作用和原理

    官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

    其实就是一个子类构造器 是 Vue 组件的核心 api 实现思路就是使用原型继承的方法返回了 Vue 的子类 并且利用 mergeOptions 把传入组件的 options 和父类的 options 进行了合并

    Vue 初始化页面闪动问题如何解决?

    出现该问题是因为在 Vue 代码尚未被解析之前,尚无法控制页面中 DOM 的显示,所以会看见模板字符串等代码。
    解决方案是,在 css 代码中添加 v-cloak 规则,同时在待编译的标签上添加 v-cloak 属性:

    [v-cloak] { display: none; }
    
    <div v-cloak>
      {
      { message }}
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如何从真实DOM到虚拟DOM

    涉及到Vue中的模板编译原理,主要过程:

    1. 将模板转换成 ast 树, ast 用对象来描述真实的JS语法(将真实DOM转换成虚拟DOM)
    2. 优化树
    3. ast 树生成代码

    你有使用过vuex的module吗?

    const moduleA = {
       
      state: () => ({
        ... }),
      mutations: {
        ... }
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    【智能AI相机】基于AI的新型成像和照明技术
    【从零开始学习RabbitMQ | 第二篇】如何确保MQ的可靠性和消费者可靠性
    浅析React Hook之useReducer
    Jetpack Compose 重写TopAppBar 实现标题多行折叠
    sass 骚用笔记
    【从0到1开发一个网关】网关日志的开发
    【MM32F5270开发板试用】四、SPI的驱动,先点个屏幕
    stm32 hal库 st7789 1.54寸lcd
    瀑布流使用虚拟列表性能优化
    秋招面经第一弹:百度一面-大数据开发工程师
  • 原文地址:https://blog.csdn.net/bb_xiaxia1998/article/details/127842117