Vue组合式API--setup中定义响应式数据的示例详解

目录
  • 一、Options API(选项式API)的弊端
    • 1.1 什么是选项式API
    • 1.2 选项式API的弊端
  • 二、Composition API(组合式API)概述
    • 2.1 Composition API的作用
    • 2.2 Composition API的编码位置
  • 三、setup函数的参数和返回值
    • 3.1 setup函数的参数
    • 3.2 setup函数的返回值
  • 四、setup中如何定义响应式数据
    • 4.1 reactive函数
    • 4.2 ref函数
    • 4.3 关于如何选择reactive函数和ref函数
  • 五、单向数据流和readonly的使用
    • 5.1 单向数据流规范
    • 5.2 readonly的使用
  • 六、Reactive相关的判断的API
  • 七、ref其他的API
    • 7.1 toRefs
    • 7.2 unref
    • 7.4 shallowRef
    • 7.5 triggerRef

一、Options API(选项式API)的弊端

1.1 什么是选项式API

Vue2.x中,编写组件的方式是使用Options API,它的特点是在对应的属性中编写对应的功能模块。

比如data中定义数据、methods中定义方法、computed中定义计算属性、watch中监听属性改变。

生命周期钩子也属于Options API(选项式API)。

1.2 选项式API的弊端

  • 当我们实现某一个功能时,这个功能对应的代码逻辑会被拆分到各个属性中。

当组件变得很大、很复杂时,逻辑关注点的列表就会增长,那么同一个功能的逻辑就会被拆分的很分散。

特别是对于那些一开始没有编写这些组件的人(阅读组件的人)来说,这个组件的代码是难以阅读和理解的。

  • 碎片化的代码使用理解和维护这个复杂的组件变得非常困难,很容易隐藏了潜在的逻辑问题。
  • 当处理单个逻辑关注点时,需要不断的跳到相应的代码块中,增加了代码维护的成本。

二、Composition API(组合式API)概述

2.1 Composition API的作用

如果能将同一个逻辑关注点相关的代码收集在一起会更好一些,这就是Composition API想 要做的事情。

Vue Composition API可以简称为VCA

2.2 Composition API的编码位置

Vue3.x提供了setup函数来编写各种组合式API

setup其实也是组件的另外一个选项,只不过这个选项可以用来替代大部分其他选项式API选项。

比如methodscomputedwatchdata、各种生命周期钩子函数等等。

三、setup函数的参数和返回值

3.1 setup函数的参数

setup函数主要由两个参数:

  • props:父组件传递过来的属性会被放到props对象中

    • props的类型,和选项式API中的的规则一样,在props选项中定义
    • props的使用,在template中依然是可以把props中的属性当成普通Vue变量去使用。
    • setup函数中用props,不可以通过this去获取
  • context:也称之为SetupContext,是setup函数的上下文对象,它主要由三个属性
    • attrs:所有的非props的的属性
    • slots:父组件传递过来的插槽,在以渲染函数返回时会有作用
    • emit:当组件内部需要发出事件时会用到emit
    • 主要是因为setup函数中不能访问this,所以无法通过this.$emit发出事件

3.2 setup函数的返回值

setup的返回值可以来替代data选项,因此setup的返回值可以在模板template中使用。

<script>
import { ref } from 'vue'

export default {
  setup() {
    // 定义counter的内容
    // 默认定义的数据都不是响应式数据,使用ref可以让数据变成响应式的
     let counter = ref(100)
     return {counter}
  }
}
</script>

setup的返回值可以来替代methods中定义的方法

<script>
import { ref } from 'vue'

export default {
  setup() {
    // 定义counter的内容
    // 默认定义的数据都不是响应式数据,使用ref可以让数据变成响应式的
    let counter = ref(100)
    const increment = () => {
       counter.value ++
       console.log(counter.value)
    }

	return {counter, increment}

  }
}
</script>

四、setup中如何定义响应式数据

4.1 reactive函数

代码示例:

<template>
  <div>
    <h2>账号: {{ account.username }}</h2>
    <h2>密码: {{ account.password }}</h2>
    <!-- 没使用reactive函数时,点击此按钮,能够修改数据,但是却不能渲染到页面上 -->
    <button @click="changeAccount">修改账号</button>
  </div>
