Vue3-拉开序幕的setup

Vue3 中的 setup 是一个新的配置项,值是一个函数。

export default {name: 'App',setup: function () {}
}
</script>

和 Vue2 中的 data 一样,我也可以将 setup 简写成为

export default {name: 'App',setup() {}
}

setup函数的使用

与 Vue2 不一样的是,setup 中包含了 data 数据,methods方法,computed计算属性,watch监听器等等一系列的属性,也就是说,在 Vue3 中,我们不会显式的把这些属性配置到 setup 中,而是直接将属性内部的数据或方法直接暴露在 setup 中

ps:本章所讲内容,不涉及响应式,也就是说 在 setup 中定义的数据,不是响应式的,如何转为响应式数据,下一章节 ref 会讲到。但是 props 传递的数据是响应式的。

setup() {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// 类似于methods属性中的方法function hello() {// 因为这是直接在 setup 函数中访问变量,直接访问就行,不用 thisalert(`我的名字是${name},我的年龄是${age}`) }}

 setup 的参数

 setup 函数接收两个参数,分别是 props上下文 context

props 是响应式的数据,且在传入新的 props 时,会同步更新现有的 props。例如

export default {// 如果这里接收到的 props 改变了props: {title: String},// 那么这里的接使用的props也会同步改变setup(props) {console.log(props.title)}
}

同时需要注意的是,在使用props传递的数据时时,尽量采取 props.xxx的方式进行。

对于传递的 props尽量不要解构,因为解构得出的变量将会丢失响应式。如果确实需要解构,或者将 props中的某一项数据传递的同时保持响应式,可以采用 torefs 和 toref 来进行转化。

import { toRefs, toRef } from 'vue'export default {setup(props) {// 将 `props` 转为一个其中全是 ref 的对象,然后解构const { title } = toRefs(props)// `title` 是一个追踪着 `props.title` 的 refconsole.log(title.value)// 或者,将 `props` 的单个属性转为一个 refconst title = toRef(props, 'title')}
}

第二个参数则是上下文 context ,其中暴露了一些在setup 中可能会用到的值,例如:

export default {setup(props, context) {// 透传 Attributes(非响应式的对象,等价于 $attrs)console.log(context.attrs)// 插槽(非响应式的对象,等价于 $slots)console.log(context.slots)// 触发事件(函数,等价于 $emit)console.log(context.emit)// 暴露公共属性(函数)console.log(context.expose)}
}

这个 context 不是响应式的,可以直接解构,

export default {setup(props, { attrs, slots, emit, expose }) {...}
}

其中 attrs 和 slots 都是有状态的对象,会随着组件自身更新而更新,但是二者都不是响应式数据,所以在使用时,同样避免解构,而是尽量通过 attrs.x 或 slots.x 方式。如果想要基于 attrs 或 slots的改变来执行副作用,那么可以在 onBeforeUpdate 声明周期中编写逻辑。

emit则是用来触发函数,和 Vue2 中作用一致。

expose 的作用则是显式的限制向外暴露的属性。当父组件引用子组件时,只能访问到通过可 expose 暴露特定的方法。当 expose 不传递参数时,代表不暴露任何东西,当传递对象时,则有选择的暴露局部状态。

import { h, ref } from 'vue'export default {setup(props, { expose }) {const count = 0const increment = () => ++count.valueexpose({increment})return () => h('div', count.value)}
}

setup 的返回值

setup 存在两种返回值:

  1. 返回一个同步对象,对象中的属性、方法在模板中均可直接使用,例如
    export default {name: 'App',setup() {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// 类似于methods属性中的方法function hello() {alert(`我的名字是${name},我的年龄是${age}`) }return {name,age,hello}}
    }
    <template><h1>我是app组件</h1><p>姓名:{{ name }}</p><p>年龄:{{ age }}</p><button @click="hello()">个人信息</button>
    </template>

  2. 返回一个渲染函数 ,可以自定义渲染内容(
    <script>
    import { h } from 'vue'
    export default {name: 'App',setup() {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// Vue2 中的 main.js 中,在使用 render 函数时,就使用了 h 这个方法,// 第一个参数是节点,第二个参数是渲染内容// 当使用 返回 render 函数之后,html 模板中的内容都会被忽略,只会执行 h 函数的渲染内容return () => h('div','我改名字了')}
    }
    </script>

ps:返回一个渲染函数将会阻止我们返回其他东西。对于组件内部来说,这样没有问题,但如果我们想通过模板引用将这个组件的方法暴露给父组件,那就有问题了。因为此时除了渲染函数之外,暴露不了别的数据和方法了,为了解决这一问题,Vue3采用了 expose 来暴露方法或属性,然后返回渲染函数 

setup(props,{ expose }) {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// 类似于methods属性中的方法function hello() {alert(`我的名字是${name},我的年龄是${age}`) }// 通过 expose 暴露方法或属性expose({name,hello})// Vue2 中的 main.js 中,在使用 render 函数时,就使用了 h 这个方法,// 第一个参数是节点,第二个参数是渲染内容// 当使用 返回 render 函数之后,html 模板中的内容都会被忽略,只会执行 h 函数的渲染内容return () => h('div','我改名字了')
}
}

 注意事项

1、Vue2 和 Vue3 不要混用。Vue3 是向下兼容的,所以即使是在 Vue3 项目中,也可以使用 Vue2 的语法,但是也会带来一些问题。

  1. 兼容性:在 Vue3 项目中也可以使用 Vue2 的写法
    <template><p>在Vue3中访问 Vue2 写法下的属性或方法</p><p>姓名:{{ newName }}</p><p>年龄:{{ newAge }}</p><button @click="getVue3Data">点击获取Vue2写法中的数据</button>
    </template><script>
    export default {name: 'App',data() {return {newName: '汤圆',newAge:1}},methods: { testVue2(){alert(`我的名字是${this.newName},我的年龄是${this.newAge}`)}},
    }
    </script>
    

2、Vue2 的配置项( data、methods、computed... )中可以访问 Vue3 中 setup 中的属性、方法

<button @click="testVue3">点击后再Vue2写法中获取Vue3写法中setup的数据</button><script>
export default {name: 'App',methods: { testVue3() {console.log(this.name);console.log(this.age);console.log(this.hello);}},setup() {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// 类似于methods属性中的方法function hello() {alert(`我的名字是${name},我的年龄是${age}`) }return {name,age,hello}}
}
</script>

点击按钮之后,控制台上打印出了 Vue3 setup 中定义的变量和方法。

3、但是在 Vue3 中的setup 中调用 Vue2 声明的变量或方法时,会无法找到

setup() {// 类似于data属性中的数据,不过不用显式的声明data,而是直接设置变量let name = 'al'let age = 18// 类似于methods属性中的方法function hello() {alert(`我的名字是${name},我的年龄是${age}`) }function testVue4() {console.log(name);console.log(age);console.log(hello);// 因为这些属性或方法不是在 setup 内部定义的,而是按照Vue2 的配置语法定义的,所以按照Vue2的访问模式 通过 this.xxx 访问console.log(this.newName);console.log(this.newAge);console.log(this.testVue2);}return {name,age,hello,testVue4}
}

从这里可以看到,在 Vue3 的 setup 中访问 Vue2 中的方法或属性时,得到的是undefined,这是因为  setup() 自身并不含对组件实例的访问权,即在 setup() 中访问 this 会是 undefined。你可以在选项式 API 中访问组合式 API 暴露的值(在 Vue2 中访问 Vue3的属性或方法),但反过来则不行。

但是但是这里其实还存在一个问题,如果我直接在 setup 中访问 this,得到的是undefined,但是如果我是在 setup 中定义的函数中访问 this,得到的是一个 Proxy 代理对象

setup() {console.log(this, 'this111');function testVue4() {console.log(this,'this');console.log(this.newName);console.log(this.newAge);console.log(this.testVue2);}return {testVue4}
}

 首先说 直接在 setup 中访问 this,问什么会是undefined?这是因为setup函数执行时,不依赖于Vue实例,换句话说就是 setup 函数在Vue实例化之前就执行了,所以无法直接访问到this。

然后再说为什么setup 中的方法作为组件模板内容使用时(例如作为事件处理函数被调用时),那么Vue会将这个方法绑定到Vue实例上。当该函数被调用时,this指向的就是Vue组件实例。

也就是说 Vue3中无法在 setup 内部直接访问到 this,但是通过 return 出去的函数 或者绑定到模板的数据时可以访问到this。

4、如果 Vue2 和 Vue3 混用时,数据或方法出现重名情况,以 setup 中的数据优先

<template><p>{{ name }}</p><button @click="hello">点击查看</button>
</template><script>
export default {name: "App",data() {return {name: "aha",};},methods: {hello() {alert(`我的名字是${this.name}`);},},setup() {let name = "al";// 类似于methods属性中的方法function hello() {alert(`我的名字是${name}`) }return {// eslint-disable-next-line vue/no-dupe-keyshello,// eslint-disable-next-line vue/no-dupe-keysname,};},
};
</script>

5、setup() 应该同步地返回一个对象。唯一可以使用 async setup() 的情况是,该组件是 Suspense 组件的后裔。

具体理解就是 setup 在一般情况下,不能使用  async 包裹,因为被 async 包裹之后,即使你返回的还是原来的对象,但是 async 会对象外部包裹一层 Promise,如果想要拿取数据的话,还需要通过.then() 来获取 ,模板中时无法直接看到并且使用 return 对象中的属性或方法的。而 Vue 是不会自动帮你做这件事的。

但是 也存在一直特殊情况,那就是  该组件是 Suspense 组件的后裔( 这个后在讲,我现在也没研究到这里来 )。

总结 

 1、Vue2 和 Vue3 的配置尽量不要混用

2、如果混用了,

  • Vue2 中的配置 (例如:data、methods、compute、watch等)可以访问到 setup 中的属性和方法
  • Vue3 中的setup 不能访问到 Vue2 中的配置项
  • 存在重名情况,以 Vue3 setup 中优先

3、setup 一般不用  async,因为 setup 需要同步的返回一个对象,以此来保证 模板中数据或方法正常绑定,如果用了 async 那么返回的数据对象 会被 Promise 包裹,模板中无法看到对象中的属性,无法绑定。但是 当该组件是 Suspense 组件的后裔时,可以使用  async setup()

 

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

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

相关文章

go 语言踏出第一步

1、下载Go语言安装包&#xff1a;在官方网站&#xff08;https://golang.org/dl/&#xff09;上下载适合你操作系统的Go语言安装包。选择一个tar.gz格式的包。 2、解压安装包&#xff1a;打开终端&#xff0c;进入下载目录&#xff0c;并使用以下命令解压安装包&#xff1a; ta…

Git操作指令(已完结)

Git操作指令 一、安装git 1、设置配置信息&#xff1a; # global全局配置 git config --global user.name "Your username" git config --global user.email "Your email"# 显示颜色 git config --global color.ui true# 配置别名&#xff0c;各种指令都…

详细介绍MLP的原理

什么是MLP MLP&#xff08;Multi-Layer Perceptron&#xff09;&#xff0c;即多层感知机&#xff0c;是一种前馈型人工神经网络。它由一个输入层、一个输出层以及至少一个隐藏层&#xff08;输入层和输出层中间的层&#xff09;组成。每个神经元&#xff08;或称为节点&#x…

【Django】 js实现动态赋值、显示show隐藏hide效果

文章目录 需要达到的前端效果预览&#xff1a;实现步骤复制bootstrp代码&#xff08;buttons&#xff09;复制bootstrp代码&#xff08;Alert警告框&#xff09;写js测试效果 需要达到的前端效果预览&#xff1a; {% load static %} <!DOCTYPE html> <html lang"…

十分钟速通 MySQL —— CRUD

表格的结构 在之前的课程中我们已经学习了关系型数据库的表格&#xff0c;我们再来回顾-下表格由哪些元素构成 表由表名、行、列、列名构成表名是表的名称列名表示列的名字&#xff0c;列名不可以重复表格实质上是一个二维数组&#xff0c;行和列都是从0开始数的(数组的特性) …

线程池配置与CPU利用率

线程数设置理论 CPU密集型&#xff1a;核心数 1I/O密集型&#xff1a;核心数 * 2 CPU利用率基础 单个CPU核心在单位时间内只能执行一个线程的指令。 实验验证 死循环测试&#xff1a;单线程可跑满一个核心利用率。多线程测试&#xff1a;增加线程数&#xff0c;核心利用率…

【软考】广义表

目录 1. 说明2. 基本操作3. 特点4. 存储结构5. 例题5.1 例题1 1. 说明 1.广义表是线性表的推广&#xff0c;是由0个或多个单元素或子表组成的有限序列。2.广义表与线性表的区别在于:线性表的元素都是结构上不可分的单元素&#xff0c;而广义表的元素既可以是单元素&#xff0c…

【过滤器 vs 拦截器】SpringBoot中过滤器与拦截器:明智选择的艺术(如何在项目中做出明智选择)

文章目录 SpringBoot 过滤器 vs 拦截器过滤器 (Filter)定义特点使用场景实现步骤创建过滤器类注册过滤器&#xff08;可选&#xff0c;如果不使用 WebFilter 注解&#xff09; 拦截器 (Interceptor)定义特点使用场景实现步骤创建拦截器类注册拦截器 过滤器与拦截器的比较实际项…

Python教程:一文了解Python中的序列化与反序列化

目录 1. 序列化与反序列化概述 1.1 什么是序列化&#xff1f; 1.2 什么是反序列化&#xff1f; 1.3 应用场景 2. Python中的序列化与反序列化模块 2.1 pickle模块 2.1.1 使用示例 2.2 json模块 2.2.1 使用示例 2.3 yaml模块 2.3.1 使用示例 2.4 marshal模块 3. 实…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十二章 定时器按键消抖实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

linux mysql 添加环境变量

要在Linux上添加MySQL的环境变量&#xff0c;可以按照以下步骤进行操作&#xff1a;打开终端窗口。使用文本编辑器&#xff08;如vi或nano&#xff09;打开~/.bashrc文件&#xff1a;vi ~/.bashrc或nano ~/.bashrc在文件的末尾添加以下内容&#xff1a;export PATH$PATH:/path/…

shardingsphere的学习(一):shardingsphere的基本概念和水平分表例子

简介 关于shardingsphere的基本相关概念的学习和使用shardingjdbc进行水平分表的例子 shardingsphere 是一套开源的分布式关系型数据库中间件解决方案&#xff0c;由sharding-jdbc&#xff0c;sharding-proxy&#xff0c;sharding-sidecar三个项目组成。 定位为关系型数据库…

日期类的实现(C++实现)

完整呈现 Date.h #include <iostream> using namespace std; //日期类 class Date { public:int GetMonthDays(int year, int month) const;//构造函数Date(int year 0, int month 1, int day 1);//拷贝构造Date(const Date& d);//打印void Print();//析构函数~…

Redis与MySQL数据一致性问题的策略模式及解决方案

目录 一、策略模式 1、旁路缓存模式&#xff08;Cache Aside Pattern&#xff09; 2、读写穿透&#xff08;Read-Through/Write-Through&#xff09; 3、异步缓存写入&#xff08;Write Behind&#xff09; 二、一致性解决方案 1、缓存延迟双删 2、删除重试机制 3、读取…

NodeJS:npm的使用

npm时nodejs的包安装工具 1.查看版本 $ npm -v 9.6.7 2.升级npm $ sudo npm install npm -g 3.安装nodejs模块 $ npm install <Module Name> 通过该方法将在当前目录下创建文件夹node_modules&#xff0c;并将模块安装到node_modules中 可以通过-g参数指定模块为全局安…

Zygote 进程你不知道的东西

一、概述 1.Zygote&#xff08;孵化&#xff09; 进程是所有 Android进程的父进程&#xff0c;包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote进程相当于Android系统的根进程&#xff0c;系统启动后所有的进程都是通过这个进程fork出来的。这样做的好处…

【python】sklearn基础教程及示例

【python】sklearn基础教程及示例 Scikit-learn&#xff08;简称sklearn&#xff09;是一个非常流行的Python机器学习库&#xff0c;提供了许多常用的机器学习算法和工具。以下是一个基础教程的概述&#xff1a; 1. 安装scikit-learn 首先&#xff0c;确保你已经安装了Python和…

Python:模块导入

step1. 创建一个.py文件&#xff0c;里面装载你想导入的内容 step2. 用import导入 import导入的两种方法 1.整体 import file_name 2.局部 from file_name import function_name 整体的调用&#xff1a; file_name.function() 局部的&#xff1a; function_name() 这是导入的文…

Unity 资源 之 Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享

精彩呈现&#xff1a;Pop It 3D 解压玩具与双人AI游戏 Unity 资源包分享 一、Pop It 3D 解压玩具的魅力二、双人游戏的互动乐趣三、Unity 游戏资源包的优势四、如何获取资源包 亲爱的游戏爱好者们&#xff0c;今天为大家带来一款令人兴奋的游戏资源——Pop It 3D 解压玩具双人带…

Linux安装Python并运行一个项目

Linux安装Python并运行一个项目 1、下载Python Python版本&#xff1a;3.10.11 操作系统&#xff1a;Centos 8.2 下载地址&#xff1a;https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tar.xz 将文件放在&#xff1a;/opt/python 下 2、安装Python 先安装一些…