十二、组合API(2)

news2024/11/28 0:29:25

本章概要

  • 响应式 API
    • reactive() 方法
    • watchEffect() 方法
    • 解构响应性状态
    • 深入 watchEffect()
    • ref
    • readonly
    • computed
    • watch

11.3 响应式 API

Vue 3.0 的核心功能主要是通过响应式 API 实现的,组合 API 将他们公开为独立的函数。

11.3.1 reactive() 方法

reactive() 方法可以对一个 JavaScript 对象创建响应式状态。在 HTML 页面中,可以编写如下代码:

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 响应式状态
  const state = Vue.reactive({
    count:0
  })
</script>

在但文件组件中,可以编写如下代码:

import { reactive } from 'vue'
// 响应式状态
const state = reactive({
  count:0
})

reactive() 方法相当于 Vue 2.x 中的 Vue.observable() 方法。

11.3.2 watchEffect() 方法

上述代码返回的 state 是一个响应式对象,可以在渲染期间使用它。由于依赖关系的跟踪,当 state 对象发生变化时,视图会自动更新。
在 DOM 中渲染内容被认为是一个“副作用”,要应用和自动重新应用基于响应式的 state 对象,可以使用 watchEffect API 。
完整代码如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { reactive, watchEffect } = Vue;
        const state = reactive({
            count: 0
        })

        watchEffect(() => {
            document.body.innerHTML = `count is ${state.count}`
        })
    </script>
</body>

</html>

watchEffect() 方法接收一个函数作为参数,它会立即运行该函数,同时响应式的跟踪其依赖项,并在依赖项发生更改时重新运行该函数。watchEffect() 方法类似于 Vue 2.x 中的 watch 选项,但是她不需要分离监听的数据源和副作用回调。组合 API 还提供了一个 watch() 方法,其行为与 Vue 2.x 中的 watch 选项完全相同。

在谷歌浏览器中打开上述页面,页面中初始显示内容为:count is 0,在浏览器的 Console 窗口 输入:state.count = 1 ,会发现页面内容同时发生了更新。如下:
在这里插入图片描述

11.3.3 解构响应性状态

当要使用一个较大的响应式对象的一些属性时,可能会考虑使用 ES6 的对象解构语法获得想要的属性。如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <div id="app">
        <p>作者:{{author}}</p>
        <p>书名:{{title}}</p>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { reactive, toRefs } = Vue;
        const app = Vue.createApp({
            setup() {
                const book = reactive({
                    author: '吴承恩',
                    year: '2022',
                    title: '西游记',
                    description: '师徒四人打怪升级的故事',
                    price: '222'
                })
                let { author, title } = book;
                return {
                    author,
                    title
                }
            }
        })
        const vm = app.mount('#app');
    </script>
</body>

</html>

但是通过这种解构,author 和 title 的响应性将丢失,在 Chrome 浏览器的 Console 窗口修改 vm.author 或 vm.title,就会发现页面内容并没有被更新。如下:
在这里插入图片描述

遇到这种情况,需要将响应式对象转换为一组 ref,这些 ref 将保留到源对象的响应式连接。这个转换是通过调用 toRefs() 方法完成的,该方法将响应式对象转换为普通对象,其中结果对象上的每个属性都是指向原始对象中相应属性的 ref。
修改上述代码,如下:

let { author, title } = toRefs(book);

再次修改 vm.author 或 vm.title ,可以发现页面内容也随着更新了,如下:
在这里插入图片描述

Vue 3.0 中还有一个 toRef() 方法,改方法是为响应式源对象的某个属性创建 ref,然后可以传递这个 ref ,并保持对其源属性的响应性连接。修改上述代码,调用 toRef() 方法分别为 book 对象的 author 和 title 属性创建 ref 对象。如下:

const { reactive, toRef } = Vue;
const app = Vue.createApp({
    setup() {
        const book = reactive({
            author: '吴承恩',
            year: '2022',
            title: '西游记',
            description: '师徒四人打怪升级的故事',
            price: '222'
        })
        const author = toRef(book,'author');
        const title = toRef(book,'title');
        return {
            author,
            title
        }
    }
})
const vm = app.mount('#app');

