关于 Vue3 setup 语法糖
Posted zjy4fun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于 Vue3 setup 语法糖相关的知识,希望对你有一定的参考价值。
Vue3 setup
新的 setup 是组件创建之前, props 被解析之后执行,是组合式 API 的入口
在 setup 中应该避免使用 this, 因为它不会找到示例。setup 的调用发生在 data property,computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取
setup 是一个接收 props 和 context 的函数,setup 返回的所有内容都暴露给组件的其余部分(计算属性、方法、生命周期钩子等等)以及组件的模版,所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup()返回对象中。
使用后,script 标签中的内容相当于原本组件声明中 setup() 的函数体,不过也有一定的区别。
使用 script setup 语法糖,组件只需引入不用注册,属性和方法也不用返回,也不用写 setup 函数,也不用洗 export default,甚至是自定义指令也可以在我们的 template 中自动获得。
调用时机
创建组实例,然后初始化 props,紧接着就调用 setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用。
模板中使用
如果 setup 返回(以count例子来看,可以暂时理解为创建)一个对象,则对象的属性将会被合并到组件模板的渲染上下文。
setup 参数
第一个参数接收一个响应式的 props ,这个 props 指向的是外部的 props。如果没有定义 props 选项,setup 中的第一个参数将为 undefined。
- 不要在自组件中修改 props,如果尝试修改,会得到警告甚至报错
- 不要解构 props,解构的 props 会失去响应式
第二个参数提供了一个上下文对象
组件自动注册
导入 component 或 directive 直接 import 即可,无需额外声明
import MyButton from "@/components"
import directive as clickOutside from \'v-click-outside\'
在 script setup 中,引入的组件可以直接使用,无需再通过 components 进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是无法再写 name 属性了。
如果需要定义类似 name 的属性,可以再加个平级的 script 标签,在里面实现即可
组件核心 API 的使用
定义组件的 props
通过 defineProps 指定当前的 props 类型,获得上下文的 props 对象。
<script setup>
import defineProps from \'vue\'
const props = defineProps(
title: String
)
</script>
或者
<script setup lang="ts">
import ref, defineProps from \'vue\'
type Props =
msg: string
defineProps<Props>()
</script>
定义 emit
使用 defineEmit 定义当前组件含有的事件,并通过返回的上下文去执行 emit
<script setup>
import defineEmit from \'vue\'
const emit = defineEmit([\'change\', \'delete\'])
</script>
父子组件通信
defineProps
用来接收父组件传来的 props;defineEmits
用来声明触发的事件
父组件
<template>
<my-son :foo="count" @childClick="childClick"></my-son>
</template>
<script setup lang="ts">
import MySon from "./MySon.vue";
import ref from "vue";
let count = ref(0)
let childClick = (e: any): void =>
count.value++
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"]); // 声明触发事件
const props = defineProps(foo: Number) // 获取 props
const sonToFather = () =>
emit("childClick", props.foo)
</script>
<style scoped></style>
自组件通过 defineProps 接收父组件传过来的数据,自组件通过 defineEmits 定义事件发送信息给父组件
增强的 props 类型定义
const props2 = defineProps<
foo: number,
bar?: number
>()
const emit2 = defineEmits<(
e: \'update\' | \'delete\',
id: number
) => void>()
采用这种方法将无法使用 props 默认值
定义响应变量、函数、监听、计算属性 computed
watchEffect
<script setup lang="ts">
import ref, computed, unref, watchEffect from \'vue\';
const count = ref(0) // 不用 return ,直接在 template 中使用
const addCount = () =>
count.value ++
// 定义计算属性,使用同上
const howCount = computed(() => "现在count值为: " + count.value)
// 定义监听,使用同上,用于有副作用的监听,会自动收集依赖,和 watch 区别:无需区分deep,immediate,只要依赖的数据发生变化就会调用
watchEffect(() => console.log(count.value))
</script>
reactive
reactive 是一个响应式对象,ref 是一个 value: \'xxx\' 的结构
<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 暴露变量到模板
无需 export 声明,编译器会自动寻找模板中使用的变量。
生命周期方法
因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。
换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。
可以在生命周期钩子前面加上 "on" 来访问组件的声明周期钩子。
获取 slots 和 attrs
useAttrs
和 useSlots
useAttrs 得到的结果
defineExpose API
传统的写法,我们可以在父组件中,通过 ref 实例的方式去访问自组件的内容,但在 script setup 中,该方法就不能用了,setup 相当于是一个闭包,除了内部的 template 模板,谁都不能访问内部的数据和方法。
如果需要对外暴露 setup 中的数据和方法,需要使用 defineExpose API
const a = 1
const b = ref(2)
defineExpose(a,b)
未亲自测试!!
支持 async await 异步
在 vue3 的源代码中,setup 执行完毕,函数 getCurrentInstance 内部的有个值会释放对 currentInstance 的引用
await 语句会导致后续代码进入异步执行的情况。
所以上述例子中最后一个 getCurrentInstance() 会返回 null,建议使用变量保存第一个 getCurrentInstance() 返回的引用
上述结论还没有亲自实验证实
定义组件其它配置
配置项的缺失,有时候我们需要更改组件选项,在 setup 中我们目前是无法做到的。
我们需要在上方再引入一个 script ,在上方写入对应的 export 即可,需要单开一个 script
Vue3.2 setup语法糖总结
前言
提示:Vue3.2
版本开始才能使用语法糖!
在 Vue3.0
中变量必须 return
出来,template
中才能使用;而在 Vue3.2
中只需要在 script
标签上加上 setup
属性,无需 return
,template
便可直接使用,非常的香啊!
一、如何使用setup语法糖
只需在 script
标签上写上setup
代码如下(示例):
<template>
</template>
<script setup>
</script>
<style scoped lang="less">
</style>
二、data数据的使用
由于 setup
不需写 return
,所以直接声明数据即可
代码如下(示例):
<script setup>
import
ref,
reactive,
toRefs,
from 'vue'
const data = reactive(
patternVisible: false,
debugVisible: false,
aboutExeVisible: false,
)
const content = ref('content')
//使用toRefs解构
const patternVisible, debugVisible, aboutExeVisible = toRefs(data)
</script>
三、method方法的使用
代码如下(示例):
<template >
<button @click="onClickHelp">vue3体验新方法</button>
</template>
<script setup>
import reactive from 'vue'
const data = reactive(
aboutExeVisible: false,
)
// 点击帮助
const onClickHelp = () =>
console.log('vue3体验新方法')
data.aboutExeVisible = true
</script>
四、watchEffect的使用
代码如下(示例):
<script setup>
import
ref,
watchEffect,
from 'vue'
let sum = ref(0)
watchEffect(()=>
const x1 = sum.value
console.log('watchEffect所指定的回调执行了')
)
</script>
五、watch的使用
代码如下(示例):
<script setup>
import
reactive,
watch,
from 'vue'
//数据
let sum = ref(0)
let msg = ref('hello word')
let person = reactive(
name:'coderkey',
age:18,
job:
j1:
salary:20
)
// 两种监听格式
watch([sum,msg],(newValue,oldValue)=>
console.log('sum或msg变了',newValue,oldValue)
,immediate:true)
watch(()=>person.job,(newValue,oldValue)=>
console.log('person的job变化了',newValue,oldValue)
,deep:true)
</script>
六、computed计算属性的使用
computed
计算属性有两种写法(简写和考虑读写的完整写法)
代码如下(示例):
<script setup>
import
reactive,
computed,
from 'vue'
//数据
let person = reactive(
firstName:'coder',
lastName:'key'
)
// 计算属性简写
person.fullName = computed(()=>
return person.firstName + '-' + person.lastName
)
// 完整写法
person.fullName = computed(
get()
return person.firstName + '-' + person.lastName
,
set(value)
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
)
</script>
七、props父子传值的使用
子组件代码如下(示例):
<template>
<span>props.name</span>
</template>
<script setup>
import defineProps from 'vue'
// 声明props
const props = defineProps(
name:
type: String,
default: '11'
)
// 或者
//const props = defineProps(['name'])
</script>
父组件代码如下(示例):
<template>
<child :name='name'/>
</template>
<script setup>
import ref from 'vue'
// 引入子组件
import child from './child.vue'
let name= ref('coderkey')
</script>
八、emit子父传值的使用
子组件代码如下(示例):
<template>
<button @click="sonClick">
确定
</button>
</template>
<script setup>
import defineEmits from 'vue';
// emit
const emit = defineEmits(['aboutExeVisible'])
/**
* 方法
*/
// 点击确定按钮
const sonClick= () =>
emit('customClick');
</script>
父组件代码如下(示例):
<template>
<AdoutExe @customClick="sonSendFatherMethod" />
</template>
<script setup>
import reactive from 'vue'
// 导入子组件
import soncomponent from '../components/soncomponent'
const data = reactive(
aboutExeVisible: false,
)
// content组件ref
// 关于系统隐藏
const sonSendFatherMethod= () =>
data.aboutExeVisible = false
</script>
九、获取子组件ref变量和defineExpose暴露
即vue2
中的获取子组件的ref
,直接在父组件中控制子组件方法和变量的方法。
子组件代码如下(示例):
<template>
<p>data </p>
</template>
<script setup>
import
reactive,
toRefs
from 'vue'
/**
* 数据部分
* */
const data = reactive(
modelVisible: false,
historyVisible: false,
reportVisible: false,
)
defineExpose(
...toRefs(data),
)
</script>
父组件代码如下(示例):
<template>
<button @click="btnClick">点击</button>
<Content ref="content" />
</template>
<script setup>
import ref from 'vue'
// content组件ref
const content = ref('content')
// 点击设置
const btnClick= ( key ) =>
content.value.modelVisible = true
</script>
<style scoped lang="less">
</style>
十、路由useRoute和useRouter的使用
代码如下(示例):
<script setup>
import useRoute, useRouter from 'vue-router'
// 声明
const route = useRoute()
const router = useRouter()
// 获取query
console.log(route.query)
// 获取params
console.log(route.params)
// 路由跳转
router.push(
path: `/index`
)
</script>
十一、store仓库的使用
代码如下(示例):
<script setup>
import useStore from 'vuex'
import num from '../store/index'
const store = useStore(num)
// 获取Vuex的state
console.log(store.state.number)
// 获取Vuex的getters
console.log(store.state.getNumber)
// 提交mutations
store.commit('fnName')
// 分发actions的方法
store.dispatch('fnName')
</script>
十二、await 的支持
setup
语法糖中可直接使用 await
,不需要写 async
, setup
会自动变成 async setup
代码如下(示例):
<script setup>
import getData from '../api/Api'
const data = await getData()
console.log(data)
</script>
十三、provide 和 inject 祖孙传值
父组件代码如下(示例):
<template>
<sonComponent />
</template>
<script setup>
import ref,provide from 'vue'
import sonComponent from '@/components/sonComponent'
let name = ref('pink')
// 使用provide
provide('provideState',
name,
changeName: () =>
name.value = 'coderkey'
)
</script>
子组件代码如下(示例):
<script setup>
import inject from 'vue'
const provideState = inject('provideState')
provideState.changeName()
</script>
以上是关于关于 Vue3 setup 语法糖的主要内容,如果未能解决你的问题,请参考以下文章