Vue 入门到实战 八

8章 组合API与响应性

目录

8.1 响应性

8.1.1 什么是响应性

8.1.2 响应性原理

8.2 为什么使用组合API

8.3 setup组件选项

8.3.1 setup函数的参数

8.3.2 setup函数的返回值

8.3.3 使用ref创建响应式引用

8.3.4 setup内部调用生命周期钩子函数

8.4 提供/注入

8.4.1 provide方法

8.4.2 inject方法

8.5 模板引用

8.6 响应式计算与侦听

8.6.1 响应式计算

8.6.2 响应式侦听


8.1 响应性

8.1.1 什么是响应性

响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。Vue.js如何追踪数据的变化呢?在生成Vue.js实例时,使用带有gettersetter的处理程序遍历传入的data,将其所有property转换为Proxy对象。Proxy代理对象,顾名思义,在访问对象前增加一个中间层,通过中间层做一个中转,通过操作代理对象,实现目标对象的修改。Proxy对象对于用户来说是不可见的,但在内部,它使Vue.js能够在property值被访问或修改的情况下进行依赖跟踪和变更通知。

8-1】property转换为Proxy对象。

<script>const data = {uname: 'chenheng',age: 90}const handler = {get(target, name, receiver) {alert('执行get方法')//Reflect.get 方法查找并返回 target 对象的 name 属性,如果没有该属性,则返回 undefinedreturn Reflect.get(...arguments)},set(target, name, value, receiver) {alert('执行set方法')//Reflect.set 方法设置 target 对象的 name 属性等于 value。return Reflect.set(...arguments)}}const proxy = new Proxy(data, handler)alert(proxy.uname)    //执行get方法proxy.uname = 'hhhhh' //执行set方法alert(proxy.uname)    //执行get方法
</script>

target

要包装的目标对象Proxy。它可以是任何类型的对象,包括本机数组,函数甚至其他代理

handler

一个对象,其属性是定义对代理p执行操作时的行为的函数

proxy监听数组

 proxy可以监听属性的新增删除操作

proxy监听深层次嵌套对象

8.1.2 响应性原理

reactive()方法和watchEffect()方法是Vue3中响应式的两个核心方法,reactive()方法负责将数据变成响应式代理对象,watchEffect()方法的作用是监听数据变化去更新视图或调用函数。

8-2】reactive()方法和watchEffect()方法的应用。

8.2 为什么使用组合API

通过创建Vue.js组件,可以将接口的可重复部分及其功能提取到可重用的代码段中,从而使应用程序可维护且灵活。然而,当应用程序非常复杂(成百上千组件)时,再使用组件的选项(datacomputedmethodswatch)组织逻辑,可能导致组件难以阅读和理解。如果能够将与同一个逻辑相关的代码配置在一起将有效解决逻辑复杂、可读性差等问题。这正是使用组合API的目的。

8.3 setup组件选项

Vue组件提供setup选项,供开发者使用组合APIsetup选项在创建组件前执行,一旦props被解析,便充当组合式API的入口点。由于在执行setup时尚未创建组件实例,因此在setup选项中没有this。这意味着,除了props之外,无法访问组件中声明的任何属性,包括本地状态、计算属性或方法。

setup选项是一个接受propscontext参数的函数。此外,从setup返回的所有内容都将暴露给组件的其余部分(计算属性、方法、生命周期钩子、模板等等)。

8.3.1 setup函数的参数

1setup函数中的第一个参数(props

setup函数中的props是响应式的,当传入新的属性时,它将被更新。

8-3】setup函数中,参数props是响应式的。

但是,因为props是响应式的,不能使用ES6解构,将会消除props的响应性。如果需要解构props,可以在setup函数中使用toRefs函数来完成此操作。

8-4】setup函数中,使用toRefs函数创建props属性的响应式引用。

toRef是把对象的某个属性改成响应式的数据,toRefs是把整个对象改成响应式数据

2setup函数中的第二个参数(context

context上下文是一个普通的JavaScript对象,它暴露组件的4个属性:attrsslotsemit以及expose

setup(props, context) {

    // Attribute (非响应式对象,等同于 $attrs)

    console.log(context.attrs)可以获取父组件的传递归来的参数hobby,但是一定需要注释props

    // 插槽 (非响应式对象,等同于 $slots)

    console.log(context.slots)

    // 触发事件 (方法,等同于 $emit)

 

 home.vue

<template><Demo @zemit="showemit"></Demo>
</template><script>
import Demo from "@/components/demo.vue";
export default {components: {Demo,},setup() {function showemit(val) {alert(`触发context.emit事件,收到参数是:${val}`);}return {showemit,};},
};
</script>

 demo.vue

<template><p>个人信息</p><p>姓名:{{ person.name }}</p><p>年龄:{{ person.age }}</p><button @click="zevent">zemit事件</button>
</template><script>
import { reactive } from "vue";
export default {name: "Home12",emits: ["zemit"],setup(props, context) {console.log("1", props);// console.log("context.attrs", context.attrs);console.log("context.attrs", context.emit);const person = reactive({name: "刘巍",age: 18,});function zevent() {context.emit("zemit", '南昌大学');}return {  person,zevent,};},
};
</script>

 

8.3.2 setup函数的返回值

1)对象

如果setup返回一个对象,则可以在组件的模板中访问该对象的属性。

8-5】在该实例中,setup函数返回一个对象。

<template><h1>一个人的信息</h1><h3>职业:{{ job.type }}</h3><h3>薪水:{{ job.salary }}</h3><h3>爱好:{{ hobby }}</h3><h3>测试数据的值:{{ job.a.b.c }}</h3><button @click="changeInfo">修改人的信息</button>
</template><script>
import {reactive} from 'vue'export default {name: 'App',setup() {//数据let job = reactive({type: 'SAP工程师',salary: '60k',a: {b: {c: 666}}})let hobby = reactive(['篮球', '说泡', '旅游'])//counts changeInfo = ()=>{...}function changeInfo() {job.type = "管理咨询顾问"job.salary = "100k"job.a.b.c = 999hobby[0] = '学习'}return {job,hobby,changeInfo}}
}
</script>

2)渲染函数

setup还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态。

8-6】实现8-5】的功能,要求setup返回渲染函数。

8.3.3 使用ref创建响应式引用

1.声明响应式状态

要为JavaScript对象创建响应式状态,可以使用reactive()方法。reactive()方法接收一个普通对象然后返回该对象的响应式代理。示例代码如下:

const book = Vue.reactive({ title: '好书' })

reactive()方法响应式转换是“深层的”即影响对象内部所有嵌套的属性。基于ESProxy实现,返回的代理对象不等于原始对象。建议使用代理对象,避免依赖原始对象。

2.使用ref创建独立的响应式值对象

ref接受一个参数值并返回一个响应式且可改变的ref对象。ref对象拥有一个指向内部值的单一属性.value。示例代码如下:

const readersNumber = Vue.ref(1000)

console.log(readersNumber.value) //1000

readersNumber.value++

console.log(readersNumber.value) // 1001

ref作为渲染上下文的属性返回(即在setup()返回的对象中)并在模板中使用时,它会自动开箱,无需在模板内额外书写.value

8.3.4 setup内部调用生命周期钩子函数

setup内部,可通过在生命周期钩子函数前面加上“on来访问组件的生命周期钩子函数。因为setup是围绕beforeCreatecreated生命周期钩子函数运行的,所以不需要显式地定义它们。换句话说,在这些钩子函数中编写的任何代码都应该直接在setup函数中编写。这些on函数接受一个回调函数,当钩子函数被组件调用时将会被执行。示例代码如下:

setup() {

 // mounted时执行

 onMounted(() => {

  console.log('Component is mounted!')

  })

}

8.4 提供/注入

通过4.3.4节可知,使用provideinject可实现组件链传值。也就是说,父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深,父组件有一个provide选项来提供数据,子组件有一个inject选项来使用这个数据。(跨组件的数据传递)

现在,在组合API中,也可以使用provide方法和inject方法实现传值,但两者都只能在当前活动实例的setup()期间调用。

8.4.1 provide方法

首先,从vue显式导入provide方法;然后,在setup()中使用provide方法定义每个property

provide方法有两个参数:

l  name:代表字符串类型的属性名称;

l  value:代表任意类型的属性值。

8.4.2 inject方法

首先,从vue显式导入inject方法;然后,在setup()中使用inject方法注入每个property值。

inject方法有两个参数:

l  name:被注入的属性名称(字符串类型);

l  defaultValue:默认值(可选)。

假设我们有一个祖先组件 app,一个中间组件 one,以及一个后代组件 two。我们希望从 app传递一个数据到 two

app.vue

<template><one></one>
</template><script setup>
// import HelloWorld from './components/HelloWorld.vue'
// import setup from './components/setup.vue'
// import setup1 from './components/setup1.vue'
import one from './components/one.vue'
import { provide } from 'vue';
const hcm = 'payroll';
provide('sap', hcm)
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

 one.vue

<template><two/>
</template><script setup>
import two from '../components/two.vue';
</script>

two.vue

<template><div :class="theme">我是SAP {{ theme }} 顾问.</div>
</template><script setup>
import { inject } from 'vue';const theme = inject('sap', 'time'); // 'time' 是默认值,如果 provide 没有提供 'theme'
</script><style scoped>
.dark {background-color: black;color: white;
}.light {background-color: white;color: black;
}
</style>

8.5 模板引用

在使用组合API时,响应式引用和模板引用的概念是统一的。为了获得对模板内元素或组件实例的引用,可以声明一个ref并从setup()返回。

8-8】在模板中使用ref引用响应式对象。

8.6 响应式计算与侦听

8.6.1 响应式计算

使用响应式计算方法computed有两种方式:传入一个getter函数,返回一个默认不可手动修改的ref对象;传入一个拥有getset函数的对象,创建一个可手动修改的计算状态。

8-9】返回一个默认不可手动修改的ref对象。

<template><div>{{count}}</div>
</template><script>
import{ref,computed} from 'vue';export default {setup() {const count = ref(1)const account = computed(()=> count.value + 1)console.log(account.value)account.value++// 返回值会暴露给模板和其他的选项式 API 钩子return {count}}
}
</script>

8-10】返回一个可手动修改的ref对象。

<template><div>{{count}}</div>
</template><script>
import{ref,computed} from 'vue';export default {setup() {const count = ref(1)const account = computed({get:()=> count.value + 1,set:(val)=> {count.value = val - 1},} )account.value = 1console.log(count.value)return {count}}
}
</script>

8.6.2 响应式侦听

可使用响应性侦听watchEffect方法,对响应性进行侦听。该方法立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。(监听所有属性)

8-11】响应性侦听watchEffect方法的使用。

监听属性变化

<template><div><input type="text" v-model="obj.name"> </div>
</template><script>
import{reactive,watchEffect} from 'vue';export default {setup() {let obj = reactive({name:'vivi'});watchEffect(()=>{console.log('name:',obj.name)})return {obj}}
}
</script>

停止监听

<template><div><input type="text" v-model="obj.name"> <button @click="stopWatchEffect">停止监听</button></div>
</template><script>
import{reactive,watchEffect} from 'vue';export default {setup() {let obj = reactive({name:'vivi'});const stop1 =  watchEffect(()=>{console.log('name',obj.name)})const stopWatchEffect = ()=>{console.log('停止监听')stop1(); // ...当该侦听器不再需要时}return {obj,stopWatchEffect,}}
}
</script>

副作用

使用 onInvalidate 清理计时器,每次 count 变化时,watchEffect 会重新执行,在此之前 onInvalidate 会先清理掉之前的计时器,避免重复创建计时器导致内存泄漏。

注意:如果在 watchEffect 没有直接使用 count.value ,那么它的变化就不会触发副作用函数重新执行,从而不会调用 onInvalidate 清理之前的计时器

<template><div><p>当前计数: {{ count }}</p><button @click="count++">增加计数</button></div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {setup() {const count = ref(0);watchEffect((onInvalidate) => {// 在函数内直接读取 count.value,确保它被追踪,这一步很重要!!!console.log(`副作用函数执行,count 值为: ${count.value}`);const timer = setInterval(() => {console.log(`计时器中 count 的值: ${count.value}`);}, 1000);onInvalidate(() => {console.log('清除计时器 timer');clearInterval(timer);});});return {count,};},
};
</script>

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

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

相关文章

Java使用aspose实现pdf转word

Java使用aspose实现pdf转word 一、下载aspose-pdf-21.6.jar包【下载地址】&#xff0c;存放目录结构如图&#xff1b;配置pom.xml。 <!--pdf to word--> <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId>…

使用Node.js搭配express框架快速构建后端业务接口模块Demo

使用Node.js搭配express框架快速构建后端业务接口模块Demo&#xff01;实际开发中&#xff0c;有很多项目&#xff0c;其实都是可以使用node.js来完成对接mysql数据库的&#xff0c;express确实使用起来非常简单&#xff0c;入手快&#xff0c;效率非常高。下面是一个简单的案例…

Python----Python高级(并发编程:协程Coroutines,事件循环,Task对象,协程间通信,协程同步,将协程分布到线程池/进程池中)

一、协程 1.1、协程 协程&#xff0c;Coroutines&#xff0c;也叫作纤程(Fiber) 协程&#xff0c;全称是“协同程序”&#xff0c;用来实现任务协作。是一种在线程中&#xff0c;比线程更加轻量级的存在&#xff0c;由程序员自己写程序来管理。 当出现IO阻塞时&#xff0c;…

Unity 加载OSGB(webgl直接加载,无需转换格式!)

Unity webgl加载倾斜摄影数据 前言效果图后续不足 前言 Unity加载倾斜摄影数据&#xff0c;有很多的插件方便好用&#xff0c;但是发布到网页端均失败&#xff0c;因为webgl 的限制&#xff0c;IO读取失效。 前不久发现一个开源项目: UnityOSGB-main 通过两种方式在 Unity 中…

【Block总结】PSA,金字塔挤压注意力,解决传统注意力机制在捕获多尺度特征时的局限性

论文信息 标题: EPSANet: An Efficient Pyramid Squeeze Attention Block on Convolutional Neural Network论文链接: arXivGitHub链接: https://github.com/murufeng/EPSANet 创新点 EPSANet提出了一种新颖的金字塔挤压注意力&#xff08;PSA&#xff09;模块&#xff0c;旨…

【重新认识C语言----结构体篇】

目录 -----------------------------------------begin------------------------------------- 引言 1. 结构体的基本概念 1.1 为什么需要结构体&#xff1f; 1.2 结构体的定义 2. 结构体变量的声明与初始化 2.1 声明结构体变量 2.2 初始化结构体变量 3. 结构体成员的访…

如何在Vscode中接入Deepseek

一、获取Deepseek APIKEY 首先&#xff0c;登录Deepseek官网的开放平台&#xff1a;DeepSeek 选择API开放平台&#xff0c;然后登录Deepseek后台。 点击左侧菜单栏“API keys”&#xff0c;并创建API key。 需要注意的是&#xff0c;生成API key复制保存到本地&#xff0c;丢失…

电脑开机提示按f1原因分析及终极解决方法来了

经常有网友问到一个问题&#xff0c;我电脑开机后提示按f1怎么解决&#xff1f;不管理是台式电脑&#xff0c;还是笔记本&#xff0c;都有可能会遇到开机需要按F1&#xff0c;才能进入系统的问题&#xff0c;引起这个问题的原因比较多&#xff0c;今天小编在这里给大家列举了比…

AI协助探索AI新构型自动化创新的技术实现

一、AI自进化架构的核心范式 1. 元代码生成与模块化重构 - 代码级自编程&#xff1a;基于神经架构搜索的强化学习框架&#xff0c;AI可通过生成元代码模板&#xff08;框架的抽象层定义、神经元结点-网络拓扑态的编码抽象定义&#xff09;自动组合功能模块。例如&#xff0…

RAID独立硬盘冗余阵列

目录 一、RAID基本功能 二、RAID常见级别 三、实现方式 1、软件磁盘阵列 2、硬件磁盘阵列 四、热备盘 RAID&#xff08;Redundant Array of Independent Disks&#xff09;是一种通过将多个硬盘组合成一个逻辑单元来提升存储性能、冗余性或两者兼具的技术。 一、RAID基本…

【高级篇 / IPv6】(7.2) ❀ 04. 在60E上配置ADSL拨号宽带上网(IPv4) ❀ FortiGate 防火墙

【简介】除了单位用户以外&#xff0c;大部分个人用户目前使用的仍然是30E、50E、60E系列防火墙&#xff0c;固件无法达到目前最高版本7.6&#xff0c;这里以最常用的60E为例&#xff0c;演示固件版本7.2下实现ADSL拨号宽带的IPv6上网。由于内容比较多&#xff0c;文章分上、下…

Qt之设置QToolBar上的按钮样式

通常给QAction设置icon后,菜单栏的菜单项和工具栏(QToolBar)上对应的按钮会同时显示该icon。工具栏还可以使用setToolButtonStyle函数设置按钮样式,其参数为枚举值: enum ToolButtonStyle {ToolButtonIconOnly,ToolButtonTextOnly,ToolButtonTextBesideIcon,ToolButtonTe…

【从零开始系列】DeepSeek-R1:(本地部署使用)思维链推理大模型,开源的神!——Windows/Linux本地环境测试 + vLLM远程部署服务

目录 一、环境配置 1.硬件设备评估 2.基础环境安装 3.模型参数下载 (1) huggingface镜像源下载 (2) modelscope魔搭社区下载 &#xff08;推荐&#xff09; 二、基础使用&#xff08;Linux、Window兼容&#xff09; 1.Transformers库自编代码 三、进阶使用&#xff08;仅Lin…

DeepSeek 开源模型全解析(2024.1.1–2025.2.6)

目录 一、通用大语言模型&#xff1a;DeepSeek-V3 系列 137 二、推理优化模型&#xff1a;DeepSeek-R1 系列 811 三、多模态模型&#xff1a;Janus 系列 10 四、生态整合与部署建议 五、总结与展望 以下为 DeepSeek 在 2024 年 1 月至 2025 年 2 月期间发布的开源模型及其…

Mac: docker安装以后报错Command not found: docker

文章目录 前言解决办法&#xff08;新的&#xff09;解决步骤&#xff08;原来的&#xff09;不推荐总结 前言 ​本操作参考 http://blog.csdn.net/enhenglhm/article/details/137955756 原作者&#xff0c;更详细请&#xff0c;查看详细内容请关注原作者。 一般&#xff0c;…

《手札·开源篇》数字化转型助力永磁电机企业降本增效:快速设计软件如何让研发效率提升40%?

数字化转型助力永磁电机企业降本增效&#xff1a;快速设计软件如何让研发效率提升40%&#xff1f; 一、痛点&#xff1a;传统研发模式正在吃掉企业的利润 永磁电机行业面临两大挑战&#xff1a; 研发周期长&#xff1a;一款新电机从设计到量产需6-12个月&#xff0c;电磁计算…

0207作业

思维导图 服务器 enum Type{TYPE_REGIST,TYPE_LOGIN };typedef struct Pack{int size;enum Type type;char buf[2048];}pack_t;typedef struct list{union Data{struct List* tail;char str[64];}data;struct List* next;struct List* prev; }List;List* create_node(){List* …

深入浅出 DeepSeek V2 高效的MoE语言模型

今天&#xff0c;我们来聊聊 DeepSeek V2 高效的 MoE 语言模型&#xff0c;带大家一起深入理解这篇论文的精髓&#xff0c;同时&#xff0c;告诉大家如何将这些概念应用到实际中。 &#x1f31f; 什么是 MoE&#xff1f;——Mixture of Experts&#xff08;专家混合模型&#x…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(五)

#作者&#xff1a;闫乾苓 系列前几篇&#xff1a; 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》&#xff1a;link 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;二&#xff09;》&#xff1a; lin…

nodejs:express + js-mdict 网页查询英汉词典,能播放.spx 声音

向 DeepSeek R1 提问&#xff1a; 我想写一个Web 前端网页&#xff0c;后台用 nodejs js-mdict , 实现在线查询英语单词&#xff0c;并能播放.spx 声音文件 1. 项目结构 首先&#xff0c;创建一个项目目录&#xff0c;结构如下&#xff1a; mydict-app/ ├── public/ │ …