IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 拥抱Vue3 (三) ref 与 reactive以及响应式原理 -> 正文阅读

[JavaScript知识库]拥抱Vue3 (三) ref 与 reactive以及响应式原理

一、ref 包装基本数据类型数据

在第二篇文章中举例的时候,我们创建了非响应式的数据,在控制台中查看数据发现并不存在get与set方法。在查了文档后发现,Vue3中需要使用一个新的方法 `ref ` 去让数据变成响应式的。?

<template>
  <div class="main">
     <h1>我叫{{name}},我今年{{age}}了</h1>
     <button @click="changeInfo">修改</button>
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup () {
    let name = ref('黑猫几绛')
    let age = ref(20)
    function changeInfo() {
      name = '白猫',
      age = 99
    }
    return {
      name,
      age,
      changeInfo
    }
  }
}
</script>

话虽这么说,但是为数据添加上 ref 后点击按钮去修改信息,页面上并没有任何变化。为了找到出错的原因,在changeInfo之前先输出name与age试试。

原来经过ref加工后基本数据变成了一个对象,它是Ref(reference)Impl(implement)的实例对象。那我们可以考虑,如何拿到经过ref包装的引用实现的实例对象(即引用对象)中包含的数据。?

?我们将刚刚打印的内容展开来看,可以清晰的看到被包装的name属性是存在get和set的。如果想读到数据,那么就需要通过.value去获取,修改的话也需要这样。

 function changeInfo () {
    name.value = '白猫',
    age.value = 99
 }

在Vue3中,ref()方法是基于Object.defineProperty与get、set方法去实现的数据劫持。?

二、ref 包装对象数据类型数据

如果想对 ref 包装的数据进行处理,需要对数据.value后再操作,那么对于包装后的对象数据类型数据,也应当需要.value拿到具体对象数据。在Vue2中我们知道,即使一个对象中嵌套了多个对象,Vue都能通过循环遍历,从外到最深处设置响应式。

那么在Vue3中面对一个people对象的时候,我们是否需要在通过people.value拿到实例对象后,继续people.value.name.value去拿到姓名这个属性。

<template>
  <div class="main">
     <h3>{{people.name}},是{{people.type}}</h3>
     <button @click="changeInfo">修改</button>
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  // 最为原始的对象写法是这样,但是通过es6我们可以简写
  // setup: function(){}
  setup () {
    let people = ref({
      name: '黑猫几绛',
      type: '学生'
    })
    function changeInfo() {
      people.value.type.value = '打工人'    // 报错
      people.value.type = '打工人'          // 正常修改
    }
    return {
      changeInfo,
      people
    }
  }
}
</script>

也许在你心中是这么想的:将对象通过 ref 封装后,里面的value也需要进行ref封装,然后获取每一项value的时候都要调用具体的get与set方法。

经过打印后发现,其实是不需要的。通过第一次的.value后,获取对象中的数据便不需要再执行.value这个操作,直接调用即可。

不必再继续调用.value的原因在于 ref 检测到对象数据类型的数据时,当.value获取到了对象实例本身后,调用了另外一个方法 `reactive` 去包装{}内的数据,该方法是基于Proxy代理实现的。当我们直接用reactive去包裹数据对象的时候甚至可以省略第一个.value。

<script>
import {reactive} from 'vue'
export default {
  name: 'App',
  setup () {
    let people = reactive({
      name: '黑猫几绛',
      type: '学生'
    })
    function changeInfo() {
      // 这里直接通过people.type就能拿到对象元素数据
      people.type = '打工人'
    }
    return {
      changeInfo,
      people
    }
  }
}
</script>

三、Vue3响应式原理

在前面介绍过Vue3的ref函数是通过Object.defineProperty去实现响应式的,reactive则是通过proxy来实现。首先介绍一下它的优点

1. 可以直接为对象添加不存在的属性/删除属性

2. 可以直接通过索引下标去修改数组中的元素数据

不难看到,这恰好弥补了Vue2中响应式原理的缺陷https://blog.csdn.net/flow_camphor/article/details/120657910

在这里我们单独创建一个html文件,通过window.proxy去了解一下原理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        let people = {
           name: '黑猫几绛',
           type: '学生'
        }
        // proxy代理能够让p去映射people的操作与变化
        // 在看文档的时候proxy第二个参数写了许多东西
        // 这里我们先用一个空对象占位,其实就可以检测结果了
        const p = new Proxy(people,{})
    </script>
</body>
</html>

在控制台中测试后发现,通过改变p对象中元素的数据后,people中的数据也会得到改变。

?这样的实现叫做数据劫持,还不能称为响应式。我们接下来需要捕获到这样修改数据的行为。

const p = new Proxy(people,{
    // 读取p身上的某个属性时调用
    get(target,propName){
        // 这里通过[]获取元素的原因在于,Proxy中get方法的第二个参数
        // 返回的是一个字符串,对象无法通过 . 的方式使用字符串
        return target[propName]
    },
    // 修改p身上的某个属性、或者是给p追加某个属性时调用
    set(target,propName,value){
        target[propName] = value
    },
    // 删除p身上某个属性时调用
    deleteProperty(target,propName){
        return delete target[propName]
    }
})

?这样做实现了最为基础的响应式修改,但是这样太简洁了,其实并非Vue3中所使用的方法,接下来我们先看看一个新的知识点Reflect反射。这个是es6中新增的内容,其实现在ECMA正在尝试将Object中的内容全部移植到Reflect中,用Reflect代替Object是一个趋势,对于框架来说,直接通过一个对象去修改数据是可以轻松很多的,因此将上面的代码用Reflect替换。

const p = new Proxy(people,{
    // 读取p身上的某个属性时调用
    get(target,propName){
        return Reflect.get(target,propName)
    },
    // 修改p身上的某个属性、或者是给p追加某个属性时调用
    set(target,propName,value){
        Reflect.set(target,propName,value)
    },
    // 删除p身上某个属性时调用
    deleteProperty(target,propName){
        return Reflect.deleteProperty(target,propName)
    }
})
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:41:41  更:2021-10-15 11:43:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:18:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码