摘要:<script setup>语法糖: https://cn.vuejs.org/api/sfc-script-setup.html
一、<script setup>语法糖用法
1.1 基本语法:
要使用这个语法,在script 中添加setup属性即可。
<script setup></script>
里面的代码最终会编译成setup()函数中的内容: 所以每次在组件实例被创建时,都会执行;
1.2 顶层绑定自动暴露给模板
当使用<script setup>时候,任何在其中声明的顶层绑定(包括变量,方法,import导入的东西)都可以在template中直接使用,不在需要return,节省代码。
<template>
<div id="app">
{{count}} <button @click="add"></button>
</div>
</template>
<script setup>
import { ref } from "vue";
const count = ref(0)
const add = count.value ++
</script>
1.3 setup 在components中的使用
1.3.1 组件名自动推断
在<script setup>中,不书写组件名,vue会自动把文件名作为组件名,如果想自定义,可以添加普通的script中name配置。
//Foo.vue
<script setup></script>
<script>
export default {
name: 'FooIndex'
}
</script>
1.3.2 动态组件: import导入的组件会被当成变量名,而非字符串,注意;
<template>
<div id="setup">
<component :is="condition ? Foo : Bar" />
</div>
</template>
<script setup>
import { ref } from "vue";
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const condition = ref(true)
setTimeout(() =>{
condition.value = false;
},2000)
</script>
1.3.3 递归组件
一个单文件组件可以通过它的文件名被其自己所引用。例如:名为 FooBar.vue 的组件可以在其模板中用 <FooBar/> 引用它自己。
请注意这种方式相比于导入的组件优先级更低。如果有具名的导入和组件自身推导的名字冲突了,可以为导入的组件添加别名:
import { FooBar as FooBarChild } from './components'
1.3.4 命名空间组件
在单文件中导入过多组件时候,之前需要写很多import,命名空间组件可以简化代码。template中可通过对象点语法使用组件.
index.vue
<template>
<div id="setup">
<All.Foo />
<All.Bar />
</div>
</template>
<script setup>
import { ref } from "vue";
// import Foo from './components/Foo.vue'
// import Bar from './components/Bar.vue'
import * as All from './components'
</script
在components中index.ts,可导入当前所有的子组件
import Foo from './Foo.vue'
import Bar from './Bar.vue'
export {
Foo,
Bar
}
1.4 defineProps 与defineEmits 运行时声明和类型声明写法
1.4.1 运行时声明和类型声明
运行时声明即代码运行后会给出相应的提示,比如子组件在props显式声明title为String类型,编码时传递number类型,Vue会给出相应的提示:类型声明(ts类型检查)即代码过程中,在运行之前,集=结合IDE,ts,就会给出提示,比如标红,下划线等
运行时声明写法
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
// setup 代码
</script>
类型声明写法
const props = defineProps<{
foo: string
bar?: number
}>()
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
1.5 defineExpose:暴露当前组件方法和数据,供父组件调用(结合ref)
//child.vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
const add = () => count.value ++
defineExpose({
count,add
})
</script>
//index.vue
<Child ref="childRef"/>
const childRef = ref(null)
onMounted(() =>{
console.log(childRef.value.count)
})
1.6 useSlots和useAttrs: 主要用与获取当前组件的插槽和attrs信息
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>
1.7 与普通script块一起用,下面这几种情况可以一起用,其他情况,反对混用
声明无法在 <script setup> 中声明的选项,例如 inheritAttrs 或插件的自定义选项。
声明模块的具名导出 (named exports)。
运行只需要在模块作用域执行一次的副作用,或是创建单例对象。
<script>
// 普通 <script>, 在模块作用域下执行 (仅一次)
runSideEffectOnce()
// 声明额外的选项
export default {
name: 'ChildIndex'
inheritAttrs: false,
customOptions: {}
}
</script>
<script setup>
// 在 setup() 作用域中执行 (对每个实例皆如此)
</script>
1.8 顶层await: 顶层不在需要写async, 最终会编译成async setup()
<script setup>
import { ref } from "vue";
const ret = await ( await fetch('https://api.uomg.com/api/rand.qinghua?format=json')).json()
if(ret.code === 1) console.log(ret.content)
// const randWords = ref('')
// const generateWords = async () =>{
// const res = await ( await fetch('https://api.uomg.com/api/rand.qinghua?format=json')).json()
// if(res.code === 1) randWords.value = res.content
// }
</script>
注意: async setup必须和Suspense(实验阶段)结合使用,目前不推荐使用
1.9 限制src引入:禁止<script steup>与src导入的.js,ts一起使用。
<template src="./template.html"></template>
<script src="./script.js"></script>
<style src="./style.css"></template>
//禁止这样混用
<script setup></script>