当把一个 prop 的 ref 传递给组合函数时,toRef() 方法就很有用了。如下:

export default {
    setup(props){
        useSomeFeature(toRef(props,'foo'))
    }
}

11.3.4 深入 watchEffect()

当 watchEffect() 方法在组件的 setup() 函数或生命周期钩子中被调用时,监听器(watcher)被链接到组件的声明周期中,并在组件卸载(unmounted)时自动停止。在其它情况下,watchEffect() 方法返回一个停止句柄,可以调用该句柄显示地停止监听器。如下:

const stop = watchEffect(() => {
  //...
})
// 之后想要停止监听器,可以调用 stop() 函数
stop()

有时候,watchEffect() 方法将执行异步副作用,当它失效时,需要清除这些副作用。例如,在副作用完成之前状态发生了改变,watchEffect() 方法可以接收一个 onInvalidate() 函数,该函数可用于注册一个无效回调,无效回调将在下面两种情况发生时被调用:

  • 副作用将再次运行
  • 监听器被停止(例如,如果在组件的 setup() 函数或生命周期钩子中使用 watchEffect() 函数,则当组件被卸载时停止)

看如下代码:

watchEffect(onInvalidate => {
  const token = performAsyncOperation(id.value)
  onInvalidate(() => {
    // id 已更改或监听器已停止时,取消挂起的异步操作
    token.cancel()
  })
})

在执行数据抓取时,effect() 函数(即副作用)通常是异步函数。代码如下:

const data = ref(null);
watchEffect(async() => {
  // 在 Promise解析之前注册清理函数
  onInvalidate(() => {...})
  data.value = await fetchData(props.id)
})

异步函数隐式地返回一个 Promise ,但是清理函数需要在 Promise 解析之前立即注册。此外,Vue 依赖返回的 Promise 来自动处理 Promise 链中的潜在错误。
看以下代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <div id="app">{{ count }}</div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { ref, watchEffect } = Vue;
        const vm = Vue.createApp({
            setup() {
                const count = ref(0);
                watchEffect(() => {
                    console.log(count.value);
                })
                    return {
                    count
                }
            }
        }).mount('#app');
    </script>
</body>

</html>

当初始运行时,将同步记录 count 值,之后当 count 发生变化后,传入 watchEffect() 方法的回调函数会在组件更新后被调用。需要注意的是,第一次运行时在挂载组件之前执行的,如果想要在一个监听的 effect() 函数中访问 DOM 模板的 ref ,则需要在 mounted 钩子中执行 watchEffect() 方法。如下:

onMounted(() => {
  watchEffect(() => {
    // 访问DOM 或模板的 ref
  })
})

在需要同步或在组件更新之前重新运行监听的 effect() 函数的情况下,可以给 watchEffect() 方法传递一个附加的选项对象,在选项对象中使用 flush 选项,该选项的默认值为 ‘post’,即在组件更新后在此运行监听的 effect() 函数。

// 同步触发
watchEffect(
  () => {
    // ...
  },
  {
    flush:'sync'
  }
)
// 在组件更新之前触发
watchEffect(
  () => {
    // ...
  },
  {
    flush:'pre'
  }
)

11.3.5 ref

reactive() 方法为一个 JavaScript 对象创建响应式代理,如果需要对一个原始值(如字符串)创建响应式代理对象,一种方式是将该原始值作为某个对象的属性,调用 reactive() 方法为该对象创建响应式代理对象,另一种方式就是使用 Vue 给出的另一个方法 ref ,该方法接收一个原始值,返回一个响应式和可改变的 ref 对象,返回的对象只有一个 value 属性指向内部值。
看以下代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { ref, watchEffect } = Vue;
        const state = ref(0)

        watchEffect(() => {
            document.body.innerHTML = `count is ${state.value}`
        })
    </script>
</body>

</html>

此时取值需要访问 state 对象的 value 属性。当 ref 作为渲染上下文中的属性返回(从 setup 返回的对象)并在模板中访问时,它将自动展开为内部值,不需要在模板中添加 .value。代码如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <div id="app">
        <span>{{ count }}</span>
        <button @click="count ++">Increment count</button>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { ref } = Vue;
        const app = Vue.createApp({
            setup() {
                const count = ref(0);
                return {
                    count
                }
            }
        })
        app.mount('#app')
    </script>
