1.模板绑定
- 直接返回模板绑定(非响应式)
<template>{{data}}</template>
<script lang="ts">
export default {
name: 'App',
setup(){
return {
data:"数据元"
}
}
}
</script>
- 响应式
<template>
<div>{{state.count}}</div>
<div>{{count1}}</div>
<div>{{name}}</div>
</template>
<script lang="ts">
interface state {
count:number
}
interface Person{
name:string
}
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
const state = reactive<state>({
count:0
})
const person = reactive<Person>({
name:"小王"
})
//setup返回的 ref 在模板中访问时是被自动浅解包的
//因此不应在模板中使用.value
const count1 = ref<number>(1)
return{
state,
count1,
//将响应式的对象变为普通对象 再解构,在模板中就可以直接使用属性,不用person.name
...toRefs<Person>(person)
}
}
})
</script>
2.参数
setup(props:,context:){
}
2.1 props
- 是由父组件传递下来的响应式数据和reactive包装的类型向相同,均是proxy类型,因此不用再次对其进行响应式包装
- 不能使用 ES6 解构props,它会消除 prop 的响应性,若想结构props,可以用
toRefs
,因为上面说了props是proxy式的响应式数据,所以用toRefs
将其转换为Ref响应数据,还能让模板绑定更简单
//Test.vue
<template>
<h1>{{title}}</h1>
</template>
<script lang="ts">
import { defineComponent, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
props:{
title:String
},
setup(props,context){
console.log(props);
//最初的时候执行一次
//变化的时候再次执行
watchEffect(()=>{
console.log(props);
})
//仅变化的时候执行
watch(()=> props.title,newValue =>{
console.log(newValue);
})
}
})
</script>
//App.vue
<template>
<Test :title="title"></Test>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
import Test from './components/Test.vue'
export default defineComponent({
name: 'App',
components:{
Test
},
setup(){
const title = ref<string>("我是vue")
console.log(title);
setTimeout(() => {
title.value = "我是vue3.0"
console.log(title)
}, 2000);
return {
title
}
}
})
</script>
- 如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:
<template>
<h1>{{title}}</h1>
</template>
<script lang="ts">
import { defineComponent, toRef, toRefs, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
props:{
title:String
},
setup(props,context){
console.log(props);
const title = toRef(props,'title')
//最初的时候执行一次
//变化的时候再次执行
watchEffect(()=>{
console.log(title.value);
})
//仅变化的时候执行
watch(()=> title,newValue =>{
console.log(newValue);
})
}
})
</script>
2.2context
-
context
包含三个属性:attrs
、slots
、emit
- 由于
context
是非响应式的,因此可以在setup
中对其进行解构
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
-
attrs
和slots
是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以attrs.x
或slots.x
的方式引用property
。与props
不同,attrs
和slots
是非响应式的。如果你打算根据attrs
或slots
更改对应业务逻辑,那么应该在onUpdated
生命周期钩子中执行此操作。
- attrs与props的不同:
- props 要先声明才能取值,attrs 不用先声明
- props 声明过的属性,attrs 里不会再出现
- props 不包含事件,attrs 包含
- props 支持 string 以外的类型,attrs 只有 string 类型
<template>
<h1>{{title}}</h1>
</template>
<script lang="ts">
import { defineComponent, toRef, toRefs, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
setup(props,context){
console.log(context.attrs);
return {
...toRefs(context.attrs)
}
}
})
</script>
<template>
<h1>{{title}}</h1>
</template>
<script lang="ts">
import { defineComponent, toRef, toRefs, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
setup(props,context){
console.log(context.attrs);
return {
//失去响应性
...context.attrs
}
}
})
</script>
<template>
<h1>{{attrs.title}}</h1>
</template>
<script lang="ts">
import { defineComponent, toRef, toRefs, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
setup(props,context){
console.log(context.attrs);
return {
attrs:context.attrs
}
}
})
</script>
- emit:用于父子通信
<template>
<h1>{{count}}</h1>
<button @click="plus(3)">增加</button>
</template>
<script lang="ts">
import { defineComponent, SetupContext, toRef, toRefs, watch, watchEffect } from "@vue/runtime-core";
export default defineComponent({
name:"Test",
props:{
count:Number
},
emits:['plus'],
setup(props,context:SetupContext){
const plus:(num: number) => void = (num:number)=>{
context.emit('plus',num)
}
return {
plus
}
}
})
</script>
<template>
<Test :count="count" @plus="plus"></Test>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
import Test from './components/Test.vue'
export default defineComponent({
name: 'App',
components:{
Test
},
setup(){
const count = ref<number>(1)
const plus:(num: number) => void = (num:number):void=>{
count.value += num
}
return {
count,
plus
}
}
})
</script>
3.this
VUE2 | VUE3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
errorCaptured | onErrorCaptured |
setup
中的this
是undefined