基础入门:vue.js 组合式 API:setup() 基本使用
1、在setup中使用watch
- watch():侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
- 详细信息:
watch()
默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。第一个参数是侦听器的源。watch(侦听的响应式引用,回调函数),这个来源可以是以下几种:- 一个函数,返回一个值
- 一个 ref
- 一个响应式对象
- ...或是由以上类型的值组成的数组
-
第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
第三个可选的参数是一个对象,支持以下这些选项:
immediate
:在侦听器创建时立即触发回调。第一次调用时旧值是undefined
。deep
:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。flush
:调整回调函数的刷新时机。参考回调的刷新时机及 watchEffect()。onTrack / onTrigger
:调试侦听器的依赖。参考调试侦听器。
- watchEffect():立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
-
第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。
-
第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。
默认情况下,侦听器将在组件渲染之前执行。设置
flush: 'post'
将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置flush: 'sync'
来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。 -
返回值是一个用来停止该副作用的函数。
-
- watch()和watchEffect()的区别:
-
watchEffect()不需要指定监听的属性,自动收集依赖,只要在回调中引用响应式的属性,只要这些属性发生改变回调就会执行;watch()只能监听指定属性,做出回调函数的执行,从vue3开始可以监听多个。
-
watch()可以获得新值和旧值,watchEffect()不可以拿到。
-
watchEffect()在组件初始化的时候就会执行一次,用来收集依赖,watch()不需要,一开始就指定。
-
源代码:
<script>
import Hello from './components/Hello.vue';
import { ref,reactive, toRefs, watch, watchEffect,} from 'vue';//ref定义响应式变量,reactive 可以定义引用数据类型
export default{
data(){
return{
message:'hello word!'
}
},
setup(){
//counter逻辑代码
const counter=ref(0)
function changCoun(){
counter.value++
}
//watch(侦听的响应式引用,回调函数)
watch(counter,(newVal,oldVal)=>{
console.log("newVal----",newVal);
console.log("oldVal----",oldVal);
})
//use逻辑代码
const use=reactive({
name:'xueysr',
age:18
})
function changeName(){
use.name='x-ysr'
}
// watch(use,(newVal,oldVal)=>{
// console.log("newVal---",newVal);
// console.log("oldVal---",oldVal)
// })
//watchEffect(回调函数),不需要指定监听的属性,自动收集依赖
watchEffect(()=>{
console.log(use.name)
})
/*
watch()和watchEffect()的区别
1、watchEffect()不需要指定监听的属性,自动收集依赖,只要在回调中引用响应式的属性,只要这些属性发生改变回调就会执行
watch()只能监听指定属性,做出回调函数的执行,从vue3开始可以监听多个。
2、watch()可以获得新值和旧值,watchEffect()不可以拿到。
3、watchEffect()在组件初始化的时候就会执行一次,用来收集依赖,watch()不需要,一开始就指定。
*/
return{
counter,
use,
changCoun,
changeName
}
},
//选项式API
watch:{
message:function(newVal,oldVal){
}
},
components:{
Hello
}
}
</script>
<template>
<h2>{{counter}}</h2>
<h2>{{use.name}}</h2>
<button @click="changCoun">改变counter</button>
<button @click="changeName">改变名字</button>
<Hello></Hello>
</template>
<style>
</style>
2、生命周期钩子函数在setup中使用
-
onMounted():注册一个回调函数,在组件挂载完成后执行。
-
onUpdated():注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。
-
onUnmounted():注册一个回调函数,在组件实例被卸载之后调用。
-
onBeforeMount():注册一个钩子,在组件被挂载之前被调用。
-
onBeforeUpdate():注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。
-
onBeforeUnmount():注册一个钩子,在组件实例被卸载之前调用。
-
onErrorCaptured():注册一个钩子,在捕获了后代组件传递的错误时调用。
-
onRenderTracked()注册一个调试钩子,当组件渲染过程中追踪到响应式依赖时调用。这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。
-
onRenderTriggered():注册一个调试钩子,当响应式依赖的变更触发了组件渲染时调用。这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。
-
onActivated():注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用。这个钩子在服务器端渲染期间不会被调用。
-
onDeactivated():注册一个回调函数,若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用。这个钩子在服务器端渲染期间不会被调用。
-
onServerPrefetch():注册一个异步函数,在组件实例在服务器上被渲染之前调用。
源代码:
<script>
import Hello from './components/Hello.vue';
import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated} from 'vue';
export default{
data(){
return{
message:'hello word!'
}
},
setup(){
//生命周期钩子函数,函数中有一个参数和一个回调函数
onBeforeMount(()=>{
console.log('onBeforeMount')
});
onMounted(()=>{
console.log('onMounted')
});
onBeforeUpdate(()=>{
console.log('onBeforeUpdate')
});
onUpdated(()=>{
console.log(' onUpdated')
})
}
}
</script>
<template>
</template>
<style>
</style>
3、在setup中使用computed
-
computed ():接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
源代码:
<script>
import Hello from './components/Hello.vue';
import { ref,reactive, toRefs, watch, watchEffect, computed} from 'vue';//ref定义响应式变量,reactive 可以定义引用数据类型
export default{
data(){
return{
message:'hello word!'
}
},
setup(){
//msg逻辑代码
const msg=ref('hello word!')
const reverseMsg=computed(()=>{//返回一个带有value属性的对象
return msg.value.split('').reverse().join('')
})
console.log(reverseMsg.value)
return{
msg,
use
}
},
//选项式API
// computed:{
// reverseMsg:function(){
// return this.message.split('').reverse().join('')
// }
// }
}
</script>
<template>
<h2>{{msg}}</h2>
</template>
<style>
</style>
4、在setup中使用props
-
setup 函数的第一个参数是组件的 props。和标准的组件一致,一个 setup 函数的 props 是响应式的,并且会在传入新的 props 时同步更新。
-
如果你确实需要解构
props
对象,或者需要将某个 prop 传到一个外部函数中并保持响应性,那么你可以使用 toRefs() 和 toRef() 这两个工具函数。
源代码:
<!-- App.vue -->
<script>
import Hello from './components/Hello.vue';
export default{
data() {
return {
message: "hello word!"
};
},
components: { Hello }
}
</script>
<template>
<Hello :message="message"></Hello>
</template>
<style>
</style>
<!-- Hello.vue -->
<script>
export default{
data(){
return{
counter:0
}
},
props:{
message:{
type:String,
default:'你好'
}
},
setup(props){
console.log(props.message)
},
// mounted(){
// console.log(this.message)
// }
}
</script>
<template>
<h2>{{message}}</h2>
</template>
<style>
</style>
5、setup中的context参数
- 传入
setup
函数的第二个参数是一个 Setup 上下文对象。上下文对象暴露了其他一些在setup
中可能会用到的值: -
export default { setup(props, context) { // 透传 Attributes(非响应式的对象,等价于 $attrs) console.log(context.attrs) // 插槽(非响应式的对象,等价于 $slots) console.log(context.slots) // 触发事件(函数,等价于 $emit) console.log(context.emit) // 暴露公共属性(函数) console.log(context.expose) } }
attrs
和slots
都是有状态的对象,它们总是会随着组件自身的更新而更新。这意味着你应当避免解构它们,并始终通过attrs.x
或slots.x
的形式使用其中的属性。此外还需注意,和props
不同,attrs
和slots
的属性都不是响应式的。
源代码:
<!-- App.vue -->
<script>
import Hello from './components/Hello.vue';
export default{
data() {
return {
message: "hello word!"
};
},
methods:{
injectContext(value){
console.log(value)
}
},
mounted(){
console.log(this.$refs.content)
this.$refs.content.sendeParent()
},
components: { Hello }
}
</script>
<template>
<!-- <Hello id="content" @injectContext="injectContext"></Hello> -->
<Hello id="content" ref="content" @injectContext="injectContext"></Hello>
<Hello id="content"></Hello>
<button @click="message='你好!'">更改</button>
</template>
<style>
</style>
<!-- Hello.vue -->
<script>
import {onUpdated,toRefs,ref,h} from 'vue'
export default{
data(){
return{
counter:0
}
},
props:{
message:{
type:String,
default:'你好'
}
},
setup(props,context){
const counter=ref(20)
function sendeParent(){
context.emit('injectContext',counter)
}
console.log(context)
context.expose({
sendeParent,
counter
})
return()=>h('div',counter.value)
//props
// console.log(props.message)
// const {message}=toRefs(props)
// console.log(message.value)
// onUpdated(()=>{
// console.log(message.value)
// })
},
// mounted(){
// console.log(this.message)
// }
}
</script>
<template>
<h1>我是子组件内容</h1>
<h2>{{message}}</h2>
<button @click="sendeParent">发送数据</button>
</template>
<style>
</style>
6、setup中provide和inject
-
provide():提供一个值,可以被后代组件注入。
-
function provide<T>(key: InjectionKey<T> | string, value: T): void
-
provide()
接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。 -
当使用 TypeScript 时,key 可以是一个被类型断言为
InjectionKey
的 symbol。InjectionKey
是一个 Vue 提供的工具类型,继承自Symbol
,可以用来同步provide()
和inject()
之间值的类型。 -
inject():注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。
-
第一个参数是注入的 key。Vue 会遍历父组件链,通过匹配 key 来确定所提供的值。如果父组件链上多个组件对同一个 key 提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过 key 匹配到值,
inject()
将返回undefined
,除非提供了一个默认值。 -
第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将
false
作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。 -
与注册生命周期钩子的 API 类似,
inject()
必须在组件的setup()
阶段同步调用。 -
当使用 TypeScript 时,key 可以是一个类型为
InjectionKey
的 symbol。InjectionKey
是一个 Vue 提供的工具类型,继承自Symbol
,可以用来同步provide()
和inject()
之间值的类型。
源代码:
<!-- App.vue -->
<script>
import Hello from './components/Hello.vue';
import {provide} from 'vue'
import { ref } from '@vue/reactivity';
export default{
data() {
return {
};
},
setup(){
const name=ref('xueysr')
provide('name',name)
function changeName(){
name.value='x-ysr'
}
return{
changeName
}
},
components: { Hello }
}
</script>
<template>
<Hello></Hello>
<button @click="changeName">改变name</button>
</template>
<style>
</style>
<!-- Hello.vue -->
<script>
import {inject} from 'vue'
export default{
data(){
return{
counter:0
}
},
setup(){
const name=inject('name')
return{
name
}
}
}
</script>
<template>
<h1>我是hello组件</h1>
<h2>{{name}}</h2>
</template>
<style>
</style>
部分内容转载自:组合式 API:setup() | Vue.js