</body>

</html>

当 ref 作为响应式对象的属性被访问或更改时,它会自动展开为内部值,其行为类似于普通属性。如下:

  const count = ref(0)
  const state = reactive({
      count
  })
  console.log(state.count); //0
  state.count = 1;
  console.log(count.value); //1

ref 展开仅在嵌套在响应式对象内时发生,当从数组或本地集合类型(如 Map)中访问 ref 时,不会执行展开操作。如下:

const books = reactive([ref('你好')])
// 需要添加 .value
console.log(books[0].value)

const map = reactive(new Map([['count',ref(0)]]))
// 需要添加 .value
console.log(map.get('count').value);

11.3.6 readonly

有时候希望跟踪响应对象(ref 或 reactive)的变化,但还希望阻止从应用程序的某个位置对其进行更改。
例如,有一个提供的响应式对象时,想要防止它在注入的地方发生更改,为此,可以为原始对象创建一个只读代理。如下:

import { reactive,readonly } from 'vue'
const original = reactive({ count : 0})
const copy = readonly(original)
// 改变original将触发依赖 copy 的观察者
original.count++
// 修改copy 将失败并导致警告
copy.count++

11.3.7 computed

computed() 方法与 computed 选项作用一样,用于创建依赖于其它状态的计算属性,该方法接收一个 getter 函数,并为 getter 返回的值返回一个不可变的响应式 ref 对象。如下:

const count = ref(1)
const plusOne = computed(() => count.value+1) 
console.log(plusOne.value) //2
plusOne.value++ // error

使用 组合API 实现反转字符串:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
</head>

<body>
    <div id="app">
        <p>原始字符串: {{ message }}</p>
        <p>计算后的反转字符串: {{ reversedMessage }}</p>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { ref, computed } = Vue;
        const vm = Vue.createApp({
            setup() {
                const message = ref('你好,世界!');
                const reversedMessage = computed(() =>
                    message.value.split('').reverse().join('')
                );
                return {
                    message,
                    reversedMessage
                }
            }
        }).mount('#app');
    </script>
</body>

</html>

与 computed 选项一样,computed() 方法也可以接受一个带有 get() 和 set() 函数的对象来创建一个可写的 ref 对象。如下:

const count = ref(1)
const plusOne = computed({
  get:() => count.value + 1,
  set:() => {
    count.value = val -1
  }
})
plusOne.value = 1
console.log(count.value) //0

另一个示例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>计算属性的getter和setter</title>
</head>

<body>
    <div id="app">
        <p>First name: <input type="text" v-model="firstName"></p>
        <p>Last name: <input type="text" v-model="lastName"></p>
        <p>{{ fullName }}</p>
    </div>

    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const { ref, computed } = Vue;
        const vm = Vue.createApp({
            setup() {
                const firstName = ref('Smith');
                const lastName = ref('Will');
                const fullName = computed({
                    get: () => firstName.value + ' ' + lastName.value,
                    set: val => {
                        let names = val.split(' ')
                        firstName.value = names[0]
                        lastName.value = names[names.length - 1]
                    }
                });
                return {
                    firstName,
                    lastName,
                    fullName
                }
            }
        }).mount('#app');
    </script>
</body>

</html>

11.3.8 watch

watch() 方法等同于 Vue 2.x 的 this.$watch()方法,以及相应的 watch 选项。watch() 方法需要监听特定的数据源,并在单独的回调函数中应用副作用。默认情况下,它也是惰性的,即只有当被监听的数据发生变化是,才会调用回调函数。
与 watchEffect() 方法相比,watch() 方法有以下功能:

  • 惰性的执行副作用
  • 更具体的说明什么状态应该触发监听器重新运行
  • 访问被监听状态的前一个值和当前值

watch() 与 watchEffect() 方法共享行为,包括手动停止、副作用失效(将 onInvalidate 作为第 3 个参数传递给回调)、刷新时间和调试。
监听的数据源可以是返回值的 getter 函数,也可以是直接的 ref 对象。如下:

