Fork me on GitHub

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

  

  

posted @ 2022-11-01 18:21  小白不白10  阅读(468)  评论(0编辑  收藏  举报