Vue3 composition API(组合API)详解与代码

本篇文章基于该视频: 尚硅谷教学Vue2与Vue3

composition API优势

使用传统Options(配置)APi,新增或者修改需求,需要在data、methods、computed等中修改
使用composition(组合)API,可以更加优雅的组织我们的代码、函数,让相关功能的代码更加有序的组织起来。

常用composition API

setup函数

初始

新的配置项 值为一个函数
组件中的所有数据、方法等,均要配置在setup中

setup函数有两个返回值:
①若返回一个对象,则对象中的属性、方法,在模板中均可使用。(重点)
②若返回一个渲染函数,则可以自定义渲染内容。(了解)


vue2中可读取setup中的数据,若重名,则setup优先。(切记不可混用)
不能是一个async函数,因为async函数返回值是promise,在模板中看不到return对象中的属性(后期可以返回Promise实例,但需要Suspense和异步组件配合)

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h1>{{uname}}</h1>
    <button @click="sayUname">alert</button>
  </div>
</template>

<script>
import {h} from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let uname = 'lyz'
    function sayUname() {
      alert(`我是${uname}`)
    }

    // 返回一个对象(常用)
    return {uname,sayUname}
    // 返回一个函数
    // return () =>h('h1', 'LYZ')
  }
}
</script>

注意点

执行时机:
在beforeCreate(通过配置项)之前执行 此时this为undefined
在这里插入图片描述

参数:
props:值为对象 包含组件外部传递过来的且组件内部声明接收了的属性(父子传值)
context:上下文对象
① attrs:值为对象 包括:组件外部传递过来但未在props配置中声明的属性 相当于this.$attrs
② slots:收到插槽内容 相当于this.$slots
③ emit:分发自定义事件的函数 相当于this.$emit

// 父组件
<template>
  <Test msg="Welcome to My App" @toTest="toTestOne">
    <template v-slot:qwe>
      <span>qwe</span>
    </template>
  </Test>
</template>

<script>
import Test from './components/Test.vue'

export default {
  name: 'App',
  components: {
    Test
  },
  setup() {
    function toTestOne(el) {
      alert(`收到参数${el}`)
    }
    return {toTestOne}
  }
}
</script>

// 子组件
<template>
  <div>
    <button @click="toTest">test</button>
  </div>
</template>

<script>
export default {
  name: 'Test',
  props: {
    msg: String
  },
  emits:['toTest'],
  setup(props, context) {
    console.log(context.slots)
    function toTest() {
      console.log(context)
      context.emit('toTest', 'lyz')
    }
    return {toTest}
  }
}
</script>

<style scoped>
</style>

响应式

ref函数(基本数据类型)

Vue2中所有data都会被捕捉,加入setter、getter 带来性能开销
ref()可以选择哪些数据被捕捉 哪些无需监听

基本数据类型:get set
引用数据类型:Proxy (ref()—>reactive())

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h1>{{uname}}</h1>
    <h2>{{uage}}</h2>
    <h3>{{job.type}}</h3>
    <h3>{{job.salary}}</h3>
    <button @click="editInfo">修改</button>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let uname = ref('lyz')
    let uage = ref('22')
    let job = ref({
        type: '前端工程师',
        salary: '30k'
    })
    function editInfo() {
      console.log(job);
      uname.value = 'my'
      uage.value = 23
      job.value.type = '后端工程师',
      job.value.salary = '50k'
    }

    return {uname, uage, job,editInfo}
  }
}
</script>

reactive函数(引用数据类型)

引用类型的响应式数据
let 代理对象 = reacvtive(源对象)
内部基于Proxy实现,通过代理对象操作源对象内部数据进行操作

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h1>{{person.uname}}</h1>
    <h2>{{person.age}}</h2>
    <h3>{{person.type}}</h3>
    <button @click="editInfo">修改</button>
  </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let person = reactive({
        uname: 'lyz',
        age: 22,
        type: '前端工程师'
    })
    function editInfo() {
        person.uname = 'my'
        person.age = 23
        person.type = '后端工程师'
    }
    return {person, editInfo}
  }
}
</script>