</template>
<script>
  // 1.引入reactive函数
  import { reactive } from 'vue'

  export default {
    setup() {

      // 2.使用reactive函数: 定义复杂类型的响应式数据数据
      const account = reactive({
        username: "张三",
        password: "666666"
      })
      function changeAccount() {
        account.username = "kobe"
      }
	  // 3.返回定义的数据
      return {account, changeAccount}
    }
  }
</script>

由代码示例可知,使用reactive函数注意好三步即可:

  • Vue中引入reactive函数
  • 把要定义的复杂数据类型(对象或者数组)传入reactive函数,reactive函数的返回值就是响应式数据不要
  • 忘记在setup函数中返回才可以在模板上使用

为什么加了reactive函数后数据就变成了响应式的:

当我们使用reactive函数处理我们的数据之后,数据再次被使用时就会进行依赖收集。

当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作。

选项式API中的data选项中的复杂数据,在底层也是交给了reactive函数将其编程响应式对象的。

4.2 ref函数

1)ref函数的基本使用

reactive函数对传入的类型是有限制的,它要求必须传入的是一个对象或者数组类型。

如果传入一个基本数据类型,比如StringNumberBoolean等等就会报出一个警告:

value cannot be made reactive : xxx

Vue3给我们提供了另外一个ref函数。

ref函数返回可变的响应式对象,该对象作为一个 响应式的引用维护着它内部的值,这也是ref名称的来源。

它内部的值是在refvalue属性中被维护的,因此使用ref函数定义的变量,使用时需要从value属性取值。

代码示例:

<template>
  <div>
    <!-- 默认情况下在template中使用ref时, vue会自动对其进行解包(取出其中value) -->
    <h2>当前计数: {{ counter }}</h2>
    <button @click="increment">+1</button>
    <button @click="counter++">+1</button>
  </div>
</template>
<script>
  // 1.引入ref函数
  import { ref } from 'vue'

  export default {
    setup() {

      // 2.ref函数: 主要定义简单类型的数据(也可以定义复杂类型的数据)
      const counter = ref(0)
      function increment() {
        counter.value++
      }
	  // 3.返回定义的数据
      return {counter, increment}
    }
  }
</script>

2)ref浅层解包

<template>
  <div>
    <!--ref 浅层解包 (意思就是把ref变量放别的对象中时就会有下面两个情况)-->
    <!-- 使用的时候不需要写.value -->
    <h2>当前计数: {{ info.counter }}</h2>
    <!-- 修改的时候需要写.value -->
    <button @click="info.counter.value++">+1</button>
  </div>
</template>
<script>
  // 1.引入ref函数
  import { ref } from 'vue'

  export default {
    setup() {

      // 2.ref函数: 主要定义简单类型的数据(也可以定义复杂类型的数据)
      const counter = ref(0)
      const info = {counter}
	  // 3.返回定义的数据
      return {counter}
    }
  }
</script>

注意点:

  • 在模板中引入ref函数定义的值时,Vue会自动帮助我们进行解包操作
  • 解包就是Vue自动取出ref函数所定义的变量中的value
  • 所以使用者并不需要在模板中通过ref.value 的方式来使用
  • setup函数内部,ref函数定义的值是一个ref引用, 所以需要使用ref.value的方式去操作
  • 关于ref的浅层解包
  • 直接在template中使用ref变量,会进行自动解包
  • 如果把ref变量放在一个对象当中会有下面的情况
    • 使用时,会进行自动解包
    • 修改时,不会进行自动解包,因此需要使用value属性去获取值

4.3 关于如何选择reactive函数和ref函数

1)选择reactive函数的场景

  • reactive函数应用于本地的数据的定义,本地数据代表这个数据并不是来源于服务器
  • reactive函数定义的复杂数据的多个属性之间是有一定联系的
import {reactive} from 'vue'

const user = reactive({
	username: '张三',
	password: '123456'
})

例如收集一个表单中的数据,就是很适合使用reactive函数的场景

2)选择ref函数的场景

定义本地的简单类型的数据

import {ref} from 'vue'

const message = ref('hello ref')

定义从服务器中获取的数据

import {ref} from 'vue'

const music = ref([])							// 定义一个本地数组
const serverMusicList = ['小星星', '虫儿飞']		// 模拟从服务器获取到的数据
music.value = serverMusicList					// 把数据赋值给music变量

