• vue3源码解析


    vue3源码解析与前端网络安全

    VUE 3 拓展

    vue3 对比 vue2

    响应式数据

    vue2 的响应式数据是通过 Object.defineProperty 进行数据劫持,其存在一些缺点:

    • 必须要预知劫持的 key 是什么,并不能很好的监听到对象属性的添加、删除;
    • 初始化递归遍历整个 data ,导致深层嵌套数据造成性能负担;

    vue3 的响应式数据是通过 Proxy 进行数据劫持的,可以很好的规避 Object.defineProperty 带来的缺陷

    组合式 Api
    • 代码更利于维护和封装
    • Vue2 中,我们会在一个 vue 文件的 data,methods,computed,watch 中定义属性和方法,共同处理页面逻辑 ,一个功能的实现,代码过于分散
    • vue3 中,代码是根据逻辑功能来组织的,一个功能的所有 api 会放在一起(高内聚,低耦合),提高可读性和可维护性,基于函数组合的 API 更好的重用逻辑代码
    Diff 算法优化

    首先了解 vue 的 虚拟dom
    虚拟DOM就是通过 JS 去生成一个 AST 节点树
    在这里插入图片描述

    一个dom节点上的属性是非常多的,所以直接操作DOM是非常浪费性能的,解决方案就是可以通过JS的计算性能去换取操作DOM所消耗的性能,既然逃不开操作DOM,那我们可以尽可能少的去操作DOM;

    diff 算法

    在这里插入图片描述
    规则一:前序对比
    在这里插入图片描述
    规则二:尾序对比
    在这里插入图片描述
    规则三:新增对比
    在这里插入图片描述
    在这里插入图片描述
    规则四:卸载移除对比
    在这里插入图片描述
    规则五:乱序对比
    vue3.x 中标记和提升所有的静态节点,diff 的时候只需要对比动态节点内容,尽可能复用标记的静态节点。

    更好的 TSX 语法支持
    // App.tsx
    
    import {ref} from 'vue'
    
    let v = ref<string>('')
    
    const renderDom = ()=>{
        return (
        <div>
            <input v-model = {v.value} type="text" />
            <div>{v.value}</div>
        </div>
        )
    }
    
    export default renderDom
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    <template>
        <renderDom></renderDom>
    </template>
    
    <script setup lang="ts">
    import renderDom from './App'
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ref 全家桶

    1. ref 将数据包装成响应式数据;
      在这里插入图片描述
    2. shallowRef (浅层的ref,一般配合triggerRef强制更新dom);
    3. triggerRef (手动执行与shallowRef关联的副作用,强制更新视图,ref的视图更新也是因为触发了triggerRef)
    4. customRef (自定义ref,场景:可以做一些防抖操作)
    5. 在这里插入图片描述

    reative 全家桶

    1. reactive 接受复杂数据类型,返回响应式数据;
      1. 数组的赋值两种方式:push解构的值;
      2. 将数组包装成对象,通过属性赋值;
        在这里插入图片描述
        泛型约束了类型,不能绑定基本数据类型
        在这里插入图片描述
        shallowReactive

    to 系列全家桶

    1. toRef, 如果想让响应式数据和以前的数据关联起来,并且更新响应式数据之后还不想更新视图,那么就可以使用 toRef ;
      在这里插入图片描述
      在这里插入图片描述
    2. toRefs,解构会破坏数据的响应式,通过 toRefs 可以解构出响应式的数据;
      源码解析:其实就是把reactive 对象的每一个属性都变成了ref 对象循环 调用了toRef
      在这里插入图片描述
    3. toRaw ,将响应式数据中得到原始数据;
      应用场景:
      A-发起请求前对数据的处理,不希望更新视图,可以先把双向绑定的响应式数据转成原始数据,再进行处理发请求;
      B-渲染具有不可变数据源的大列表时,可以跳出响应式的追踪,提高性能;
      在这里插入图片描述

    组件通信 Provide inject

    通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,会很麻烦。

    场景A:通过路由进行局部组件的刷新,对数据进行操作之后需要手动刷新页面;
    场景B:父组件有很多数据需要分发给其子代组件的时候

    源码解析:
    在这里插入图片描述

    Inject 接收的值是unknown的问题:
    在这里插入图片描述
    组件实例化的时候注入 provides 的值
    在这里插入图片描述

    自定义Hooks( 区别于vue2的mixins )

    钩子主要用来处理复用代码逻辑的封装,在vue2的时候就已经有 Mixins 去做这样的事情了, Mixins 就是将这些多个相同的逻辑抽离出来,各个组件只需要引入 mixins 就能实现一次写代码,多组件受益的效果
    缺点是会涉及覆盖问题,同名data、methods、filters覆盖,以及变量来源不明确,不利于阅读,使代码难以维护;

    为了解决mixins存在的问题,Vue3.x版本使用了自定义Hooks去做这样的事情。

    开源的hooks库(VueUse)

    // 定义转换base64的hooks   
    import { onMounted } from 'vue'
     
    type Options = {
        el:string
    }
    export default function(options:Options)Promise<{baseUrl:string}>{
        return new Promise((reslove)=>{
            onMounted(()=>{
                let img:HTMLImageElement = document.querySelector(options.el) as HTMLImageElement
                img.onload = () => {
                resolve({
                    baseUrl: base64(img)
                })
            }
        })
        
            const base64 = (el:HTMLImageElement) => {
                const canvas = document.createElement('canvas')
                const ctx = canvas.getContext('2d')
                canvas.width = el.width
                canvas.height = el.height
                ctx?.drawImage(el,0,0,canvas.width,canvas.height)
                return canvas.toDataURL('image/png')
            }
        })
      
    }
    
    
    // 使用 hooks
    <template>
        <div>
            <img id='img' src='./assets/test.png'>
        </div>
    </template>
    
    <script lang="ts" setup>
    import useBase64 from './hooks'
    
    useBase64({el: '#img'}).then(res=>{
        window.console.log(res.baseUrl)
    })
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
  • 相关阅读:
    想找个程序员朋友和我做件事情
    基于A2C与超启发式的航天器星载自主任务规划算法-笔记
    git reset 与 git revert 用法(回退远程提交)
    Vue 3的革命性新特性:深入了解Composition API
    使用vue扫描扫描仪图像
    第十九届全国环境友好科技竞赛(绿色创业类)正式启动
    【精品】pinia 基于插件pinia-plugin-persist的 持久化
    初始结构体
    el-table纵向垂直表头
    计算机网络基础一
  • 原文地址:https://blog.csdn.net/weixin_43029824/article/details/133749796