返回一个data对象 类似于vue2

<template>
  <div>
    <h1>{{data.person.uname}}</h1>
  </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let data = reactive({
      person: {
        uname: 'lyz'
      }
    })
    return {data}
  }
}
</script>

<style scoped>
</style>

ref与reactive区别

定义:
ref用来定义基本数据类型
reactive用来定义对象、数组类型数据
▲ref也可定义对象、数组类型数据,内部会通过reactive转为代理对象

原理:
ref通过Object。defineProperty()的get和set来实现响应式(数据劫持)
reactive通过使用Proxy来实现响应式(数据劫持),应通过Reflect操作源对象内部的数据
使用:
ref定义的数据,操作数据需要.value,读取数据时模板中直接读取不需要.value
reactive定义的数据,操作数据和读取数据都不需要.value

响应式原理

Vue2.0X响应式原理

对象:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
数组:通过重写数组的一系列方法来完成拦截。(对数组的变更方法进行了包裹)
[...].splice() vue.set() this.$set() vue.delete() this.$delete()

存在问题⚠
① 新增 删除界面不会更新;
② 直接通过下标修改数组,界面不会自动更新。

        let p = new Proxy(person, {
            // 有人读取某个属性时调用
            get(target, propName) {
                console.log('get')
                return target[propName]
            },
            // 有人 修改 或 追加 某个属性时调用
            set(target, propName, value) {
                console.log('set')
                target[propName] = value
            },
            deleteProperty(target, propName) {
                console.log('delete')
                return delete target[propName]
            }
        })

Vue3.0X响应式原理

通过Proxy(代理)拦截对象中任意属性的变化:读 写 添加 删除等
通过Reflect(反射) 对被代理对象(源对象)的操作

           let p = new Proxy(person, {
            // 有人读取某个属性时调用
            get(target, propName) {
                console.log('get')
                return Reflect.get(target, propName)
            },
            // 有人 修改 或 追加 某个属性时调用
            set(target, propName, value) {
                console.log('set')
                target[propName] = value
                Reflect.set(target, propName, value)
            },
            deleteProperty(target, propName) {
                console.log('delete')
                return Reflect.deleteProperty(target, propName)
            }
        })

computed

与vue2配置功能一致
写在setup中

<template>
  <div>
    <input v-model="person.firstName"/><br>
    <input v-model="person.lastName"/><br>
    <input v-model="person.fullName"/>
  </div>
</template>

<script>
import {reactive,computed} from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let person = reactive({
      firstName: 'lyz',
      lastName: 'my'
    })

    // 简写 只读
    // person.fullName = computed(() =>{
    //   return person.firstName + '-' + person.lastName
    // })

    // 完整
    person.fullName = computed({
      get() {
         return person.firstName + '-' + person.lastName
      },
      set(value) {
        let fullName = value.split('-')
        person.firstName = fullName[0]
        person.lastName = fullName[1]
      }
    })
    return {person}
  }
}
</script>

watch

与vue2配置功能一致
写在setup中

不同情况

情况一 监视ref所定义的一个响应式数据

情况二 监视ref所定义的多个响应式数据

情况三 监视reactive所定义的一个响应式数据
▲此处无法获取正确的oldValue
强制开启了深度监听(deep无效)

情况四 监视reactive所定义的一个响应式数据的某个属性
相当于监视的基本数据类型

情况五 监视reactive所定义的一个响应式数据的某些属性

特殊情况
监视的是reactive定义的对象中的对象属性 则deep有效
此处无法获取正确的oldValue

<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
    <hr>
    <h1>{{hello}}</h1>
    <button @click="hello+='!'">hello+!</button>
    <hr>
    <h1>{{person.name}}</h1>
    <h1>{{person.age}}</h1>
    <h1>{{person.job.j1.salary}}</h1>
    <button @click="person.name+='!'">姓名+!</button>
    <button @click="person.age++">年龄+1</button>
    <button @click="person.job.j1.salary++">工资+1000</button>
  </div>
</template>