这是经验之谈,很多优秀的开源项目中也都是这么取做的,文档中并没有明确说明什么情况使用什么

这其实也是程序员本身应该自己去考虑的问题

五、单向数据流和readonly的使用

5.1 单向数据流规范

1)什么是单向数据流规范

父组件传递给子组件的对象数据,子组件只能使用,不允许修改。

虽然是能修改的,但是违反了单向数据流的原则。

如果真的想修改这个数据,应该发出事件,让父组件监听这个事件,然后在父组件中进行修改。

2)为什么要遵循这个原则

今后项目中可能会有很多子组件,父组件的一个数据可能会传递给多个子组件。

由于传递的是数据对象的引用,因此其中一个子组件中修改了数据,会导致全部引用它的地方,全部受到影响。

而且维护时,难以知道是哪个位置修改的这个数据。

其它地方也有很多类似的概念规范:

  • react
  • react有一个重要的原则:任何一个组件都应该像纯函数一样,不能修改传入的props
  • js
  • js中也有类似原则,熟悉js的可能会知道一个纯函数的概念。纯函数意思就是函数不要对传入的参数进行修改。

这些规范如果不遵守,代码确实也能实现功能。但是将来维护性将会非常差,谁试谁知道。

5.2 readonly的使用

在给组件传递数据时,如果希望组件使用传递的内容。但是不允许它们修改时,就可以使用readonly了。

因为单向数据流原则在Vue2.x的时候时没法从代码上避免的。如果一个程序员根本不知道这个原则。

就有可能写出难以维护的代码。

Vue3.x则提供了readonly函数从编码层面去避免这个问题。

<template>
	<!-- 给组件home传递一个只读数据 -->
	<home :info="readonlyInfo" />
</template>
<script>
    import { readonly } from 'vue'
    setup() {
      // 本地定义多个需要传递给子组件的数据
      const info = reactive({
        name: "张三",
        age: 25,
        height: 1.78
      })

      // 使用readOnly包裹info
      const roInfo = readonly(info)
      return {roInfo}
    }
</script>

readonly返回的对象都是不允许修改的;但是经过readonly处理的原来的对象是允许被修改的。

比如 对于语句const info = readonly(obj)info对象是不允许被修改的。

obj被修改时,readonly返回的info对象也会被修改;

但是我们不能去修改readonly返回的对象info

如果代码本身就非常遵守单向数据流的原则,那么也可以不使用

readonly的其它注意点:

  • readonly会返回原始对象的只读代理
  • 也就是它依然是一个Proxy,这是一个proxyset方法被劫持,并且不能对其进行修改
  • 在开发中常见的readonly方法会传入三个类型的参数:
  • 类型一:普通对象
  • 类型二:reactive返回的对象
  • 类型三:ref的对象

六、Reactive相关的判断的API

  • isProxy:检查对象是否是由 reactivereadonly创建的 proxy
  • isReactive: 检查对象是否是由reactive创建的响应式代理
  • 如果该代理是 readonly 建的,但包裹了由 reactive 创建的另一个代理,它也会返回 true
  • isReadonly:检查对象是否是由 readonly 创建的只读代理。
  • toRaw :返回reactivereadonly 代理的原始对象(不建议保留对原始对象的持久引用。请谨慎使用)
  • shallowReactive: 创建一个响应式代理,它跟踪其自身property的响应性

但不执行嵌套对象的深层响应式转换 (深层还是原生对象)。

shallowReadonly: 创建一个proxy,使其自身的property为只读

但不执行嵌套对象的深度只读转换(深层还是可读、可写的)

这些用的可能不会很多,但是也要了解

七、ref其他的API

7.1 toRefs

使用ES6的解构语法,对reactive返回的对象进行解构获取值,数据将不再是响应式的。

const info = reactive({
    name: "张三",
    age: 25,
    height: 1.78
})

ES6解构:

const {name, age, height} = info;

数据失去响应式

toRefs解构:

const {name, age, height} = toRefs(info);

解构后数据仍然保持响应式

7.2 unref

用于获取一个ref引用中的value

  • 如果参数是一个ref,则返回内部值,否则返回参数本身
  • 这也是 val = isRef(val) ? val.value : val 的语法糖函数 7.3 isRef

