详解vue2和vue3如何定义响应式数据

 更新时间:2023年11月09日 14:33:59   作者:ashklwi  
这篇文章主要是来和大家一起讨论一下vue2和vue3是如何定义响应式数据的,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解下

响应式原理

Vue2和Vue3的响应式实现原理是不同的

  • Vue2底层是通过es5Object.defineProperty,使用Object.defineProperty()进行数据劫持,结合订阅发布的方式实现,有一定的局限性。
  • Vue3底层是通过es6Porxy, 通过Proxy代理,使用ref或者reactive将数据转化为响应式数据,能够更好地支持动态添加属性和删除属性。它解决了Vue2底层实现的缺点,对数组、层级比较深的对象处理都很优秀,但缺点是浏览器兼容不是很好。

Vue2的响应式数据

在Vue2中,是使用选项式API的方式来编写代码,比如data()、computed()、watch等方法实现响应式

Vue3的响应式数据

reactive和ref

reactive

reactive定义引用数据类型(以对象和数组举例),它能够将复杂数据类型的内部属性或者数据项声明为响应式数据,所以reactive的响应式是深层次的,其底层是通过ES6的Proxy来实现数据响应式,相对于Vue2的Object.defineProperty,具有能监听增删操作,能监听对象属性的变化等优点

  • reactive是一个函数,它可以定义一个复杂数据类型,成为响应式数据;
  • 通常用来定义响应式的对象数据。
<template>
  <div>name:{{obj.name}}</div>
  <button @click="updateName">修改name</button>
</template>
<script>
import { reactive } from 'vue'
export default {
    setup() {
        // 定义响应式对象
        const obj = reactive({
            name: 'lisi',
            age:20
        })
        const updateName = () => {
            obj.name = '我是修改后的name'
            console.log('我是按钮..........');
        };
        return {
            obj,
            updateName
        }
    }
}
</script>

ref函数

ref函数,常用于简单数据类型定义为响应式数据,其实也可以定义复杂数据类型的响应式数据,对于数据未知的情况下ref是最适用的。

在修改值,获取值的时候,需要.value。在模板中使用ref申明的响应式数据,可以省略.value,在js代码中修改ref声明的数据,需要加上.value。

<template>
  <div>name:{{name}}</div>
  <button @click="changeName">修改name</button>
</template>

<script>
import { ref } from 'vue'
export default {
    setup() {
        const name = ref('zhangsan');
        const changeName = () => {
            name.value = 'lisi'
        }
        return {
            name,
            changeName
        }
    }
} 
</script>

两者的不同

  • ref用于定义基本类型和引用类型,reactive仅用于定义引用类型
  • reactive只能用于定义引用数据类型的原因在于内部是通过ES6的Proxy实现响应式的,而Proxy不适用于基本数据类型
  • ref定义对象时,底层会通过reactive转换成具有深层次的响应式对象,所以ref本质上是reactive的再封装(会判断数据的类型进行不同处理)
  • 在脚本里使用ref定义的数据时,记得加.value后缀
  • 在定义数组时,建议使用ref,从而可避免reactive定义时值修改导致的响应式丢失问题
const tableData = reactive([]) // 定义
const getTableData = async () => {
	const { data } = await getTableDataApi() // 模拟接口获取表格数据
	tableData = data // 修改,错误示例,这样赋值会使tableData失去响应式
}

// 方法一:改为 ref 定义
const tableData = ref([])
const getTableData = async () => {
	const { data } = await getTableDataApi()
	tableData.value = data // 使用.value重新赋值
}
// 方法二:使用 push 方法
const tableData = reactive([])
const getTableData = async () => {
	const { data } = await getTableDataApi()
	tableData.push(...data) // 先使用...将data解构,再使用push方法
}
// 方法三:定义时数组外层嵌套一个对象
const tableData = reactive({ list:[] })
const getTableData = async () => {
	const { data } = await getTableDataApi()
	tableData.list = data // 通过访问list属性重新赋值
}
// 方法四:赋值前再包一层 reactive
const tableData = reactive([])
const getTableData = async () => {
	const { data } = await getTableDataApi()
	tableData = reactive(data) // 赋值前再包一层reactive
}

为什么需要两个

虽然ref函数既可以处理基本数据类型也可以处理引用数据类型,但是在普通js代码里修改该响应式数据的值时需要使用.value的写法,会存在.value的嵌套问题,因此使用reactive来处理引用数据类型,避免该问题。

toRef和toRefs

ref是对元数据的拷贝,修改响应式数据时不会影响之前的数据,视图会更新。tooRef和toRefs是对元数据的引用,修改响应式数据时,原数据也会改变,但是视图不会更新,只有原始数据改变后,该数据和视图都会更新。toRef修改的是对象的某个属性,toRefs修改的是整个对象

toRef

toRef 函数的作用:转换响应式对象中某个属性为单独响应式数据,并且转换后的值和之前是关联的(ref 函数也可以转换,但值非关联)。