<script>
import {watch, ref, reactive} from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let sum = ref(0),
        hello = ref('hello')
    // 情况一 监视ref所定义的一个响应式数据
    // immediate是否立即监视
    // watch(sum, (newValue, oldValue) =>{
    //   console.log(newValue, oldValue)
    // }, {immediate: true})

    // 情况二 监视ref所定义的多个响应式数据
    // watch([sum, hello], (newValue, oldValue) =>{
    //   console.log(newValue, oldValue)
    // })

    let person = reactive({
      name: 'lyz',
      age: 21,
      job: {
        j1: {
          salary: 10000
        }
      }
    })
    /* 情况三 监视reactive所定义的一个响应式数据 
       ▲此处无法获取正确的oldValue
        强制开启了深度监听(deep无效)
    */
    // watch(person, (newValue, oldValue) =>{
    //   console.log('person被监听了', newValue, oldValue)
    // })

    // 情况四 监视reactive所定义的一个响应式数据的某个属性
    // 相当于监视的基本数据类型
    // watch(() =>person.age, (newValue, oldValue) =>{
    //   console.log('person的age被监听了', newValue, oldValue)
    // })

    // 情况五 监视reactive所定义的一个响应式数据的某些属性
    // watch([() =>person.age, () =>person.name], (newValue, oldValue) =>{
    //   console.log('person的age或name被监听了', newValue, oldValue)
    // })

    /* 特殊情况
       监视的是reactive定义的对象中的对象属性 则deep有效
       此处无法获取正确的oldValue
    */
    watch(() =>person.job, (newValue, oldValue) =>{
      console.log('person的job被监听了', newValue, oldValue)
    }, {deep: true})


    return {sum, hello, person}
  }
}
</script>

监听ref定义的数据(基本或引用数据类型)

基本数据类型:监听的是RefImpl对象
引用数据类型:监听的是Proxy对象 实际为reactive定义的数据

<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
    <hr>
    <h1>{{hello}}</h1>
    <button @click="hello+='!'">hello+!</button>
    <hr>
    <h1>{{person.name}}</h1>
    <h1>{{person.age}}</h1>
    <h1>{{person.job.j1.salary}}</h1>
    <button @click="person.name+='!'">姓名+!</button>
    <button @click="person.age++">年龄+1</button>
    <button @click="person.job.j1.salary++">工资+1000</button>
  </div>
</template>

<script>
import {watch, ref} from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let sum = ref(0),
        hello = ref('hello'),
        person = ref({
          name: 'lyz',
          age: 21,
          job: {
            j1: {
              salary: 10000
            }
          }
        })
    /* 
      监听的sum为RefImpl对象 
      不能监听sum.value:sum.value为值
    */ 
    watch(sum, (newValue, oldValue) =>{
      console.log('sum值变化', newValue, oldValue)
    })

    /*
      person是由ref定义的响应式数据
      person.value是Proxy对象 为reactive所定义的数据
    */
    // watch(person.value, (newValue, oldValue) =>{
    //   console.log('sum值变化', newValue, oldValue)
    // })

    // person为RefImpl对象 只能检测到地址值 浅层次
    watch(person, (newValue, oldValue) =>{
      console.log('person变化', newValue, oldValue)
    }, {deep: true})

    return {sum, hello, person}
  }
}
</script>

watchEffect函数

与watch区别

watch:既要指名监听的属性。也要指名监听回调函数
watchEffect:无需指名监听那个属性,只监听回调中用哪个属性就监视哪个属性

与computed区别

有点类似,但是
computed:注重计算出的结果,回调函数有返回值
watchEffect:更注重过程,回调函数的而函数体

eg:报销流程、ajax请求

<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
    <hr>
    <h1>{{hello}}</h1>
    <button @click="hello+='!'">hello+!</button>
    <hr>
    <h1>{{person.name}}</h1>
    <h1>{{person.age}}</h1>
    <h1>{{person.job.j1.salary}}</h1>
    <button @click="person.name+='!'">姓名+!</button>
    <button @click="person.age++">年龄+1</button>
    <button @click="person.job.j1.salary++">工资+1000</button>
  </div>
</template>

