Vue3.2 setup syntax sugar, you deserve it

0. Foreword

The data function in vue2 is deleted in vue3. Therefore, if vue3.0 uses certain variables in the template, it must be returned at the end. It is not convenient and friendly to declare variables multiple times. After the vue3.2 version, we only need to add the setup attribute to the script tag, and it can be used directly in the template without writing return, and writing code is very smooth. Hey, this is great!

Vue3.0 writing sample code.

<template>
  <div>
    <p>{
    
    {
    
     `${
      
      state.name}发布于${
      
      state.age}${
      
      msg}` }}</p>

    <button @click="onClick">点击</button>

    <ChildComp />
  </div>
</template>

<script lang="ts">
import {
    
     defineComponent, ref, reactive } from "vue"
import ChildComp from './ChildComp.vue'

export default defineComponent({
    
    
  // 注册组件
  components: {
    
    
    ChildComp
  },
  props: {
    
    
    show: {
    
    
      type: Boolean,
      default: false
    }
  },
  emits: ['on-confirm'],

  setup(props, {
     
      emit }) {
    
    
    console.log(props.show) // false

    const msg = ref('');
    msg.value = '哎,这就很不棒!';

    const state = reactive({
    
    
      name: 'vue3.0',
      age: '2020年9月18日'
    })
    // 点击事件
    const onClick = () => {
    
    
      emit('on-confirm')
    }
    // 必须return出来
    return {
    
    
      msg,
      state,
      onClick
    }
  }
})
</script>

When you first started using the script setup syntactic sugar, the editor will prompt that this is an experimental attribute. If you want to use it, you need to fix the vue version. At the end of June 2021, the proposal was officially finalized. On the vue3.1.3 version, it will continue to be used but there will still be hints of the experimental proposal. In vue3.2, the hints will be removed and some obsolete APIs will be removed.

script setup is a new grammatical sugar of vue3.2, not a new functional module. The main advantages are: (1) less template content, concise code, no need to write return; (2) better declaration using ts props, and throw events; (3) better runtime performance.

1. Variables and methods do not need to return

Variables, methods, and imported content do not need to be exposed in return, and there is no need to write export default and setup functions, just add the setup attribute to the script tag, and directly declare variables, methods, and imported content to use, making the template code more concise.

<template>
  <div>
    <!-- 使用变量 -->
    <p>{
    
    {
    
     `${
      
      state.name}发布于${
      
      state.age}${
      
      msg}` }}</p>
    <!-- import导入 -->
    <ul>
      <li v-for="item in subjectList" :key="item.value">
        {
    
    {
    
    item.label}}
      </li>
    </ul>
    <!-- 使用方法 -->
    <button @click="onClick">点击</button>
  </div>
</template>

<!-- 在script标签上添加setup属性 -->
<script setup lang="ts">
import {
    
     ref, reactive } from "vue"
import {
    
     subjectList } from './utils.js'

const msg = ref('');
msg.value = '哎,这就很棒!';

const state = reactive({
    
    
  name: 'vue3',
  age: '2020年9月18日'
})

// 点击事件
const onClick = ():void => {
    
    
  console.log('点击了')
}
</script>

2. Introduce component automatic registration

Introduce components in the script setup syntactic sugar, the components do not need to be registered in components, the imported components will be automatically registered, and the component cannot specify the name attribute, mainly the name of the file, the name attribute is omitted

<template>
  <div>
    <Child />
  </div>
</template>

<!-- 在script标签上添加setup属性 -->
<script setup lang="ts">
import Child from './Child.vue'
</script>

3、defineProps和defineEmits

The defineProps and defineEmits API must be used in script setup to declare props and emits, they have complete type inference and are directly available in script setup without importing. Options passed into defineProps and defineEmits are hoisted from setup to the module's scope, so passed options cannot refer to local variables declared in setup scope, doing so will cause a compile error.

(1)defineProps

//父组件
<template>
  <div>
    <Child :name="name" />
  </div>
</template>

<!-- 在script标签上添加setup属性 -->
<script setup lang="ts">
import {
    
     ref } from 'vue';
import Child from './Child.vue';

const name = ref('张三')
</script>
//子组件
<template>
  <div>
    <p>{
    
    {
    
     `${
      
      props.name}在学习JavaScript` }}</p>
  </div>
</template>

<script setup lang="ts">
// defineProps不需要从vue中导入
const props = defineProps({
    
    
  name: {
    
    
    type: String,
    default: '张三'
  }
})
// 或者
const props = defineProps(['name'])
</script>

(2)defineEmits

// 父组件
<template>
  <div>
    <Child @on-confirm="onConfirm" />
  </div>
</template>

<script setup lang="ts">
import {
    
     ref } from 'vue';
import Child from './Child.vue';

const show = ref(false)
// 点击确定关闭弹框等操作
const onConfirm = (val: boolean) => {
    
    
  show.value = val
} 
</script>
// 子组件
<template>
  <button type="button" @click="handleConfirm">确定</button>
