vue3.x之setup语法糖
<script setup>是Vue3.2正式支持的一个语法糖,在<script setup>中的代码就像是在setup()函数中一样,所有顶级变量、函数、导入的组件都会暴露给模板使用(不用return)
Vue3.0中:变量必须return出来才能在template中才能使用
Vue3.2后:基于script setup 语法糖,无需return
一、语法糖用法:
只需在 script 标签上写上 setup🐰 3.0前用法
<script lang="ts"> //👀:需要什么导入什么 import { ref, reactive, onMounted, computed, watch } from 'vue' export default { name: 'App', //setup函数是组合式API的入口函数,调用在beforeCreated之前 setup() { //1.定义响应式 let person = reactive({ name: 'Vue', age: 28 }) let name = ref('姓名') //2.定义计算属性 let compute = computed(() => { return name.value + 'Hello' }) //3.侦听器 watch(name, (newvalue) => { console.log('name': newvalue) }) //4.定义函数 let myFn = function () { } //5.生命周期 onMounted(() => { }) //属性暴露出来 return {person,compute,myFn} } } </script>
🐰 3.2用法
<script setuup lang="ts"> //👀:需要什么导入什么 import { ref, reactive, onMounted, computed, watch } from 'vue' //1.定义响应式(自动暴露) let person = reactive({ name: 'Vue', age: 28 }) let name = ref('姓名') //2.定义计算属性(自动暴露) let compute = computed(() => { return name.value + 'Hello' }) //4.定义函数(自动暴露) let myFn = function () {} //5.生命周期(自动暴露) onMounted(() => {}) </script>
二、语法糖带来的体验
1. data
<script setup lang="ts"> //👀:需要什么导入什么 import { ref, reactive, toRefs} from 'vue' //【ref】 // 1. ref声明响应式数据,用于声明基本数据类型 const name = ref('Jerry') // 2. 修改 name.value = 'Tom' //【reactive】 // 1.reactive声明响应式数据,用于声明引用数据类型 const state = reactive({ name:'Jerry', age:'男' }) // 2.修改 state.name = 'Tom' //【toRefs】 // 1.使用toRefs结构 const sexRef = toRefs(state) </script>
2.method方法的使用
<template> <button @click="onClickHelp">帮助</button> </template> <script setup lang="ts"> //👀:需要什么导入什么 import { reactive } from 'vue' //1.定义响应式变量 const data = reactive({ aboutExeVisible: false }) //2.定义方法 const onClickHelp = ()=>{ console.log('系统帮助'); data.aboutExeVisible = true } </script>
3.computed
<script setup lang="ts"> //👀:需要什么导入什么 import { computed,ref } from 'vue' //1.定义响应式变量 const count = ref(1) //2.定义计算属性 const doubleCount = computed(() => { return count.value * 2 }) </script>
4.watch
<script setup lang="ts"> //👀:需要什么导入什么 import { watch,ref, reactive } from 'vue' //1.定义响应式变量 const state = reactive({ count:1 }) //2.定义监听 watch( ()=>state.count, //通过函数返回需要监听的数据 (newval,oldval)=>{ console.log(state.count); console.log(`watch监听变化前的数据:${oldval}`) console.log(`watch监听变化后的数据:${newval}`) }, {immediate:true,deep:true}) </script>
5.组件自动注册
在 script setup 中,引入的组件可以直接使用,无需再通过 components 进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写 name 属性了。
// 无需使用components,引入即注册 <script setup> import MyComponent from './MyComponent.vue' </script> <template> <MyComponent /> </template>
6.生命周期钩子函数
<script setup lang="ts"> //👀:需要什么导入什么 import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue' //1.生命周期钩子 onBeforeMount(()=>{ console.log('onBeforeMount'); }) onMounted(() => { console.log('onMounted'); }); onBeforeUpdate(() => { console.log('onBeforeUpdate'); }); onUpdated(() => { console.log('onUpdated'); }); onBeforeUnmount(() => { console.log('onBeforeUnmount'); }); onUnmounted(() => { console.log('onUnmounted'); }); </script>
7.数据通信
⏰ defineProps:子组件接收父组件传值
<template> <div>childProps</div> </template> <script setup lang="ts"> //👀:需要什么导入什么 import { defineProps } from 'vue' //1.定义props,子组件接受父组件传值 const props = defineProps({ childProps: { type: String, default: 'a' } }) </script>
⏰ defineEmits:子组件向父组件触发事件
<template> <button @click="sendMessage">Message</button> <button @click="senderDelete">Delete</button> </template> <script setup lang="ts"> //👀:需要什么导入什么 import { defineEmits } from 'vue' //1.定义Emits,子组件向父组件触发事件 const emit = defineEmits(["acceptMessage","delete"]) //2.定义自定义函数 const sendMessage = function(){ emit('acceptMessage','a') } const senderDelete = function(){ emit('delete','b') } </script>
⏰ defineExpose:父组件中调用子组件方法
作用:在<script setup>组件中明确要暴露出去的属性
- 子组件
<script setup lang="ts"> //👀:需要什么导入什么 import { defineExpose, ref } from 'vue' //1.定义响应式变量 const num = ref(0) //2.定义普通变量 const msg = 'Hello World' //3.定义自定函数 const childFn = function(){ console.log('我是子组件') } //4.明确暴露出去组件内的属性 defineExpose({ num, msg, childFn }) </script>
父组件:<template> <div>childProps</div> <HelloWorld ref="child"></HelloWorld> </template> <script setup lang="ts"> //👀:需要什么导入什么 import {onMounted, ref } from 'vue' import HelloWorld from '@/components/HelloWorld.vue' const child = ref('child') onMounted(()=>{ console.log(child.value); console.log(child.value.num); console.log(child.value.msg); console.log(child.value.childFn); }) </script>
![]()
8. 获取 slots 和 attrs
一般来说,你会在模板中直接通过$slots和$attrs来访问slots和attrs,不过当你需要在<script>中使用时,你可以通过useSlots和useAttrs来获取
⏰ useAttrs:见名知意,这是用来获取 attrs 数据,但是这和 vue2 不同,里面包含了class、属性、方法。
- 子组件
<template> <div>{{ childMsg }} -- {{ childNum }}</div> </template> <script setup lang="ts"> //👀:需要什么导入什么 import { defineProps, useAttrs } from 'vue' //1.定义props defineProps(['childMsg']) console.log(useAttrs()); //返回一个Proxy对象 //2.定义atts let {childNum} = useAttrs() </script>
- 父组件
<template> <HelloWorld :childMsg='msg' :childNum='num'></HelloWorld> </template> <script setup lang="ts"> //👀:需要什么导入什么 import {ref } from 'vue' import HelloWorld from '@/components/HelloWorld.vue' let msg = ref('我是父组件的msg数据') let num = ref(10) </script>
- 效果如下
![]()
⚠️ 注意:接收父组件传递没有被defineProps接收的属性
⏰ useSlots:顾名思义,获取插槽数据。
- 子组件
<template> <div>useSlots获取沟槽信息</div> <slot name="header">header</slot><br> <slot name="footer">footer</slot> </template> <script setup lang="ts"> //👀:需要什么导入什么 import { useSlots,onMounted } from 'vue' //1.定义slots const slots = useSlots() onMounted(() => { console.log(slots); }); </script>
- 父组件
<template> <HelloWorld :childMsg='msg' :childNum='num'> <!-- header --> <template v-slot:header> <span>header</span> </template> <!-- footer --> <template v-slot:footer> <span>footer</span> </template> </HelloWorld> </template> <script setup lang="ts"> //👀:需要什么导入什么 import {ref } from 'vue' import HelloWorld from '@/components/HelloWorld.vue' let msg = ref('我是父组件的msg数据') let num = ref(10) </script>
- 效果如下
![]()
9.v-model
支持绑定多个v-model,v-model 是 v-model:modelValue 的简写
绑定其他字段,如:v-model:name
- 子组件
<template> <span @click="changeInfo">我叫{{ modelValue }},今年{{ age }}岁</span> </template> <script setup> // import { defineEmits, defineProps } from 'vue' // defineEmits和defineProps在<script setup>中自动可用,无需导入 // 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】、【defineProps: true】 defineProps({ modelValue: String, age: Number }) const emit = defineEmits(['update:modelValue', 'update:age']) const changeInfo = () => { // 触发父组件值更新 emit('update:modelValue', 'Tom') emit('update:age', 30) } </script>
- 父组件
<template> // v-model:modelValue简写为v-model // 可绑定多个v-model <child v-model="state.name" v-model:age="state.age"/> </template> <script setup> import { reactive } from 'vue' // 引入子组件 import child from './child.vue' const state = reactive({ name: 'Jerry', age: 20 }) </script>
10.provide和inject
在开发中往往会嵌套一定深度的组件,为了让更深层级的组件获取到上层组件的数据和方法我们可以使用provide()、inject()函数来实现
- 子组件
<script setup> import { inject } from 'vue' // 注入,第二个参数为默认值 const provideState = inject('provideState', {}) // 子组件触发name改变 provideState.changeName() </script>
- 父组件
<template> <child/> </template> <script setup> import { ref, watch, provide } from 'vue' // 引入子组件 import child from './child.vue' let name = ref('Jerry') // 声明provide provide('provideState', { name, changeName: () => { name.value = 'Tom' } }) // 监听name改变 watch(name, () => { console.log(`name变成了${name}`) setTimeout(() => { console.log(name.value) // Tom }, 1000) }) </script>
11. 顶层await
<script setup>是默认声明async的,类似于async setup()的效果,你可以在<script setup>中直接使用await函数:
<script setup> const res = await fetch("/api/getData") </script>
12.路由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>



浙公网安备 33010602011771号