<script>
import {ref, reactive, watchEffect} from 'vue'
export default {
  name: 'Test',
  props: {
    msg: String
  },
  setup() {
    let sum = ref(0),
        hello = ref('hello'),
        person = reactive({
          name: 'lyz',
          age: 21,
          job: {
            j1: {
              salary: 10000
            }
          }
        })
    watchEffect(() =>{
      let sum_w = sum.value
      let salary_w = person.job.j1.salary
      console.log('watchEffect监听了', sum_w, salary_w)
    })

    return {sum, hello, person}
  }
}
</script>

生命周期

与vue2相比,修改了最后两个钩子函数,改为beforeUnmount、unmounted

组合式api先于配置项出现,最好用一种形式
beforeCreate/created对应 组合式api setup函数
在这里插入图片描述

配置项

<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref(0)

    return {sum}
  },
  // 通过配置项使用生命周期钩子函数
   beforeCreate() {
    console.log('-----beforeCreate-----')
  },
  created() {
    console.log('-----created-----')
  },
  beforeMount() {
    console.log('-----beforeMount-----')
  },
  mounted() {
    console.log('-----mounted-----')
  },
  beforeUpdate() {
    console.log('-----beforeUpdate-----')
  },
  updated() {
    console.log('-----updated-----')
  },
  beforeUnmount(){
    console.log('-----beforeUnmount-----')
  },
  unmounted() {
    console.log('-----unmounted-----')
  }
}
</script>

组合式api

<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
  </div>
</template>

<script>
import {ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref(0)
    //组合式api使用生命周期函数
    onBeforeMount(()=>{
      console.log('-----onBeforeMount-----')
    })
    onMounted(()=>{
      console.log('-----onMounted-----')
    })
    onBeforeUpdate(()=>{
      console.log('-----onBeforeUpdate-----')
    })
    onUpdated(()=>{
      console.log('-----onUpdated-----')
    })
    onBeforeUnmount(()=>{
      console.log('-----onBeforeUnmount-----')
    })
    onUnmounted(()=>{
      console.log('-----onUnmounted-----')
    })
    return {sum}
  }
}
</script>

hook函数

本质上是一个函数,把setup函数中使用的Composition API进行封装,类似于Vue2.X中的mixin
自定义hook函数的优势:复用代码,让setup中的逻辑清晰易懂

//src/hook/usePiont
import { reactive, onBeforeMount, onBeforeUnmount} from "vue"

export default function() {
    // '鼠标'位置数据
    let point = reactive({
        x: 0,
        y: 0
    })
    //  '鼠标'位置方法
    function savePiont(e) {
        point.x = e.pageX
        point.y = e.pageY
        console.log(e.pageX, e.pageY)
    }
    //  '鼠标'位置相关生命周期钩子函数
    onBeforeMount(() =>{
        window.addEventListener('click', savePiont)
    }) 
    onBeforeUnmount(() =>{
        window.removeEventListener('click', savePiont)
    })
    return point
}
// src/components/Test.vue
<template>
  <div>
    <h1>{{sum}}</h1>
    <button @click="sum++">sum+1</button>
    <hr>
    <h2>X:{{point.x}} Y:{{point.y}}</h2>
  </div>
</template>

<script>
import {ref} from 'vue'
import usePoint from '../hook/usePoint.js'
export default {
  name: 'Test',
  setup() {
    let sum = ref(0)
    let point = usePoint()
    return {sum, point}
  }
}
</script>

toRef函数

作用:创建一个ref对象 其value指向另一个对象中的某个属性
console.log(toRef(p, 'uname'))
在这里插入图片描述
应用:要将响应式对象中的某个属性单独提供给外部使用
扩展:toRefs于其功能一致,但可批量创建多个ref对象
console.log(toRefs(p, 'uname'))在这里插入图片描述

不常用Composition API

shallowReactive与shallowRef

shallowReactive

只处理最外层属性的响应式
使用:如果有一个对象数据,结构比较深,但变化的是外层属性