</template>

<script setup lang="ts">
const emit = defineEmits(['on-confirm'])

const handleConfirm = () => {
    
    
  // 此处也可以传入参数
  emit('on-confirm', false)
}
</script>

4、defineExpose

defineExpose can actively expose the properties and methods of components.

// 子组件示例代码
// 子组件
<template>
  <div v-if="show">
    <p>{
    
    {
    
     count }}</p>
  </div>
</template>

<script setup lang="ts">
import {
    
     ref } from 'vue';

const count = ref(0)
const show = ref(false)

const onShow = () => {
    
    
  show.value = true
}
// defineExpose暴露出count属性和onShow方法
defineExpose({
    
    
  count,
  onShow
})
</script>
// 父组件示例代码
// 父组件
<template>
  <div>
    <button type="button" @click="onClick">父组件点击</button>
    <Child ref="childRef" />
  </div>
</template>

<script setup lang="ts">
import {
    
     ref } from 'vue';
import Child from './Child.vue';
// Child组件的ref
const childRef = ref(null)

// 在父组件操作子组件的暴露出的属性或方法
const onClick = () => {
    
    
  childRef.value.count += 1;
  childRef.value.onShow();
}
</script>

5. useSlots and useAttrs

It should be rare to use slots and attrs in script setup. Most people are developing in (SFC) mode. Slots can be rendered <template/>through tags, and they can be accessed through $slots and $attrs in the template. <slot/>It is mainly used in JSX/TSX.

(1)useSlots

slots can get the virtual Dom object passed by the slot in the parent component.

// 父组件
<template>
  <Child>
    <span>默认插槽</span>
    <template v-slot:footer>
      <div>具名插槽footer</div>
    </template>
  </Child>
</template>

<script setup>
import Child from './Child.vue'
</script>
// 子组件
<template>
  <div>
    <!-- 在模板中使用插槽 -->
    <slot></slot>
    <slot name="footer"></slot>
  </div>
</template>

<script setup lang="ts">
import {
    
     useSlots } from 'vue'
 
const slots = useSlots()
// 访问插槽默认插槽default、具名插槽footer
console.log(slots.default)
console.log(slots.footer)
</script>

(2)useAttrs

attrs is used to obtain non-props attributes passed to child components in the parent component, including class and style attributes.

// 父组件
<template>
  <Child class="child-class" title="子组件title" />
</template>

<script setup>
import Child from './Child.vue'
</script>
// 子组件
<template>
  <!-- 在模板中使用 $attrs 访问属性 -->
  <div>{
    
    {
    
     $attrs.title }}</div>
</template>

<script setup lang="ts">
import {
    
     useAttrs } from 'vue'
 
const attrs = useAttrs()
// 使用
console.log(attrs.class)  // child-class
console.log(attrs.title)  // 子组件title
</script>

Use in jsx/tsx

<script lang="tsx">
import {
    
     defineComponent, ref, useSlots } from 'vue';
export default defineComponent({
    
    
  setup(){
    
    
    const slots = useSlots();
    const str = ref<string>('tsx的使用');

    return () => (
      <>
        <div class='async'>{
    
    str.value}</div>
        <div>{
    
     slots.default ? slots.default() : 'foo' }</div>
        <div>{
    
     slots.bar?.() }</div>
      </>
    );
  }
})
</script>

6. Top-level await

<script setup>You can use top-level await in . The resulting code will be compiled into async setup(), and the await expression will be automatically compiled into a format that preserves the context of the current component instance after the await.

<script setup lang="ts">
import {
    
     getUserInfo } from '@/api/system'

const userInfo = await getUserInfo();
console.log(userInfo)
</script>
// api/system
export const getUserInfo = async () => {
    
    
  const res: any = await request.get(`/api/user/info`)
  return res
}

7, with ordinary

<script setup>Can be used with <script>normal . Ordinary may be used <script>in situations where:

  • Options that cannot be <script setup>declared , such as inheritAttrs or custom options enabled via plugins.
  • Declares a named export.
  • Run side effects or create objects that only need to be executed once
<script>
// 普通 <script>, 在模块范围下执行(只执行一次)
runSideEffectOnce()

// 声明额外的选项
export default {
    
    
  inheritAttrs: false,
  customOptions: {
    
    }
}
</script>

<script setup>
// 在 setup() 作用域中执行 (对每个实例皆如此)
</script>

8. Summary

The syntactic sugar of script setup is really delicious! The content of the template is less, and the code is more brief, so it is necessary to learn, friends, hurry up and learn. Here are a few commonly used grammatical sugar usages, and some other usages can be learned by yourself. If the article is written inappropriately, please correct and modify it. If you feel that the article is practical and helpful to you, welcome to like, collect and follow. Your likes and concerns are my motivation. Let's learn and progress together.

Guess you like

Origin blog.csdn.net/qq_39327418/article/details/125667307