VUE3 Setup语法糖

目前setup sugar已经进行了定稿,vue3 + setup sugar + TS的写法看起来很香,写本文时 Vue 版本是 “^3.2.6”

script setup 语法糖

新的 setup 选项是在组件创建之前, props 被解析之后执行,是组合式 API 的入口。

WARNING
在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法>在 setup 中被获取。

setup 选项是一个接收 props 和 context 的函数,我们将在之后进行讨论。此外,我们将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。

它是 Vue3 的一个新语法糖,在 setup 函数中。所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。

在添加了setup的script标签中,我们不必声明和方法,这种写法会自动将所有顶级变量、函数,均会自动暴露给模板(template)使用
这里强调一句 “暴露给模板,跟暴露给外部不是一回事”

使用方式极其简单,仅需要在 script 标签加上 setup 关键字即可。示例:

<script setup></script>

该setup功能是新的组件选项。它是组件内部暴露出所有的属性和方法的统一API。
使用后意味着,script标签内的内容相当于原本组件声明中setup()的函数体,不过也有一定的区别。
使用 script setup 语法糖,组件只需引入不用注册,属性和方法也不用返回,也不用写setup函数,也不用写export default ,甚至是自定义指令也可以在我们的template中自动获得。

调用时机

创建组件实例,然后初始化 props ,紧接着就调用setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用.

模板中使用

如果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文

<template><div>{{ count }} {{ object.foo }}</div>
</template>

setup 参数

「props」 第一个参数接受一个响应式的props,这个props指向的是外部的props。如果你没有定义props选项,setup中的第一个参数将为undifined。props和vue2.x并无什么不同,仍然遵循以前的原则;

  • 不要在子组件中修改props;如果你尝试修改,将会给你警告甚至报错。
  • 不要结构props。结构的props会失去响应性。

「context」 第二个参数提供了一个上下文对象,从原来 2.x 中 this 选择性地暴露了一些 property。

<script setup="props, context" lang="ts">context.attrscontext.slotscontext.emit 
<script>

像这样,只要在setup处声明即可自动导入,同时也支持解构语法:

<script setup="props, { emit }" lang="ts"><script>

组件自动注册

导入 component 或 directive 直接import即可,无需额外声明

import { MyButton } from "@/components"
import { directive as clickOutside } from 'v-click-outside'

与原先一样,模板中也支持使用kabab-case来创建组件,如
在 script setup 中,引入的组件可以直接使用,无需再通过components进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写name属性了。示例:

<template><HelloWorld />
</template><script setup>
import HelloWorld from "./components/HelloWorld.vue"; //此处使用 Vetur 插件会报红
</script>

如果需要定义类似 name 的属性,可以再加个平级的 script 标签,在里面实现即可。

组件核心 API 的使用

定义组件的 props

通过defineProps指定当前 props 类型,获得上下文的props对象。示例:

