Vue3 script setup 语法糖

script setup 语法糖

一、组合式 API:setup()

Vue 3 的 Composition API 系列里,推出了一个全新的 setup 函数,它是一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点。
setup 选项是一个接收 propscontext 的函数,我们将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。

<script>
// 这是一个基于 TypeScript 的 Vue 组件
import { defineComponent } from 'vue'

export default defineComponent({
  setup(props, context) {
    // 在这里声明数据,或者编写函数并在这里执行它

    return {
      // 需要给 `<template />` 用的数据或函数,在这里 `return` 出去
    }
  },
})

</script>

新的 setup 选项是在组件创建之前, props 被解析之后执行,是组合式 API 的入口。
注意:
①在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法>在 setup 中被获取。
②在添加了setup的script标签中,我们不必声明和方法,这种写法会自动将所有顶级变量、函数,均会自动暴露给模板(template)使用
这里强调一句 “暴露给模板,跟暴露给外部不是一回事”
TIP
说的通俗一点,就是在使用 Vue 3 生命周期的情况下,整个组件相关的业务代码,都可以放在 setup 里执行。
组件生命周期
关于 Vue 生命周期的变化,可以从下表直观地了解:

Vue 2 生命周期 Vue 3 生命周期
beforeCreate setup --组件创建前执行
created setup–组件创建后执行
beforeMount onBeforeMount–组件挂载到节点上之前执行
mounted onMounted–组件挂载完成后执行
beforeUpdate onBeforeUpdate–组件更新之前执行
updated onUpdated–组件更新完成之后执行
beforeDestroy onBeforeUnmount–组件卸载之前执行
destroyed onUnmounted–组件卸载完成后执行
errorCaptured onErrorCaptured–当捕获一个来自子孙组件的异常时激活钩子函数

Vue 2 生命周期里的 beforeCreatecreated ,在 Vue 3 里已被 setup 替代。

二、script setup 语法糖

它是 Vue3 的一个新语法糖,在 setup 函数中。所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。
1、自动注册属性和方法无需返回,直接使用
①、script setup语法糖并不是新增的功能模块,它只是简化了以往的组合API(compositionApi)的必须返回**(return)**的写法,并且有更好的运行时性能。
②、在 setup 函数中:所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 ​​setup()​​ 返回对象中。相对于之前的写法,使用后,语法也变得更简单。
你不必担心​​setup语法糖​​的学习成本,他是组合式API的简化,并没有新增的知识点。你只需要了解一些用法和细微的不同之处,甚至比之前写​​setup()​​还要顺手!
使用方式也很简单,只需要在 script 标签加上 setup 关键字即可

<script setup>
</script>

2、组件核心 API 的使用
ref 暴露变量到模板
ref是最常用的一个响应式 API,它可以用来定义所有类型的数据,包括 Node 节点和组件。返回一个响应式对象,所有的值都通过 .value 属性获取。

<template>
    <div>{
   
   {counter}}</div>
</template>
<script setup >
import { ref } from 'vue'

const counter = ref(0);//不用 return ,直接在 templete 中使用

const timer = setInterval(() => {
    counter.value++
}, 1000)

onUnmounted(() => {
    clearInterval(timer);
})
</script>

reactive
返回一个对象的响应式代理。

<script setup>
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对象**
reactive的底层是Proxy,ref的本质也是用reactive来包装,所以也是Proxy,ref本质也是reactive
ref(obj)等价于reactive({value: obj})
3、组件自动注册
script setup 中,引入的组件可以直接使用,无需再通过components进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写name属性了。
示例:

<template>
	<Child />
</template>

<script setup>
import Child from '@/components/Child.vue'
</script>

4、定义组件的 props
defineProps—>[用来接收父组件传来的props]
通过defineProps指定当前props类型,获得上下文的props对象
示例:

<script setup>
   // defineEmits,defineProps无需导入,直接使用
   const props = defineProps({
      title: String,
   })
</script>
<!-- 或者 -->
<script setup lang="ts"> 
    import { ref,defineProps } from 'vue';
    
    type Props={ 
        msg:string 
    }
    defineProps<Props>(); 
</script>

5、定义 emit
defineEmit—>[子组件向父组件传递事件]
使用defineEmit定义当前组件含有的事件,并通过返回的上下文去执行emit
代码示列:

<script setup>
     // defineEmits,defineProps无需导入,直接使用
     const emit = defineEmits(['change','delete'])
</script>

6、defineExpose API
defineExpose —>[组件暴露出自己的属性]
传统的写法,我们可以在父组件中,通过ref实例的方式去访问子组件的内容,但在 script setup 中,该方法就不能用了,setup相当于是一个闭包,除了内部的 template 模板,谁都不能访问内部的数据和方法。
script setup 的组件默认不会对外部暴露任何内部声明的属性。如果有部分属性要暴露出去,可以使用 defineExpose
注意:目前发现 defineExpose 暴露出去的属性以及方法都是 unknown 类型,如果有修正类型的方法,欢迎评论区补充。
如果需要对外暴露 setup 中的数据和方法,需要使用 defineExpose API。示例:

//子组件
<template>
     {
   
   {msg}}
</template>
<script setup>
import  {ref} from 'vue'
let msg = ref("Child Components");
let num = ref(123);
// defineExpose无需导入,直接使用
defineExpose({
      msg,
     num
})
</script>
//父组件
<template>
    <Child ref="child"  />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from '@/components/Child.vue'

let child = ref(null);
onMounted(() => {
    console.log(child.value.msg); // Child Components
	console.log(child.value.num); // 123
})
</script>

7、父子组件通信

//父组件
<template>
  <div class="wrapper">
     <Child :page="page"
                @pageFn="pageFn"
                ref="childRef"
     >
    <button @click="doSth1"> defineExpose</button>
  </div>
</template>

<script setup>
import {ref} from 'vue'
import Child from './Child.vue'

const childRef = ref();
const page = ref(1)
const  pageFn = (num) => {
  page.value += num
}
function doSth1() {
  console.log(childRef.value)
  childRef.value.doSth();
}
</script>

<style scoped>
div {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
</style>
//子组件
<template>
  <!--  <p>子</p>-->
  <button @click="butFn">改变page值: {
   
   { page }} </button>
</template>
<script setup>
// defineEmits,defineProps无需导入,直接使用
const props = defineProps({
    page: Number
});//接收父组件传来的值
const emit = defineEmits(["pageFn"]); //定义一个变量来接收父组件传来的方法
const butFn = () => {
   emit('pageFn', props.page)
}
function doSth(){
   console.log(333,'defineExpose');
}
defineExpose({ doSth });
// 获取父组件传递过来的数据
console.log(props.page, "parent value"); // parent value
</script>
<style scoped>
button {
  margin: 20px;
}
</style>

子组件通过 defineProps 接收父组件传过来的数据,子组件通过 defineEmits 定义事件发送信息给父组件,使用defineExpose子组件传父组件

猜你喜欢

转载自blog.csdn.net/renfeideboke/article/details/129127105