<template>
  <div>
    <h1>{{point.x}}</h1>
    <h1>{{point.z.val}}</h1>
    <button @click="point.x+=1">+1</button> <!--可改变-->
    <button @click="point.z.val+=1">+1</button> <!--可改变-->
    <hr>
    <h1>{{point_s.x}}</h1>
    <h1>{{point_s.z.val}}</h1>
    <button @click="point_s.x+=1">+1</button> <!--可改变-->
    <button @click="point_s.z.val+=1">+1</button> <!--不可改变-->
  </div>
</template>

<script>
import {reactive, ref, shallowReactive, shallowRef} from 'vue'
export default {
  name: 'Test',
  setup() {
    let point = reactive({
      x: 100,
      y: 99,
      z: {
        val: 100
      }
    })
    let point_s = shallowReactive({
      x: 10,
      y: 9,
      z: {
        val: 100
      }
    })
    return {point, point_s}
  }
}
</script>

shallowRef

只处理基本数据类型的响应式(ref会将引用类型的转换为reactive响应式),不进行对象的响应式
使用:如果有一个对象,后续功能不会修改对象中的属性,二是新的对象来替换
在这里插入图片描述

<template>
  <div>
    <h1>{{sum.x}}</h1> <!--可改变-->
    <h1>{{sum.z.val}}</h1> <!--可改变-->
    <button @click="sum.x+=1">+1</button>
    <button @click="sum.z.val+=1">+1</button>
    <hr>
    <h1>{{sum_s.z.val}}</h1> <!--不可改变-->
    <button @click="sum_s.z.val+=1">+1</button><!--不可改变-->
    <button @click="sum_s={z: {val: 1000}}">改变</button> <!--改变对象-->
  </div>
</template>

<script>
import {reactive, ref, shallowReactive, shallowRef} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref({
      x: 10,
      y: 9,
      z: {
        val: 100
      }
    })
    let sum_s = shallowRef({
      x: 10,
      y: 9,
      z: {
        val: 100
      }
    })
    console.log('ref', sum)
    console.log('shallowRef', sum_s)
    return {sum, sum_s}
  }
}
</script>

readonly与shallowReadonly函数

让一个响应式数据变为只读
readonly(深只读)
shallowReadonly(浅只读):对象中嵌套的对象可修改

页面中数据不更新情况:
①不是响应式
②数据不让修改

①从跟上解决不让修改数据
②▲所用的属性不是本组件定义的 别人定义的响应式数据交给你不让改

<template>
  <div>
    <h2>{{name}}</h2>
    <h2>{{age}}</h2>
    <h2>{{salary.val}}K</h2>
    <button @click="name+='!'">姓名+!</button> <!--只读-->
    <button @click="age++">年龄+1</button> <!--只读-->
    <button @click="salary.val++">工资+1</button> <!--只读-->
    <hr>
    <h2>{{rname}}</h2>
    <h2>{{rage}}</h2>
    <h2>{{rsalary.val}}K</h2>
    <button @click="rname+='!'">姓名+!</button> <!--只读-->
    <button @click="rage++">年龄+1</button> <!--只读-->
    <button @click="rsalary.val++;console.log(rsalary.val)">工资+1</button> <!--可修改-->
  </div>
</template>

<script>
import {reactive, readonly, ref, toRefs, shallowReadonly} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref(99)
    let person = reactive({
      name: 'lyz',
      age: 22,
      salary: {
        val: 10
      }
    })
    person = readonly(person)

    let person_r =reactive({
      rname: 'my',
      rage: 23,
      rsalary: {
        val: 30
      }
    })
    person_r = shallowReadonly(person_r)
    return {sum, ...toRefs(person), ...toRefs(person_r)}
  }
}
</script>

toRaw与markRaw

toRaw

作用:将一个由reactive生成的响应式对象转为普通对象
使用场景:用于读取响应式对象对应的普通对象,对这个普通对象所有的操作不会引起页面更新
在这里插入图片描述

<template>
  <div>
    <h2>{{name}}</h2>
    <h2>{{age}}</h2>
    <h2>{{salary.val}}K</h2>
    <button @click="name+='!'">姓名+!</button>
    <button @click="age++">年龄+1</button>
    <button @click="salary.val++">工资+1</button>
    <button @click="changePerson">原始数据</button>
  </div>
