Vue3 script setup syntactic sugar, just ask if you are sweet or not

script setup syntactic sugar

Composition API: setup()

basic use

In the Composition API series of Vue 3, a brand new  setup function is introduced, which is a component option, executed before the component is created, once the props are parsed, and serves as the entry point of the composition API.

setup options is a  function that takes a props sum  context , we refer to the documentation for discussion. Additionally, we  setup expose everything we return to the rest of the component (computed properties, methods, lifecycle hooks, etc.) as well as the component's template.

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

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

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

</script>
复制代码

The new  option is executed beforesetup  the component is created and after it   is parsed, and it is the entry point of the combined API.props

NOTE:  You should avoid using 
in  because it won't find the component instance.  The call to the property happens before the   property,  property  or  is parsed, so they cannot >  be obtained in thesetupthissetupdatacomputedmethodssetup

In the script tag with setup added, we don’t have to declare and method, this way of writing will automatically expose all top-level variables and functions to the template (template) for use one thing "

TIP: To put it simply, in the case of using the Vue 3 life cycle, the business code related to the entire component can be  setup executed in it.

因为在 setup 之后,其他的生命周期才会被启用,我们对比一下Vue2的Vue3生命周期的变化

组件生命周期

关于 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 生命周期里的 beforeCreate 和 created ,在 Vue 3 里已被 setup 替代。

script setup 语法糖

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

自动注册属性和方法无需返回,直接使用

1.<script setup> 语法糖并不是新增的功能模块,它只是简化了以往的组合API(compositionApi)的必须返回(return)的写法,并且有更好的运行时性能。

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

你不必担心​​setup语法糖​​的学习成本,他是组合式API的简化,并没有新增的知识点。你只需要了解一些用法和细微的不同之处,甚至比之前写​​setup()​​还要顺手!

使用方式也很简单,只需要在 script 标签加上 setup 关键字即可

<script setup>
</script>
复制代码

组件核心 API 的使用

组件自动注册

在 script setup 中,引入的组件可以直接使用,无需再通过components进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写name属性了。

示例

<template>
	<Child />
</template>

<script setup>
import Child from '@/components/Child.vue'
</script>
复制代码

定义组件的 props

defineProps ----> [用来接收父组件传来的 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 ----> [子组件向父组件事件传递]

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

 代码示列

<script setup>
  import { defineEmits } from 'vue'
  const emit = defineEmits(['change', 'delete'])
  
</script>
复制代码

父子组件通信

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

//父组件
<template>
	<Child @getChild="getChild" :title="msg" />
</template>

<script setup>
import { ref } from 'vue'
import Child from '@/components/Child.vue'
const msg = ref('parent value')
const getChild = (e) => {
	// 接收父组件传递过来的数据
	console.log(e); // child value
}
</script>

复制代码
//子组件
<template>
	<div @click="toEmits">Child Components</div>
</template>

<script setup>
// defineEmits,defineProps无需导入,直接使用
const emits = defineEmits(['getChild']);
const props = defineProps({
	title: {
		type: String,
		defaule: 'defaule title'
	}
});

const toEmits = () => {
	emits('getChild', 'child value') // 向父组件传递数据
}

// 获取父组件传递过来的数据
console.log(props.title); // parent value
</script>

复制代码

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

useSlots() 和 useAttrs()

获取 slots 和 attrs

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

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

  1. useAttrs:见名知意,这是用来获取 attrs 数据,但是这和 vue2 不同,里面包含了 class属性方法
<template>
    <component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>
   const attrs = useAttrs();
<script>
复制代码
  1. 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>
复制代码

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>


复制代码

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

<script setup > 
import { ref,computed,watchEffect } from 'vue';

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

const addCount=()=>{ //定义函数,使用同上 
    count.value++; 
} 

//创建一个只读的计算属性 ref:
const plusOne = computed(() => count.value + 1)

// 创建一个可写的计算属性 ref
const plusOne = computed({
get: () => count.value + 1, 
set: (val) => { count.value = val - 1 } 
})


//定义监听,使用同上 //...some code else 
watchEffect(()=>console.log(count.value)); 
</script>
复制代码

watchEffect和watch区别

1、watch是惰性执行,也就是只有监听的值发生变化的时候才会执行,但是watchEffect不同,每次代码加载watchEffect都会执行(忽略watch第三个参数的配置,如果修改配置项也可以实现立即执行)

2、watch需要传递监听的对象,watchEffect不需要

3、watch只能监听响应式数据:ref定义的属性和reactive定义的对象,如果直接监听reactive定义对象中的属性是不允许的,除非使用函数转换一下

4、watchEffect如果监听reactive定义的对象是不起作用的,只能监听对象中的属性。

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对象

ref 暴露变量到模板

曾经的提案中,如果需要暴露变量到模板,需要在变量前加入export声明:

export const count = ref(0)
复制代码

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

<script setup >
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>
复制代码

其他 Hook Api

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

支持 async await 异步

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

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

<script setup> 中可以使用顶层 await。结果代码会被编译成 async setup()

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

另外,await 的表达式会自动编译成在 await 之后保留当前组件实例上下文的格式。

Note that
async setup()  it must be  used in Suspense combination with , which Suspense is still an experimental feature. We plan to develop and provide documentation in one of the future releases - if you're interested now, check  out the tests  to see how it works.

Define other configurations of components

In the absence of configuration items, sometimes we need to change component options, setupwhich we currently cannot do in . We need 上方to introduce another one  script, just write the corresponding one above  export, and need to open a script separately.

<script setup> Can be used with normal  <script> . Ordinary  <script> may be used when there are these needs:

  • Options that cannot be  <script setup> declared, for example,  inheritAttrs or customized via plugins.
  • Declares a named export.
  • Run side effects or create objects that only need to be executed once.

Use export default outside script setup, its content will be processed and put into the original component declaration field.

<script>
// 普通 `<script>`, 在模块范围下执行(只执行一次)
runSideEffectOnce()

// 声明额外的选项
  export default {
    name: "MyComponent",
    inheritAttrsfalse,
    customOptions: {}
  }
</script>
<script setup>
    import HelloWorld from '../components/HelloWorld.vue'
    // 在 setup() 作用域中执行 (对每个实例皆如此)
    // your code
</script>
<template>
  <div>
    <HelloWorld msg="Vue3 + TypeScript + Vite"/>
  </div>
</template>
复制代码

Note: Vue 3 SFC will generally automatically infer the component's name from the component's filename. In most cases, no explicit name declaration is required. The only time you need this is when you need  <keep-alive> options to include or exclude or inspect components directly.

refer to

Gaby

View

[木依Sam]( I didn’t know until I got started, Vue3’s script setup syntax sugar is really cool- Nuggets (juejin.cn) )

Guess you like

Origin juejin.im/post/7166145871246000159