<template>
  <div class="container">
      <h2>name: {{ obj.name }} age: {{obj.age}}</h2>
      <button @click="updateName">修改数据</button>
  </div></template><script>
  import { reactive } from 'vue'
  export default {
      name: 'App',
      setup() {
          const obj = reactive({
              name: '初映',
              age: 18,
              address: '江西',
              sex: '男',
          })
          const updateName = () => {
              obj.name = '初映CY的前说'
          }
          return { obj, updateName }
      },
  }</script>

这样写有几个问题:

  • 模板中都要使用 obj. 进行获取数据,较为麻烦
  • 明明模板中只用到了 name 和 age,却把整个 obj 进行了导出,没必要,性能浪费。

使用toRef进行修改,只需要将需要的属性return出去即好,且模板中也不需要加obj.前缀了。

<template>
  <div class="container">
      <h2>name: {{ name }} </h2>
      <button @click="updateName">修改数据</button>
  </div></template><script>
  import { reactive,toRef  } from 'vue'
  export default {
      name: 'App',
      setup() {
          const obj = reactive({
              name: '初映',
              age: 18,
              address: '江西',
              sex: '男',
          })
          const name = toRef(obj, 'name')
          const updateName = () => {
              obj.name = '初映CY的前说'
          }
          return { name, updateName }
      },
  }</script>

toRefs

toRefs 函数的作用:转换响应式对象中所有属性为单独响应式数据,并且转换后的值和之前是关联的。

<template>
<div>{{name}}</div>
<div>{{age}}</div>
<button @click="update">修改name</button>
</template>

<script>
import {reactive, toRefs} from 'vue'

export default {
    setup() {
        const obj = reactive({
            name: '张三',
            age:18
        })
        console.log(obj);

        const obj2 = toRefs(obj);
        console.log(obj2); //发现obj2里面的name和age都是响应式属性,指向obj的属性

        // 解构之后重新赋值的是普通对象
        const obj3 = { ...obj };
        console.log(obj3);

        const update =()=> {
            obj.name = '我是修改的原始数据的obj'
        }
        return {
            // 解构obj2,用的时候直接拿属性名,不需要obj2.name或obj2.age
            ...obj2,
            update
        }
    }
}
</script>

修改原始数据obj后会发现,转换过后的obj2中的值会跟着改变。

以上就是详解vue2和vue3如何定义响应式数据的详细内容,更多关于vue定义响应式数据的资料请关注脚本之家其它相关文章!

相关文章

  • 详解vue2路由vue-router配置(懒加载)

    详解vue2路由vue-router配置(懒加载)

    本篇文章主要介绍了详解vue2路由vue-router配置(懒加载),实例分析了vue-router懒加载的技巧,非常具有实用价值,需要的朋友可以参考下
    2017-04-04
  • Vue element树形控件添加虚线详解

    Vue element树形控件添加虚线详解

    这篇文章主要为大家介绍了Vue element树形控件添加虚线,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>
    2021-11-11
  • 解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题

    解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit(

    这篇文章主要介绍了vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效的解决方法,这里需要主要项目中用的element-ui是V1.4.3,感兴趣的朋友参考下吧
    2018-08-08
  • vue在外部方法给下拉框赋值后不显示label的解决

    vue在外部方法给下拉框赋值后不显示label的解决

    这篇文章主要介绍了vue在外部方法给下拉框赋值后不显示label的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • vue2中filter()的实现代码

    vue2中filter()的实现代码

    vue2.0里,不再有自带的过滤器,需要自己定义过滤器。下面通过实例代码给大家介绍vue2中filter()的相关知识,感兴趣的朋友一起看看吧
    2017-07-07
  • 解读Vue组件注册方式

    解读Vue组件注册方式

    无论是Vue还是React,都有组件的概念。组件,就是能和别人组合在一起的物件。在前端页面开发过程中,将一个页面划分成一个个小的模块,每个模块单独定义,每个模块就是一个组件。组件可以进行复用,A页面和B页面有一个相似的模块,可以抽离成一个可局部修改的组件。
    2021-05-05
  • 前端MVVM框架解析之双向绑定

    前端MVVM框架解析之双向绑定

    这篇文章主要介绍了MVVM 框架解析之双向绑定,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • vue2和vue3子组件父组件之间的传值方法

    vue2和vue3子组件父组件之间的传值方法

    在组件化开发的过程中难免会遇见子组件和父组件之间的通讯那么这里讲关于vue2和vue3不同的通讯方式,文中有详细的代码示例供大家参考,感兴趣的同学可以阅读下
    2023-05-05
  • Vue element-ui el-cascader 只能末级多选问题

    Vue element-ui el-cascader 只能末级多选问题

    这篇文章主要介绍了Vue element-ui el-cascader 只能末级多选问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue3中使用百度地图的简单步骤

    vue3中使用百度地图的简单步骤

    最近项目要用到百度地图api,好久没用到地图,就百度了一番,下面这篇文章主要给大家介绍了关于vue3中使用百度地图的简单步骤,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06

最新评论