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来访问slotsattrs,不过当你需要在<script>中使用时,你可以通过useSlotsuseAttrs来获取

⏰ 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-modelv-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>

posted on 2024-07-12 01:24  梁飞宇  阅读(125)  评论(0)    收藏  举报