</template>

<script>
import {reactive, ref, toRefs, toRaw} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref(99)
    let person = reactive({
      name: 'lyz',
      age: 22,
      salary: {
        val: 10
      }
    })

    function changePerson() {
      let p = toRaw(person)
      console.log(p)
    }

    return {sum, ...toRefs(person), changePerson}
  }
}
</script>

markRaw

作用:标记一个对象,使其永远不会成为响应式对象
使用场景:
① 有些值不应该被设为响应式 (复杂的第三方库)
② 当渲染具有不可改变数据源的大列表时,跳转响应式可提高性能

<template>
  <div>
    <h2>{{name}}</h2>
    <h2>{{age}}</h2>
    <h2>{{salary.val}}K</h2>
    <h2 v-if="person.car">{{person.car}}</h2>
    <button @click="addCar">添加car</button>
    <button @click="person.car.name+='!'">修改car名称</button> <!--不可修改-->
    <button @click="person.car.salary++">修改car价格</button> <!--不可修改-->
  </div>
</template>

<script>
import {reactive, ref, toRefs, toRaw, markRaw} from 'vue'
export default {
  name: 'Test',
  setup() {
    let sum = ref(99)
    let person = reactive({
      name: 'lyz',
      age: 22,
      salary: {
        val: 10
      }
    })
    function addCar() {
      let car = {
        name: 'bc',
        salary: 40
      }
      person.car = markRaw(car)
    }

    return {sum, person, ...toRefs(person), addCar}
  }
}
</script>

customRef函数

创建一个自定义ref,并对其依赖项跟踪和更新触发进行显示控制

<template>
  <div>
    <input v-model="val"/>
    <h3>{{val}}</h3>
  </div>
</template>

<script>
import {customRef} from 'vue'
export default {
  name: 'Test',
  setup() {
    function myRef(value, delay) {
      let timer
      return customRef((track, trigger) =>{
        return {
          get() {
            console.log(`有人读取数据${value}`)
            track()
            return value
          },
          set(newValue) {
            console.log(`有人读取数据${value}${newValue}`)
            // 定时器要清除
            clearTimeout(timer)
            timer = setTimeout(() =>{
              value = newValue
              trigger()
            }, delay)
          }
        }
      })
    }

   let val = myRef('lyz', 1000)
   return {val}
  }
}
</script>

provide与inject

作用:祖与后代间的通信
套路:父组件使用provide传递数据,后代选用inject接收数据

// Son.vue
<template>
  <h1 class="son">子组件 {{car}}</h1>
</template>

<script>
import {inject} from 'vue'
export default {
  name: 'Son',
  setup() {
    let car = inject('car')
   return {car}
  }
}
</script>

<style scoped>
  .son {
    height: 200px;
    background: rgb(241, 198, 198);
  }
</style>

// Father.vue
<template>
  <div class="fa">
    <h1>父组件</h1>
    <Son/>
  </div>
</template>

<script>
import Son from './Son.vue'
export default {
  name: 'Father',
  components: {
    Son
  },
  setup() {

   return {}
  }
}
</script>

<style scoped>
  .fa {
    height: 400px;
    background: rgb(236, 95, 95);
  }
</style>

// App.vue
<template>
  <div class="ap">
    <h1>App组件 {{car}}</h1>
    <Test></Test>
  </div>
</template>

<script>
import Test from './components/Father.vue'
import {provide} from 'vue'

export default {
  name: 'App',
  components: {
    Test
  },
  setup() {
    let car = {
      name: '奔驰',
      price: '40w'
    }
    provide('car', car)
    return {car}
  }

}
</script>

<style scoped>
  .ap {
    height: 600px;
    background: rgb(240, 31, 31);
  }
</style>

响应式数据的判断

isRef:检查一个值是否为Ref对象
isReactive:检查一个对象是否为reactive创建的响应式代理
isReadonly:检查一个对象是否为readonly创建的只读代理
isProxy:检查一个对象是否为readonly或readonly创建的代理

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值