<script setup lang="ts"> 
import { defineProps } from 'vue';const props = defineProps(["title"]);
</script>
<!-- 或者 -->
<script setup>import { defineProps } from 'vue';const props = defineProps({title: String, // 可以设置传来值的类型})
</script>
<!-- 或者 -->
<script setup>import { defineProps } from 'vue';const props = defineProps({// 可以设置传来值的类型和默认值title: {type:String,default: ''}})
</script>
<!-- 或者 -->
<script setup>import { defineProps } from 'vue';const props = defineProps({title: [String,Number] // 可以设置传来值的多种类型})
</script>
<!-- 或者 -->
<script setup lang="ts"> import { ref,defineProps } from 'vue';type Props={ title:string }defineProps<Props>(); 
</script>

定义 emit

使用defineEmit定义当前组件含有的事件,并通过返回的上下文去执行 emit。示例:

<script setup>import { defineEmits } from 'vue'// 定义两个方法 change 和 deleteconst emit = defineEmits(['change', 'delete'])const handleClick=()=>{emit('change', 5); // 传给父组件的值的方法}const handleClickDel=()=>{emit('delete', 8); // 传给父组件的值的方法}
</script>

父子组件通信

  • 在Vue3中父子组件传值、方法是通过defineProps, defineEmits实现的。
  • defineProps 和 defineEmits 都是只在 

defineProps 用来接收父组件传来的 props ; defineEmits 用来声明触发的事件。

//父组件
<template><my-son foo="🚀🚀🚀🚀🚀🚀" @childClick="childClick" />
</template><script lang="ts" setup>
import MySon from "./MySon.vue";let childClick = (e: any):void => {console.log('from son:',e);  //🚀🚀🚀🚀🚀🚀
};
</script>//子组件
<template><span @click="sonToFather">信息:{{ props.foo }}</span>
</template><script lang="ts" setup>
import { defineEmits, defineProps} from "vue";const emit = defineEmits(["childClick"]);     // 声明触发事件 childClick
const props = defineProps({ foo: String });   // 获取propsconst sonToFather = () =>{emit('childClick' , props.foo)
}
</script>

子组件通过 defineProps 接收父组件传过来的数据,子组件通过 defineEmits 定义事件发送信息给父组件
增强的props类型定义:

const props = defineProps<{foo: stringbar?: number
}>()const emit = defineEmit<(e: 'update' | 'delete', id: number) => void>()

不过注意,采用这种方法将无法使用props默认值。

父组件调用子组件事件

父组件

<!-- 父组件 app.vue -->
<template><div class="par"><!-- 使用 ref 指令关联子组件 --><child ref="childRef"/><button @click="handleClick">提交</button></div>
</template>
<script setup>
import { reactive, ref } from "vue";
import child from "./child.vue";
//定义子组件实例,名称要和上面的ref相同
const childRef = ref(null);//访问demo组件的方法或对象
const handleClick = () => {//获取到子组件的 title 数据 let title = childRef.value.state.title;//调用子组件的 play方法childRef.value.submit();
};
</script>

子组件
子组件通过defineExpose暴露对象和方法

<!--子组件名称  child.vue -->
<template><div class="child">{{ state.title }}</div>
</template>
<script setup>
import { ref, reactive } from "vue";
//定义一个变量
const state = reactive({title: "标题",
});
//定义一个方法
const submit = () => {state.title = "你调用了子组件的方法";
};//暴露state和play方法
defineExpose({state,submit
});
</script>

定义响应变量、函数、监听、计算属性computed

<script setup lang="ts"> 
import { ref,computed,watchEffect } from 'vue';const count = ref(0); //不用 return ,直接在 templete 中使用const addCount=()=>{ //定义函数,使用同上 count.value++; 
} //定义计算属性,使用同上
const howCount=computed(()=>"现在count值为:"+count.value);//定义监听,使用同上 //...some code else 
watchEffect(()=>console.log(count.value)); 
</script>

watchEffect
用于有副作用的操作,会自动收集依赖。
和watch区别
无需区分deep,immediate,只要依赖的数据发生变化,就会调用

reactive

此时name只会在初次创建的时候进行赋值,如果中间想要改变name的值,那么需要借助composition api 中的reactive。

<script setup lang="ts">
import { reactive, onUnmounted } from 'vue'const state = reactive({counter: 0
})
// 定时器 每秒都会更新数据
const timer = setInterval(() => {state.counter++
}, 1000);onUnmounted(() => {clearInterval(timer);
})
</script>
<template><div>{{state.counter}}</div>
</template>

使用ref也能达到我们预期的’counter’,并且在模板中,vue进行了处理,我们可以直接使用counter而不用写counter.value.

ref和reactive的关系:
ref是一个{value:‘xxxx’}的结构,value是一个reactive对象

ref 暴露变量到模板

曾经的提案中,如果需要暴露变量到模板,需要在变量前加入export声明:
js复制代码export const count = ref(0)

不过在新版的提案中,无需export声明,编译器会自动寻找模板中使用的变量,只需像下面这样简单的声明,即可在模板中使用该变量

<script setup lang="ts">
import { ref } from 'vue'const counter = ref(0);//不用 return ,直接在 templete 中使用const timer = setInterval(() => {counter.value++
}, 1000)onUnmounted(() => {clearInterval(timer);
})
</script>
<template><div>{{counter}}</div>
</template>

生命周期方法

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。

可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。官网:生命周期钩子

<script setup lang="ts"> 
import { onMounted } from 'vue';onMounted(() => { console.log('mounted!'); });</script>

获取 slots 和 attrs

注:useContext API 被弃用,取而代之的是更加细分的 api。

可以通过useContext从上下文中获取 slots 和 attrs。不过提案在正式通过后,废除了这个语法,被拆分成了useAttrs和useSlots。

useAttrs:见名知意,这是用来获取 attrs 数据,但是这和 vue2 不同,里面包含了 class、属性、方法。

<template><component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>const attrs = useAttrs();
<script>

useSlots: 顾名思义,获取插槽数据。

使用示例:

// 旧
<script setup>import { useContext } from 'vue'const { slots, attrs } = useContext()
</script>// 新
<script setup>import { useAttrs, useSlots } from 'vue'const attrs = useAttrs()const slots = useSlots()
</script>

其他 Hook Api

  • useCSSModule:CSS Modules 是一种 CSS 的模块化和组合系统。vue-loader 集成 CSS Modules,可以作为模拟 scoped CSS。允许在单个文件组件的setup中访问CSS模块。此 api 本人用的比较少,不过多做介绍。
  • useCssVars: 此 api 暂时资料比较少。介绍v-bind in styles时提到过。
  • useTransitionState: 此 api 暂时资料比较少。
  • useSSRContext: 此 api 暂时资料比较少。

defineExpose API

传统的写法,我们可以在父组件中,通过 ref 实例的方式去访问子组件的内容,但在 script setup 中,该方法就不能用了,setup 相当于是一个闭包,除了内部的 template模板,谁都不能访问内部的数据和方法。
如果需要对外暴露 setup 中的数据和方法,需要使用 defineExpose API。示例:

const a = 1
const b = ref(2)
defineExpose({ a, b, })

注意:目前发现defineExpose暴露出去的属性以及方法都是 unknown 类型,如果有修正类型的方法,欢迎评论区补充。

//父组件<template><Daughter ref="daughter" />
</template><script lang="ts" setup>
import { ref } from "vue";
import Daughter from "./Daughter.vue";const daughter = ref(null)
console.log('🚀🚀🚀🚀~daughter',daughter)
</script>//子组件<template><div>妾身{{ msg }}</div>
</template><script lang="ts" setup>
import { ref ,defineExpose} from "vue";
const msg = ref('貂蝉')
defineExpose({msg
})
</script>

一、父组件调用子组件方法
子组件需要使用defineExpose对外暴露方法,父组件才可以调用。
子组件

<template><div>子组件</div>
</template><script setup lang="ts">// 第一步:定义子组件的方法const handleSubmit = (str: string) => {console.log('子组件的hello方法执行了--' + str)}// 第二部:暴露方法defineExpose({handleSubmit})
</script>

父组件

<template><button @click="handleChild">触发子组件方法</button><!-- 一:定义 ref --><Child ref="childRef"></Child>
</template><script lang="ts" setup>import { ref } from 'vue';import Child from '../../components/child.vue';// 二:定义与 ref 同名变量const childRef = ref <any> ()// 三、函数const handleChild = () => {// 调用子组件的方法或者变量,通过valuechildRef.value.hello("hello world!");}
</script>

参考网址:cn.vuejs.org/api/sfc-scr…

属性和方法无需返回,直接使用!

这可能是带来的较大便利之一,在以往的写法中,定义数据和方法,都需要在结尾 return 出去,才能在模板中使用。在 script setup 中,定义的属性和方法无需返回,可以直接使用!示例:

<template><div><p>My name is {{name}}</p></div>
</template><script setup>
import { ref } from 'vue';const name = ref('Sam')
</script>

支持 async await 异步

注意在vue3的源代码中,setup执行完毕,函数 getCurrentInstance 内部的有个值会释放对 currentInstance 的引用,await 语句会导致后续代码进入异步执行的情况。所以上述例子中最后一个 getCurrentInstance() 会返回 null,建议使用变量保存第一个 getCurrentInstance() 返回的引用.

<script setup>const post = await fetch(`/api/post/1`).then((r) => r.json())
</script>

另外,await 的表达式会自动编译成在 await 之后保留当前组件实例上下文的格式。注意
> async setup() 必须与 Suspense 组合使用,Suspense 目前还是处于实验阶段的特性。我们打算在将来的某个发布版本中开发完成并提供文档 - 如果你现在感兴趣,可以参照 tests 看它是如何工作的。## 定义组件其他配置
配置项的缺失,有时候我们需要更改组件选项,在setup中我们目前是无法做到的。我们需要在上方再引入一个 script,在上方写入对应的 export即可,需要单开一个 script。
<script setup> 可以和普通的 <script> 一起使用。普通的 <script> 在有这些需要的情况下或许会被使用到:- 无法在 <script setup> 声明的选项,例如 inheritAttrs 或通过插件启用的自定义的选项。
- 声明命名导出。
- 运行副作用或者创建只需要执行一次的对象。在script setup 外使用export default,其内容会被处理后放入原组件声明字段。
```

注意:Vue 3 SFC 一般会自动从组件的文件名推断出组件的 name。在大多数情况下,不需要明确的 name 声明。唯一需要的情况是当你需要  包含或排除或直接检查组件的选项时,你需要这个名字。

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

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

相关文章

火山引擎 DataLeap:从短视频 APP 实践看如何统一数据指标口径

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 短视频正在成为越来越多人发现世界的窗口&#xff0c;其背后的创作者生态建设是各大短视频 APP 不可忽视的重要组成部分。 为了激励更多优质内容生产&#xff0c;某…

数据压缩算法一览

文章首发地址 Huffman编码&#xff1a; Huffman编码是一种基于字符频率的无损压缩算法。它将出现频率较高的字符用较短的编码表示&#xff0c;出现频率较低的字符用较长的编码表示&#xff0c;从而实现压缩。Lempel-Ziv-Welch (LZW)&#xff1a; LZW是一种基于字典的无损压缩算…

iOS 分别对一张图的局部进行磨砂,拼接起来不能贴合

效果图 需求&#xff0c;由于视图层级的原因&#xff0c;需要对图片分开进行磨砂&#xff0c; 然后组合在一起 如图&#xff0c;上下两部分&#xff0c;上下两个UIImageVIew大小相同&#xff0c;都是和图片同样的大小&#xff0c;只是上面的UIimageVIew 只展示上半部份 &#…

初识【类和对象】

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 5.类的作用域 6.类的实例化 7.类的对象大小的计算 8.类成员函数的this指针 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的…

stm32之9.中断优先级配置

主函数main.c #include <stm32f4xx.h> #include "led.h" #include "key.h"#define PAin(n) (*(volatile uint32_t *)(0x42000000 (GPIOA_BASE0x10-0x40000000)*32 (n)*4)) #define PEin(n) (*(volatile uint32_t *)(0x42000000 (GP…

html实现iframe全屏

前言 html浏览器全屏操作&#xff0c;基于jquery iframe全屏、指定标签全屏 实现 css /** 全屏*/ .lay-dbclick-box{position: relative;width: 100%;height: 100%; } .lay-dbclick-screen{position: absolute;top: 0;left: 0;width: 100%;height: 100%;z-index: 999999999…

pytorch里面的nn.AdaptiveAvgPool2d

今天遇到nn.AdaptiveAvgPool2d((None, 1)) AdaptiveAvgPool2d函数详细解释&#xff1a; 2D自适应平均池化&#xff08;2D adaptive average pooling&#xff09;是一种对输入信号进行二维平均池化的操作&#xff0c;输入信号由多个输入平面&#xff08;input planes&#xff0…

分布式技术

分布式没有权威的技术&#xff0c;只有实践经验和积累的组件。常见的分布式技术有发号机制、分布式数据库、分布式数据库事物、基于Redis的分布式缓存、分布式会话、分布式安全认证。 1、发号机制 在数据库&#xff08;关系数据库&#xff09;中&#xff0c;主键往往是一条记…

为什么学嵌入式还要学单片机和人工智能?

从企业用人需求的角度来看&#xff0c;许多企业在招聘嵌入式工程师时都希望其具备一定的技能要求。其中&#xff0c;熟悉STM32单片机开发、熟悉嵌入式Linux开发以及熟悉实时操作系统开发&#xff0c;如FreeRTOS等&#xff0c;是常见的要求。掌握这些技术点的课程将为学生提供更…

成都国际车展来袭:有颜值有实力 大运新能源两款车型备受关注

今年成都国际车展现场最大看点是什么&#xff1f;诸多实力车企汇聚一堂各显神通&#xff0c;形式各样的新能源车型更是吸晴无数&#xff0c;成为消费者的购车首选。老品牌、新势力的大运新能源独具匠心设计特色展台&#xff0c;旗下两款车型悦虎和远志M1重磅登场。两款车型既有…

【设备树笔记整理6】中断系统中的设备树

1 中断概念的引入与处理流程 1.1 中断处理框图 1.2 中断程序的使用 主函数() while(1) {do_routine_task(); }中断处理函数() {handle_interrupt_task(); }如何调用中断处理函数&#xff1f; 1.3 ARM对异常(中断)的处理过程 &#xff08;1&#xff09;初始化 ① 设置中断…

【算法题】2788. 按分隔符拆分字符串

题目&#xff1a; 给你一个字符串数组 words 和一个字符 separator &#xff0c;请你按 separator 拆分 words 中的每个字符串。 返回一个由拆分后的新字符串组成的字符串数组&#xff0c;不包括空字符串 。 注意 separator 用于决定拆分发生的位置&#xff0c;但它不包含在…

前端面试:【前端安全】安全性问题与防范措施

嗨&#xff0c;亲爱的前端开发者&#xff01;在构建Web应用程序时&#xff0c;确保安全性是至关重要的。本文将深入讨论前端开发中的安全性问题&#xff0c;并提供一些防范措施&#xff0c;以确保你的应用程序和用户数据的安全性。 前端安全性问题&#xff1a; 跨站脚本攻击&am…

线程安全问题(收集和记录)

线程安全和线程不安全的集合 两个例子讲解为什么线程不安全以及带来的问题 如何线程安全 加锁synchronized 根据情况判断锁class还是锁object, 有时候无脑锁class也不会带来性能消耗使用集合锁 public static List linkedList Collections.synchronizedList(new LinkedList…

Apollo自动驾驶:引领未来的智能出行

自动驾驶技术正日益成为当今科技领域的焦点&#xff0c;它代表着未来出行的一大趋势&#xff0c;而Baidu公司推出的Apollo自动驾驶平台则在这一领域中展现出强大的领导地位。本文将深入探讨Apollo自动驾驶技术的关键特点、挑战以及它对未来智能出行的影响。 Apollo自动驾驶平台…

【python脚本】cv2.putText不显示中文,显示为???????解决方案,亲测有效

【python脚本】cv2.putText不显示中文&#xff0c;显示为&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;解决方案&#xff0c;亲测有效。 text "选中目标区域增强后的\n空间频率是%s,\n信息熵是%s" % (spatialF(gray_over…

wx:for的使用和事件传参,解构赋值的应用

在页面的.js文件中创建了一个对象&#xff0c; 并且在页面的view中调用了两种不同的方法将对象中的元素显示出来&#xff01; 第2种代码要加强理解&#xff01;&#xff01;&#xff01; 小程序中的wx:if wx:elif wx:else 其实好像c语言中的 if-elif-else 在页面的.j…

一个专业级 AI 聊天浏览器,开源了!

公众号关注 “GitHubDaily” 设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01; 在 AI 模型大爆炸的今天&#xff0c;我们每天都能在技术圈见证无数个大语言模型诞生&#xff0c;其诞生速度之快&#xff0c;着实让人看得目不暇接。 对于热衷于体验、调试、评测各种大模型…

【跟小嘉学 Rust 编程】十九、高级特性

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

Pandas由入门到精通-分层索引

采集的数据存储后通常会分为多个文件或数据库,如何将这些文件按需拼接,或按键进行连接十分重要。这节将介绍数据索引的复杂操作如分层索引,stack,unstack,seet_index,reset_index等帮助重构数据,数据的拼接如merge,join,concat,combine_first等帮助连接数据,以及数据透视表…