Vue3(一)(重写双向绑定,优化Vdom, Fragment,Tree shaking, Composition Api,ref,isRef,shallowRef,triggerRef ,customRef)
重写双向绑定
vue2
基于Object.defineProperty()实现
vue3 基于Proxy
proxy与Object.defineProperty(obj, prop, desc)方式相比有以下优势:
//丢掉麻烦的备份数据 //省去for in 循环 //可以监听数组变化 //代码更简化 //可以监听动态新增的属性; //可以监听删除的属性 ; //可以监听数组的索引和 length 属性; let proxyObj = new Proxy(obj,{ get : function (target,prop) { return prop in target ? target[prop] : 0 }, set : function (target,prop,value) { target[prop] = 666; } })
Vue3 优化Vdom
在Vue2中,每次更新diff,都是全量对比,Vue3则只对比带有标记的,这样大大减少了非动态内容的对比消耗
Vue3 Fragment
vue3 允许我们支持多个根节点
同时支持render JSX 写法,新增了Suspense teleport 和 多 v-model 用法
render() { return ( <> {this.visable ? ( <div>{this.obj.name}</div> ) : ( <div>{this.obj.price}</div> )} <input v-model={this.val}></input> {[1, 2, 3].map((v) => { return <div>{v}-----</div>; })} </> ); },
Vue3 Tree shaking
简单来讲,就是在保持代码运行结果不变的前提下,去除无用的代码
在Vue2中,无论我们使用什么功能,它们最终都会出现在生产代码中。主要原因是Vue实例在项目中是单例的,捆绑程序无法检测到该对象的哪些属性在代码中被使用到
而Vue3源码引入tree shaking特性,将全局 API 进行分块。如果你不使用其某些功能,它们将不会包含在你的基础包中
就是比如你要用watch 就是import {watch} from 'vue' 其他的computed 没用到就不会给你打包减少体积
Vue 3 Composition Api
Setup 语法糖式编程
例如 ref reactive watch computed toRefs toRaws
模板插值语法
在script 声明一个变量可以直接在template 使用用法为{{变量名称}}
<template> <div>{{ message }}</div> </template> <script setup lang="ts"> const message = "hello" </script> <style> </style>
介绍虚拟DOM
虚拟DOM就是通过JS来生成一个AST节点树
为什么要有虚拟DOM?
一个dom上面的属性是非常多,直接操作DOM非常浪费性能,解决方案就是 我们可以用JS
的计算性能来换取操作DOM
所消耗的性能,
既然我们逃不掉操作DOM
这道坎,但是我们可以尽可能少的操作DOM,
操作JS是非常快的
ref
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value
property,指向该内部值。
案例
我们这样操作是无法改变message 的值 应为message 不是响应式的无法被vue 跟踪要改成ref
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template>
<script setup lang="ts"> let message: string = "我是message" const changeMsg = () => { message = "change msg" } </script> <style> </style>
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import {ref} from 'vue' let message = ref("我是message") const changeMsg = () => { message.value = "change msg" } </script> <style> </style>
注意被ref包装之后需要.value 来进行赋值
isRef
判断是不是一个ref对象
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import { ref, Ref,isRef } from 'vue' let message: Ref<string | number> = ref("我是message") let notRef = 123 const changeMsg = () => { message.value = "change msg" console.log(isRef(message)); //true console.log(isRef(notRef)); //false } </script> <style> </style>
shallowRef
创建一个跟踪自身 .value
变化的 ref,但不会使其值也变成响应式的
例子
修改其属性是非响应式的这样是不会改变的
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import { Ref, shallowRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "小满" }) const changeMsg = () => { message.value.name = '大满' console.log(message.value) } </script> <style> </style>
例子2
这样是可以被监听到的修改value
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import { Ref, shallowRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "小满" }) const changeMsg = () => { message.value = { name: "大满" } } </script> <style> </style>
triggerRef
强制更新页面DOM
这样也是可以改变值的
<template> <div> <button @click="changeMsg">change</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import { Ref, shallowRef,triggerRef } from 'vue' type Obj = { name: string } let message: Ref<Obj> = shallowRef({ name: "小满" }) const changeMsg = () => { message.value.name = '大满' triggerRef(message) } </script> <style> </style>
customRef
自定义ref
customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set 适合去做防抖之类的
<template> <div ref="div">小满Ref</div> <hr> <div> {{ name }} </div> <hr> <button @click="change">修改 customRef</button> </template> <script setup lang='ts'> import { ref, reactive, onMounted, shallowRef, customRef } from 'vue' function myRef<T = any>(value: T) { let timer:any; return customRef((track, trigger) => { return { get() { track() return value }, set(newVal) { clearTimeout(timer) timer = setTimeout(() => { console.log('触发了set') value = newVal trigger() },500) } } }) } const name = myRef<string>('小满') const change = () => { name.value = '大满' } </script> <style scoped> </style>
————————————————
版权声明:本文为CSDN博主「小满zs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq1195566313/article/details/122768533