判断值是否是一个ref对象。

7.4 shallowRef

创建一个浅层的ref对象。

7.5 triggerRef

手动触发和shallowRef创建对象的响应式。

到此这篇关于Vue组合式API--setup中定义响应式数据详解的文章就介绍到这了,更多相关Vue组合式API setup内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue组合式API浅显入门示例详解

    目录 正文 组合式API setup 变量声明 目前比起选项式API的优点 生命周期 正文 在react推出了hook之后,vue也在vue3里面添加了组合式API,鉴于这个时间间隔,我有理由认为组合式api和hook还是有一些关系的.不过在我具体的使用中,我并没发现这两个方法太多的相同点,不过鉴于vue自动发布之后就与react之间那剪不断理还乱的量子力学关系,估计会有很多人会问及这俩之间的异同.我还没到能分辨出异同的地步,就简单的介绍一下vue的组合式API吧. 组合式API 在vue3.0

  • 一文详解Vue选项式 API 的生命周期选项和组合式API

    目录 Vue2.Vue3 生命周期的变化 选项式 API 的生命周期选项的变化 小知识 组合式 生命周期选项 API VNode 生命周期事件 Vue2x Vue3x Vue2.Vue3 生命周期的变化 正好在看Vue的官方文档,也正好比对一下,做一下笔记 选项式 API 的生命周期选项的变化 Vue2.x Vue3 beforeCreate beforeCreate created created beforeMount beforeMount mounted mounted beforeUp

  • vue3-组合式api-provide/inject详解

    目录 一.父组件 二.子组件 三.孙组件 四.运行项目界面效果如下 Vue3:组合式API-依赖注入(provide().inject()) 1.provide() 2.inject() provide/inject 适用于跨级通信,例如在父组件中改变值,在孙组件中通过依赖注入的方式能获取到父组件中改变的这个值 一.父组件 <template> <div> <!-- 子组件 --> <son></son> <button @click=&q

  • vue3组合式api实现v-lazy图片懒加载的方法实例

    目录 前置知识 Intersection Observer Vue3指令周期 image对象 思路 完整代码 总结 前置知识 Intersection Observer 浏览器提供api,用于检测目标元素和祖先元素/顶级文档视窗 (viewport) 交叉状态的方法. const observer = new IntersectionObserver(function (IntersectionObserverEntry) {},options); observer.observe(el); 构

  • vue  composition-api 封装组合式函数的操作方法

    目录 介绍 最佳实践 1. options对象化 2. 动态返回 3. 灵活地使用ref 4. 异步变同步 5. 简单的状态管理 参考资料 介绍 在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数. 组合式函数 | Vue.js 组合式 API 常见问答 | Vue.js Composables 函数就是利用 Vue3 提出的 Composition API ,封装出的一些可以复用的组合式函数,目前 Vue2 也

  • Vue响应式原理的示例详解

    Vue 最独特的特性之一,是非侵入式的响应系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.聊到 Vue 响应式实现原理,众多开发者都知道实现的关键在于利用 Object.defineProperty , 但具体又是如何实现的呢,今天我们来一探究竟. 为了通俗易懂,我们还是从一个小的示例开始: <body> <div id="app"> {{ message }} </div> <script> v

  • vue组件中使用props传递数据的实例详解

    在 Vue 中,父子组件的关系可以总结为 props向下传递,事件向上传递.父组件通过 props 给子组件下发数据,子组件通过事件给父组件发送消息.看看它们是怎么工作的.  一.基本用法 组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信. 在组件中,使用选项props 来声明需要从父级接收的数据, props 的值可以是两种, 一种是字符串数组,一种是对象. 1.1 字符串数组: <div id="app4"> <my-component4 messa

  • Bootstrap 响应式实用工具实例详解

    Bootstrap 提供了一些辅助类,以便更快地实现对移动设备友好的开发.这些可以通过媒体查询结合大型.小型和中型设备,实现内容对设备的显示和隐藏. 需要谨慎使用这些工具,避免在同一个站点创建完全不同的版本.响应式实用工具目前只适用于块和表切换. 实例 下面的实例演示了上面所列举的帮助器类的用法.调整浏览器的窗口大小,或者在不同的设备上加载实例,测试响应式实用工具类. <div class="container" style="padding: 40px;"&

  • Vue3中Vuex状态管理学习实战示例详解

    目录 引言 一.目录结构 二.版本依赖 三.配置Vuex 四.使用Vuex 引言 Vuex 是 Vue 全家桶重要组成之一,专为 Vue.js 应用程序开发的 状态管理模式 + 库 ,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 一.目录结构 demo/ package.json vite.config.js index.html public/ src/ api/ assets/ common/ components/ store/ index.

  • 详解Python中生成随机数据的示例详解

    目录 随机性有多随机 加密安全性 PRNG random 模块 数组 numpy.random 相关数据的生成 random模块与NumPy对照表 CSPRNG 尽可能随机 os.urandom() secrets 最佳保存方式 UUID 工程随机性的比较 在日常工作编程中存在着各种随机事件,同样在编程中生成随机数字的时候也是一样,随机有多随机呢?在涉及信息安全的情况下,它是最重要的问题之一.每当在 Python 中生成随机数据.字符串或数字时,最好至少大致了解这些数据是如何生成的. 用于在 P

  • vue3中的透传attributes教程示例详解

    目录 引言 绑定样式 对象 数组 透传的attributes 透传 attributes 之样式绑定 透传 attributes 之事件绑定 特殊1:组件嵌套 特殊2:禁用透传attributes 特殊3:在 javascript 中访问透传的attributes 总结 引言 最近两年都是在使用 react 进行项目开发,看技术博客都是针对 react 和 javaScript 高级方面的,对 vue 的知识基本上遗忘的差不多了.最近开始慢慢回顾 vue 的知识以及对新的语法进行学习,为后面的计

  • python中前缀运算符 *和 **的用法示例详解

    这篇主要探讨 ** 和 * 前缀运算符,**在变量之前使用的*and **运算符. 一个星(*):表示接收的参数作为元组来处理 两个星(**):表示接收的参数作为字典来处理 简单示例: >>> numbers = [2, 1, 3, 4, 7] >>> more_numbers = [*numbers, 11, 18] >>> print(*more_numbers, sep=', ') 2, 1, 3, 4, 7, 11, 18 用途: 使用 * 和

  • Python中八大图像特效算法的示例详解

    目录 0写在前面 1毛玻璃特效 2浮雕特效 3油画特效 4马赛克特效 5素描特效 6怀旧特效 7流年特效 8卡通特效 0 写在前面 图像特效处理是基于图像像素数据特征,将原图像进行一定步骤的计算——例如像素作差.灰度变换.颜色通道融合等,从而达到期望的效果.图像特效处理是日常生活中应用非常广泛的一种计算机视觉应用,出现在各种美图软件中,这些精美滤镜背后的数学原理都是相通的,本文主要介绍八大基本图像特效算法,在这些算法基础上可以进行二次开发,生成更高级的滤镜. 本文采用面向对象设计,定义了一个图像

  • vue+three.js实现炫酷的3D登陆页面示例详解

    目录 前言: Three.js的基础知识 关于场景 关于光源 关于相机(重要) 关于渲染器 完善效果 创建一个左上角的地球 使地球自转 创建星星 使星星运动 创建云以及运动轨迹 使云运动 完成three.js有关效果 结语 前言: 大家好,我是xx传媒严导(xx这两个字请自行脑补) . 该篇文章用到的主要技术:vue3.three.js 我们先看看成品效果: 高清大图预览(会有些慢): 座机小图预览: 废话不多说,直接进入正题 Three.js的基础知识 想象一下,在一个虚拟的3D世界中都需要什

  • JS前端中的设计模式和使用场景示例详解

    目录 引言 策略模式 1.绩效考核 2.表单验证 策略模式的优缺点: 代理模式 1.图片懒加载: 2.缓存代理 总结 引言 相信大家在日常学习和工作中都多多少少听说/了解/使用过 设计模式,我们都知道,使用恰当的设计模式可以优化我们的代码,那你是否知道对于前端开发哪些 设计模式 是日常工作经常用到或者必须掌握的呢?本文我将带大家一起学习下前端常见的设计模式以及它们的 使用场景!!! 本文主讲: 策略模式 代理模式 适合人群: 前端人员 设计模式小白/想知道如何在项目中使用设计模式 策略模式 策略

随机推荐