子组件Test.vue
<template>
<h3>here is test component</h3>
<h1>{{count}}</h1>
<button @click="emitAddEvent">add</button>
</template>
<script>
import {watchEffect,watch,toRefs} from 'vue'
export default {
name: 'Test',
props: {
count:Number
},
//自定义事件注册在setup外面
emits:['add'],
//连个参数,一个props,一个context
setup(props,context){
//3和2在定义函数是不一样的,通过回调函数,将自定义事件发射出去
const emitAddEvent=()=>{
//发射事件不再使用thies.emit,而是用context,this在3里面不用了,
//emit函数和2里面一致,先注册后使用
context.emit('add',100)
}
return {
//用到那个变量或者函数一定要return出去
emitAddEvent
}
}
}
</script>
<style scoped>
</style>
父组件app.vue
<template>
<div>
<!--这里add是自定事件,addcount是自定义事件的回调函数 -->
<Test :count="mycount" @add="addcount"></Test>
</div>
</template>
<script>
import Test from './components/Test.vue'
//从vue中解构导出所需要的函数,包括钩子都是以函数的形式解构出来使用
import {reactive,ref,toRefs} from 'vue'
export default {
name: 'App',
setup(props,context){
//使用到的变量要ref包裹一下
const mycount=ref(1000)
//发射过来的emit事件是带参的,回调函数要用个形参来接收一下
const addcount=(plusdata)=>{
//被ref包裹的数据,由于响应式的问题,是只读的(readonly)不能修改,需要拆一下把value拆出来修改
mycount.value+=plusdata
}
return {
//变脸及回调函数都要return出去
mycount,
addcount
}
},
components: {
Test
}
}
</script>
<style>
</style>
<template>
<div>
spp
</div>
</template>
<script>
import {reactive,ref,toRefs} from 'vue'
export default {
name: 'App',
setup(props,context){
const proxyObj=reactive({
a:1,
b:2,
c:[
{d:3,e:4},{f:3,g:5}
]
})
console.log(proxyObj)
return {
}
},
components: {
}
}
</script>
<style>
</style>
<template>
<div>
spp
</div>
</template>
<script>
import {reactive,ref,toRefs} from 'vue'
export default {
name: 'App',
setup(props,context){
const myref=ref(100)
const proxyObj=ref({
a:1,
b:2,
})
console.log(myref.value)
console.log(proxyObj.value.a)
const state=reactive({ myref })
//使用reactive包裹的对象会自动展开,state.myref等效于state.value.myref
console.log(state.myref)
//也可以直接修改数据
state.myref=200
console.log(state.myref)
return {
myref,
state
}
},
components: {
}
}
</script>
<style>
</style>
<template>
<div>
<h1>{{name}}</h1>
<h1>{{person.homeland.city}}</h1>
</div>
</template>
<script>
import {reactive,ref,toRefs} from 'vue'
export default {
name: 'App',
setup(props,context){
const name=ref('')
name.value='zhangsan'
setTimeout(()=>{
name.value='lisi'
console.log(name.value)
},2000)
const person=ref({
name:'wanger',
age:12,
homeland:{
province:'hebei',
city:'shijiazhuang'
}
})
setTimeout(()=>{
//非深度响应
person.value.name='mazouri'
//深度响应
person.value.homeland.city='baoding'
},3000)
console.log(person.value.name)
console.log(person.value.homeland.city)
return {
name,
person,
}
},
components: {
}
}
</script>
<style>
</style>
<template>
<div>
</div>
</template>
<script>
import {reactive,ref,toRefs,isRef,unref} from 'vue'
export default {
name: 'App',
setup(props,context){
const myobj={
name:'zhangsan',
age:22,
address:'heibei'
}
const obj1=isRef(myobj) ? myobj.name : myobj
console.log(obj1)
const obj2=ref(myobj)
const obj3=isRef(obj2) ? myobj.name : myobj
console.log(obj3)
//unref实际就等于上面的obj3
const obj4=unref(obj2)
console.log(obj4)
const obj5=unref(myobj)
console.log(obj5)
return {
myobj
}
},
components: {
}
}
</script>
<style>
</style>
1、toRef:建立reactive和ref的一种转换
可以把对象中的某个属性单独拿出来转成ref
<template>
<div>
{{myref}}
</div>
</template>
<script>
import {reactive,ref,toRef,isRef,unref} from 'vue'
export default {
name: 'App',
setup(props,context){
const state=reactive({
name:'zhangsan',
age:23
})
//指定转换的属性,这里将state的reactive包装对象的name属性传给myref
const myref=toRef(state,'name')
//修改转换后的值
myref.value='lisi'
console.log('11111',state.name)
//修改state.name和修改myref.value都会影响到对方
state.name='wanger'
console.log('22222',myref.value)
return {
myref,
}
},
components: {
}
}
</script>
<style>
</style>
2、toRefs:建立reactive包装对象和ref的一种转换
<template>
<div>
urname:{{name}}<br/>
urage:{{age}}
</div>
</template>
<script>
import {reactive,ref,toRef,toRefs,isRef,unref} from 'vue'
export default {
name: 'App',
setup(props,context){
const state=reactive({
name:'zhangsan',
age:23
})
//指定转换的属性,这里将state的reactive包装对象的name属性传给myref
//这里转成了一个普通对象
const myrefs=toRefs(state)
console.log(myrefs)
console.log({
...myrefs
})
console.log('11111',myrefs.name.value)//zhangsan
console.log('11111',myrefs.age.value)//23
//修改转换后的值
myrefs.name.value='lisi'
myrefs.age.value=33
//修改转换后的值会影响到原则,因为实际本质上还是引用的
console.log(state.name)//lisi
console.log(state.age)//33
//修改state.name和修改myref.value都会影响到对方
state.name='wanger'
state.age=44
console.log('22222',myrefs.name.value)
console.log('22222',myrefs.age.value)
return {
//直接展开转化后的myrefs,这样在template里面可以直接拿到展开后的name和age
...myrefs,
state
}
},
components: {
}
}
</script>
<style>
</style>
3、isRef判断是否为ref
参看前几例
用于数据防抖
customRef需要有一个工厂函数做参数,track(追踪),trigger(触发),分别对应getter和setter
<template>
<div>
<span>{{text}}</span>
<input type="text" v-model="text">
</div>
</template>
<script>
import {reactive,customRef} from 'vue'
function useDebounce(value,delay=200){
let time=null
return customRef((track,trigger)=>{
return {
get(){
//跟踪旧值,返回旧值前要跟踪旧值,防止其发生变化
track()
return value
},
set(newvalue){
clearTimeout(time)
time=setTimeout(()=>{
value=newvalue
//更新数值和要去触发trigger
trigger()
},delay)
}
}
})
}
export default {
name: 'App',
setup(props,context){
const text=useDebounce('',500)
return {
text
}
},
components: {
}
}
</script>
<style>
</style>
浅ref,由于使用ref包装之后,数据就具有了响应式,如果使用shallowRef包装,转化后成为一个proxy对象(普通对象)
<template>
<div>
<span>{{myobj1}}</span>
<hr/>
<span>{{myobj2}}</span>
</div>
</template>
<script>
import {ref,reactive,customRef,shallowRef} from 'vue'
export default {
name: 'App',
setup () {
const myobj1=ref({
name:'zhangsan',
age:12
})
console.log(myobj1)//RefImpl
myobj1.value={
name:'lisi',
age:33
}
console.log(myobj1.value)//Proxy
const myobj2=shallowRef({
name:'zhangsan',
age:12
})
console.log(myobj2)//RefImpl
myobj2.value={
name:'wanger',
age:55
}
console.log(myobj2)//RefImpl
return {
myobj1,
myobj2
}
}
}
</script>
<style>
</style>
手动触发响应式操作
<template>
<div>
<span>{{myobj1}}</span>
<hr/>
<span>{{myobj2}}</span>
</div>
</template>
<script>
import {ref,reactive,customRef,shallowRef,watchEffect,triggerRef} from 'vue'
export default {
name: 'App',
setup () {
const myobj1=ref({
name:'zhangsan',
age:12
})
console.log(myobj1)//RefImpl
myobj1.value={
name:'lisi',
age:33
}
console.log(myobj1.value)//Proxy
const myobj2=shallowRef({
name:'zhangsan',
age:12
})
console.log(myobj2)//RefImpl
myobj2.value={
name:'wanger',
age:55
}
console.log(myobj2)//RefImpl
let name=''
watchEffect(()=>{
name=myobj2.value.name
console.log(name)
})
myobj2.value.name='zhaoqiusun'
triggerRef(myobj2)
return {
myobj1,
myobj2
}
}
}
</script>
<style>
</style>
返回一个不可变的值
返回值也是一个ref
<template>
<div>
<span>{{superSentence}}</span>
</div>
</template>
<script>
import {ref,computed} from 'vue'
export default {
name: 'App',
setup (props,context) {
const textRef=ref('欢迎来到我的小屋')
const superSentence=computed(()=>{
return '小明'+textRef.value
})
console.log(superSentence.value)
return {
superSentence
}
}
}
</script>
<style>
</style>
实际机制其实也是一个get和set
<template>
<div>
<span>{{superSentence}}</span>
</div>
</template>
<script>
import {ref,computed} from 'vue'
export default {
name: 'App',
setup (props,context) {
const textRef=ref('欢迎来到我的小屋')
const superSentence=computed(
{
get(){
return '小明'+textRef.value
},
set(value){
console.log('我通过计算属性修改了值')
console.log(value)
}
}
)
console.log(superSentence.value)
superSentence.value='我一旦修改,就要触发set语句'
return {
superSentence
}
}
}
</script>
<style>
</style>