const state = reactive({ count : 0 })
// 监听返回值的 getter 函数
watch(
  () => state.count,
  (count,prevCount) => {
    // ...
  }
)

// 直接监听一个 ref 对象
watch(count,(count,prevCount) => {
  // ...
})

监听器还可以使用数组同时监听多个数据源,如下:

watch([fooRef,barRef],([foo,bar],[prevFoo,prevBar]) => {
  // ...
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于物联网的自动灌溉系统的设计与实现

本设计是基于物联网的自动灌溉系统&#xff0c;主要实现以下功能&#xff1a; 1&#xff0c;OLED显示温湿度和土壤温湿度&#xff1b; 2&#xff0c;可通过继电器实现自动灌溉和自动加热的功能&#xff1b; 3&#xff0c;通过lora构建自组网&#xff0c;进行主从机间的数据传输…

正点原子 核心板IMX6ULL IIC RTC驱动 PCF8563

目录前言IIC RTC PCF8563硬件使用IIC设备地址配置 menuconfig 自带PCF8563驱动修改设备树dtb编写应用App测试前言 此篇基于学完【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6 后&#xff0c;使用核心板进行自行设置。 IIC RTC PCF8563硬件使用 Imx6ul内部的RTC时钟不是很准…

VMware Workstation虚拟机网络相关配置

1、网络配置 1.1、方式一&#xff1a;配置文件 配置文件&#xff1a;网络参数之IP地址与子网掩码、网关地址、DNS 1.1.1、删除旧网卡配置文件 rm -rf /etc/sysconfig/network-scripts/ifcfg-* 1.1.2、grub内核引导程序&#xff0c;定义网卡重新命名规则 vim /etc/default/…

若依vue ruoyi-vue ant design版本使用

若依vue默认是使用element ui的&#xff0c;但是现在大部分项目都用ant design&#xff0c;ant design的组件也比element多&#xff0c;所以最近有想更改成ant design。网上搜了一下&#xff0c;已经有现成的了。 RuoYi-Antdv https://gitee.com/fuzui/RuoYi-Antdv RuoYi-Ant…

【scala】第二章——Scala 变量和数据类型

文章目录1 注释2 变量和常量&#xff08;重点&#xff09;3 标识符的命名规范4 字符串输出5 键盘输入6 数据类型&#xff08;重点&#xff09;7 整数类型&#xff08;Byte、Short、Int、Long&#xff09;8 浮点类型&#xff08;Float、Double&#xff09;9 字符类型&#xff08…

1秒钟搞懂tee和vim文件的使用命令(超级详细)

1秒钟搞懂tee和vim文件的使用命令&#xff08;超级详细&#xff09;一&#xff0c;tee的具体使用1&#xff0c;tee用来显示屏幕并且保存在文件中2&#xff0c;&#xff08;|&#xff09;管道符用来覆盖上一文件内容3&#xff0c;-a用来追加文件内容二&#xff0c;vim的命令模式…

[附源码]计算机毕业设计JAVA教室用电控制系统

[附源码]计算机毕业设计JAVA教室用电控制系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

如何把图片文字转换成文字?图片转文字方法推荐

我们在上课的时候&#xff0c;常常会跟不上老师的板书&#xff0c;这时候我们就会对一些来不及记录的板书&#xff0c;拍成图片保存下来&#xff0c;等到课后再进行整理。可是当图片积累的过多的时候&#xff0c;再一张一张的进行抄写&#xff0c;就会很浪费时间和精力了。但其…

诚邀莅临 | 天奥智能参展第86届中国国际医疗器械博览会

11月23-26日&#xff0c;第86届中国国际医疗器械博览会&#xff08;CMEF&#xff09;在深圳国际会展中心&#xff08;宝安新馆&#xff09;隆重举办。本届大会以“创新科技、智领未来”为主题&#xff0c;吸引了超过4000家国内外医疗器械、医用耗材、医疗机器人等企业参会。 南…

机器学习参数|数学建模|自相关性

目录 1.定义和影响 1.1自相关性产生的原因 1.2自相关的后果 2.减小影响方法 2.1如何判断数据存在自相关性 a.用相关计量软件 b.Durbin-Watson Statistics(德宾-瓦特逊检验) c.Q-Statistics 以(box-pierce)- Eviews(7th version第七版本)为例子 2.2如何减弱模型的自相关…

pytorch使用GPU加速--windows11,GTX1650Super

使用的都是anaconda创建的环境 1.软件准备 下载cuda 查看自己的显卡驱动–进入NVIDIA的控制面板 然后根据显卡驱动下载对映的cuda 查看的网址 下载cuda的网址 下载cuDNN NVIDIA cuDNN是用于深度神经网络的GPU加速库。它强调性能、易用性和低内存开销。 cudnn下载网址 这个下…

使用CAPL 内置函数 memcpy 和memcmp 处理数组的若干问题

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

树状数组学习

树状数组简介 树状数组&#xff0c;用于维护和查询前缀和&#xff0c;与线段树功能类似。树状数组代码短&#xff0c;常数和空间小&#xff0c;时间复杂度小&#xff0c;所以这也是一个十分优秀的算法。 设a[i]a[i]a[i]为原数组上的点&#xff0c;s[i]s[i]s[i]为树状数组中各点…

WordPress管理仪表板:在15分钟内成为WordPress专家

WordPress管理仪表板是内容管理系统 (CMS)的核心和灵魂。在这里&#xff0c;您可以监督网站的各个方面&#xff0c;从配置基本设置到发布内容、安装插件和主题等等。如果您不熟悉 WordPress 管理仪表板&#xff0c;您将很难管理网站。 了解如何使用仪表板比您想象的要容易。所有…

PixiJs学前篇(三):Canvas基础【下篇】

前言 在上一篇文章 PixiJs学前篇&#xff08;二&#xff09;&#xff1a;Canvas基础【中篇】 中我们了解了Canvas的基本绘制形状&#xff0c;接下来我们看一下如何在 Canvas 中绘制文本。 绘制文本 文本的绘制也是 Canvas 中也是比较常见的&#xff0c;在 Canvas 的绘制中&a…

STC51单片机36——51单片机简单分两路控制步进电机

按键控制步进电机正反转一定设置的角度&#xff0c;比如一圈360度&#xff0c;按一次30度&#xff0c;一起12档。分两路控制&#xff0c;4个加减按键&#xff0c;一个按键控制复位&#xff0c;每路控制输出tb6600驱动器驱动两个42电机同步。同时数码管显示出来每次按键加减后的…

FastDFS(分布式文件管理系统)

一、简介 解决了大容量的文件存储和高并发访问的问题&#xff0c;文件存取时实现了负载均衡。 FastDFS服务端只有两个角色&#xff0c;tracker server和storage server。 所有同角色服务器集群节点都是平等的&#xff0c;不存在主从关系&#xff08;Master-Slave&#xff09;…

golang爬虫练习-抓取行业信息分类

抓取框架介绍 gathertool gathertool是golang脚本化开发库&#xff0c;目的是提高对应场景程序开发的效率&#xff1b;轻量级爬虫库&#xff0c;接口测试&压力测试库&#xff0c;DB操作库等。 地址&#xff1a; https://github.com/mangenotwork/gathertool 下载: go get …

醛肽:Gly-Phe-Gly-aldehyde、102579-48-6

可逆组织蛋白酶 B 抑制剂 GFG-醛缩氨基脲已用于通过亲和层析从日本血吸虫中纯化组织蛋白酶 B 样蛋白酶 Sj31&#xff0c;并用于从疟原虫物种中分离恶性疟原虫。编号: 200138 中文名称: 三肽Gly-Phe-Gly-aldehyde CAS号: 102579-48-6 单字母: H2N-GFG-CHO 三字母: H2N-Gly-Phe-G…

Docker网络管理

目录 一、Docker 网络实现原理 二、Docker 的网络模式 1.四种网络模式 2.各网络模式详解 &#xff08;1&#xff09;Host模式 &#xff08;2&#xff09;Container模式 &#xff08;3&#xff09;None模式 &#xff08;4&#xff09;Bridge模式 3.指定容器网络…