vue3.2单文件组件 <script setup> 语法糖常用写法

<script setup> 是在单文件组件中使用组合式 API 的编译时语法糖,当使用 <script setup> 的时候,任何在其中声明的顶层的绑定 (包括变量函数声明,以及 import 导入的内容) 都能在模板中直接使用。

<template>
  <div><Child></Child>{{ count }}</div>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child'
const count = ref(0)
</script>

响应式数据

定义响应数据

ref()

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

reactive()

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

computed()

接受一个 getter 函数,返回一个只读的响应式 ref 对象。

<template>
  <span v-show="hidden">{{ count }} </span><button @click="toggle">显示</button>
</template>
<script lang="ts" setup>
import { ref, reactive, computed} from 'vue'
const hidden = ref(false)
const state = reactive({
  name: '张三',
  age: 18,
  family: [
    { name: '张爸', age: 45 },
    { name: '张妈', age: 42 }
  ]
})
const count = computed(() => {
  return state.family.length
})
const toggle = () => {
  hidden.value = !hidden.value
}
</script>

监听器

当需要在数据变化时执行一些“副作用”:如更改 DOM、执行异步操作,可以使用监听器。
使用同步语句创建的侦听器当组件卸载的时候会停止监听;使用异步回调创建一个监听器器,必须手动停止,以防内存泄漏。

watch()

watch()用于监听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
参数:

  1. 监听器的数据源(ref/响应式对象/函数)
  2. 发生变化时的回调函数
  3. 配置对象
    immediate:在监听器创建时立即触发回调
    deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。
    flush:指定回调函数的刷新时机。
    • pre (默认)dom 更新前调用回调
    • post dom 更新后调用回调
    • sync 同步调用回调
      onTrack / onTrigger:用于调试的钩子。在依赖收集和回调函数触发时被调用
import { watch } from 'vue'
// 监听ref
watch(hidden, (newValue, oldValue) => {
  console.log(`${oldValue} -> ${newValue}`)
})
// 监听proxy对象,vue3将强制开启deep深度监听,和vue2一样,oldValue和newValue相同
watch(state, newValue => {
  console.log(newValue)
})
// 使用函数监听proxy数据的某个属性
watch(
  () => state.family,
  newValue => {
    console.log(newValue)
  },
  {
    deep: true // family是引用数据,需开启deep属性
  }
)
// 使用数组监听proxy数据的某些属性
watch([() => state.name, () => state.age], ([newName, newAge], [oldName, oldAge]) => {
  console.log(`${newName}:${newAge}->${oldName}:${oldAge}`)
})
// 侦听多个数据源
watch([hidden, () => state.name], ([newHidden, newName], [oldHidden, oldName]) => {
  console.log(`${newName}:${newHidden}->${oldName}:${oldHidden}`)
})

watchEffect()

watchEffect()会立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行,当组件卸载的时候会停止监听。
参数:

  1. 要运行的副作用函数
  2. 一个可选的选项
    flush: 指定回调函数的刷新时机
    onTrack / onTrigger:用于调试的钩子。在依赖收集和回调函数触发时被调用
import { watchEffect } from 'vue'
watchEffect(()=>{
  console.log("watchEffect配置的回调执行了",hidden.value)
})

停止监听

const stop=watch(hidden, (newValue, oldValue) => {
  console.log(`${oldValue} -> ${newValue}`)
})

setTimeout(()=>{
    stop()
}, 3000)

组件传值

defineProps() / defineEmits()

  • defineProps(): 子组件使用defineProps接收父组件的props
  • defineEmits(): 子级组件向父级组件传值
    子组件
<template>
  <span >{{ props.name }} </span>
  <input type="text" @change="changeName" v-model="name">
</template>

<script setup>
import { ref} from 'vue'
const props = defineProps({
  name: { type: String, required: true }
})
const emit = defineEmits(['updateName'])
const name= ref(props.name)
const changeName = () => {
  emit('updateName', name.value)
}
</script>

父组件

<template>
  <Child :name="name" @updateName="handleUpdate" />
</template>

<script setup>
import { ref} from 'vue'
import Child from './components/Child.vue'
const name=ref('张三')
const handleUpdate=(newName)=>{
  console.log(newName)
  name.value=newName
}
</script>

模板ref / defineExpose()

  • 模板ref 和选项式api一样,在模板中用ref 注册元素或子组件的引用
  • defineExpose():script setup语法糖不能直接使用ref 取到子组件的方法和变量,需使用defineExpose方法暴露组件的属性以及方法供外部使用。

子组件

<template>
  <input type="text" @change="changeName" v-model="name">
</template>
<script setup>
import { ref,defineExpose } from 'vue'
const emit = defineEmits(['updateName'])
const name= ref('张三')
const changeName = () => {
  emit('updateName', name.value)
}
// 将方法、变量暴露给父组件使用,父组件才可通过ref API拿到子组件暴露的数据
defineExpose({
  name,
  changeName
})
</script>

父组件

<template>
  <Child ref="root" />
</template>

<script setup>
import { ref,onMounted } from 'vue'
import Child from './components/Child.vue'
const root = ref(null)
onMounted(() => {
  console.log(root.value) // DOM 元素将在初始渲染后分配给 ref
})
</script>

provide() / inject()

依赖注入

  • provide()
    提供一个值,可以被后代组件注入,provide()接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。
  • inject()
    注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值

父组件

import { ref,provide  } from 'vue'
// 提供静态值
provide('size','small')
// 提供响应式的值
const loading = ref(false)
provide('loading', loading)

后端组件

import { inject } from 'vue'
const size = inject('size')
const loading = inject(loading)

插槽

  1. 在子组件的模板中使用<slot>元素定义插槽出口
<template>
 <div>
   <slot name="title"></slot>
    <slot name="content" msg="子组件的数据"></slot>
    <slot></slot>
 </div>
</template>
  1. 在父组件的模板中使用v-slot:(缩写:#)指令声明具名插槽或是期望接收 props 的作用域插槽.
<template>
  <Child>
    <template v-slot:title>标题</template>
    <template #content="{ msg }">内容:{{msg}}</template>
    <span>作者:admin</span>
  </Child>
</template>

参考:vue中slot组件的使用

useSlots() 和 useAttrs()

import { useSlots, useAttrs } from 'vue'
// 获取插槽的信息
const slots = useSlots()
// 获取过来的所有属性
const attrs = useAttrs()

常用生命周期钩子

钩子函数生命周期选项执行条件备注
onBeforeMount()beforeMount在组件被挂载之前被调用
onMounted()mounted在组件挂载完成后执行
onBeforeUpdate()beforeUpdate在组件即将因为响应式状态变更而更新其 DOM 树之前调用
onUpdated()updated在组件因为响应式状态变更而更新其 DOM 树之后调用
onBeforeUnmountbeforeDestroy在组件实例被卸载之前调用
onUnmounted()destroyed在组件实例被卸载之后调用
onErrorCaptured()errorCaptured在捕获了后代组件传递的错误时调用

顶层 await

await setup前面会自动加一个async

const data = await fetch("/api/demo")

使用路由

import { useRoute, useRouter } from 'vue-router'
const route = useRoute() // 返回当前路由地址
const router = useRouter() // 返回 router 实例
import { nextTick } from 'vue'
// DOM更新完毕之后执行回调的两种写法
nextTick(() => {
  console.log('DOM更新完毕')
})
await nextTick()
console.log('DOM更新完毕')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值