vue3.0之组合API有哪些(详解)

vue3.0之组合API有哪些

  • 一、setup函数
  • 二、生命周期
  • 三、reactive函数
  • 四、toRef函数
  • 五、toRefs函数
  • 六、ref函数
  • 七、知识运用案例
  • 八、computed函数
  • 九、watch函数
  • 十、ref属性
  • 十一、父子通讯
    • 1.父传子
    • 2.子传父
  • 十二、依赖注入
  • 十三、补充 v-model语法糖(简写)
  • 十四、补充 mixins语法

一、setup函数

  • setup 是一个新的组件选项,作为组件中使用组合API的起点
  • 从组件生命周期来看,它的执行在组件实例创建之前vue2.x的beforeCreate执行
  • 这就意味着在setup函数中 this 还不是组件实例,this 此时是 undefined
  • 在模版中需要使用的数据和函数,需要在 setup 返回

演示代码

<template><div class="container"><h1 @click="say()">{{msg}}</h1></div>
</template>
<script>
export default {setup () {console.log('setup执行了')console.log(this) //undefined// 定义数据和函数const msg = 'hi vue3'const say = () => {console.log(msg)}return { msg , say}  //必须以对象形式返回},beforeCreate() {console.log('beforeCreate执行了')console.log(this)}
}
</script>

二、生命周期

vue2.0vue3.0
beforeCreatesetup 创建实例前
created
beforeMountonBeforeMount 挂载DOM前
mountedonMounted 挂载DOM后
beforeUpdateonBeforeUpdate 更新组件前
updatedonUpdated 更新组件后
beforeDestroyonBeforeUnmount 卸载销毁前
destroyedonUnmounted 卸载销毁后
  • 注意
    • 1.页面中钩子函数需要先从vue引入
    • 2.需要写在setup函数内部
    • 3.可以多次使用同一个钩子,执行顺序和书写顺序相同

实例代码

<template><div class="container">container</div>
</template>
<script>
import { onBeforeMount, onMounted } from 'vue'
export default {setup () {onBeforeMount(()=>{console.log('DOM渲染前',document.querySelector('.container'))})onMounted(()=>{console.log('DOM渲染后1',document.querySelector('.container'))})onMounted(()=>{console.log('DOM渲染后2',document.querySelector('.container'))})},
}
</script>

三、reactive函数

  • reactive是一个函数,它可以定义一个复杂数据类型,成为响应式数据。
  • 通常是用来定义响应式对象数据

实例代码

<template><div><div>名字{{ obj.name }}</div><div>年龄{{ obj.age }}</div><button @click="updateName()">更改名字</button></div>
</template><script>
import { reactive } from 'vue'
export default {name: 'App',setup() {//定义对象响应式数据const obj = reactive({age: 18,name: '李四'})//修改名字const updateName = () => {obj.name = '张三'console.log('更改了', obj.name)}return { obj, updateName }}
}
</script>

四、toRef函数

  • toRef是函数,转换响应式对象中某个属性为单独响应式数据,并且值是关联的
  • 使用场景:有一个响应式对象数据,但是模版中只需要使用其中一项数据

示例代码

<template><div class="container">{{name}} <button @click="updateName">修改数据</button></div>
</template>
<script>
import { reactive, toRef } from 'vue'
export default {name: 'App',setup () {// 1. 响应式数据对象const obj = reactive({name: 'ls',age: 10})console.log(obj)// 2. 模板中只需要使用name数据// 注意:从响应式数据对象中解构出的属性数据,不再是响应式数据// let { name } = obj 不能直接解构,出来的是一个普通数据const name = toRef(obj, 'name')// console.log(name)const updateName = () => {console.log('updateName')// toRef转换响应式数据包装成对象,value存放值的位置name.value = 'zs'}return {name, updateName}}
}
</script>

五、toRefs函数

  • toRefs是函数,转换响应式对象中所有属性为单独响应式数据,对象成为普通对象,并且值是关联的
  • 剥离响应式对象(解构|展开),想使用响应式对象中的多个或者所有属性做为响应式数据
<template><div><div>名字{{ name }}</div><button @click="updateName()">更改名字</button></div>
</template><script>
import { reactive, toRef, toRefs } from 'vue'
export default {name: 'App',setup() {//1.定义响应式数据对象const obj = reactive({age: 18,name: '李四'})//obj1 具有响应式const obj1 = toRefs(obj)console.log('打印obj1', obj1)const updateName = () => {//更改方式1// obj1.name.value = "张三"//更改方式2 (直接更改响应式数据)obj.name = "张三"}return { ...obj1, updateName }}
}
</script>

六、ref函数

  • ref函数,常用于简单数据类型定义为响应式数据
  • 在修改值,获取值的时候,需要.value
  • 在模板中使用ref申明的响应式数据,可以省略.value
  • 注意
    • 当你明确知道需要的是一个响应式数据 对象 那么就使用 reactive 即可
    • 其他情况使用ref

示例代码

<template><div><div>名字{{ name }}</div><button @click="updateName()">更改名字</button></div>
</template><script>
import { ref } from 'vue';
export default {name: 'App',setup() {const name = ref('李四')const updateName = () => {name.value = '张三'}return { name, updateName }}
}
</script>

七、知识运用案例

在这里插入图片描述

<template><div class="container"><div>坐标</div><div>x: {{x}}</div><div>y: {{y}}</div><hr><div>{{count}} <button @click="add">累加1</button></div></div>
</template>
<script>
import { onMounted, onUnmounted, reactive , ref, toRefs} from 'vue'
const useMouse = () => {// 1. 记录鼠标坐标// 1.1 申明一个响应式数据,他是一个对象,包含x yconst mouse = reactive({x: 0,y: 0})// 1.3 修改响应式数据const move = (e) => {mouse.x = e.pageXmouse.y = e.pageY}// 1.2 等dom渲染完毕。去监听事件onMounted(()=>{document.addEventListener('mousemove', move)})// 1.4 组件消耗,删除事件onUnmounted(()=>{document.removeEventListener('mousemove', move)})return mouse
}
export default {name: 'App',setup () {const mouse = useMouse()// 2. 数字累加const count = ref(0) const add = () => {count.value ++}return { ...toRefs(mouse), count, add }}
}
</script>

八、computed函数

  • computed函数,是用来定义计算属性的,计算属性不能修改。
  • 总结
    • 给computed传入函数,返回值就是计算属性的值
    • 给computed传入对象,get获取计算属性的值,set监听计算属性改变。
<template><div><div>今年{{ age }}</div><div>后年{{ newAge }}</div><input v-model="newAge"></div>
</template><script>
import { computed, ref } from 'vue'
export default {name: 'App',setup() {//计算属性使用场景 需要依赖响应式数据得到一个新的数据const age = ref(18)// const newAge = computed(() => {//   return age.value + 2// })//计算属性高级用法const newAge = computed({//get方法 取值get() {return age.value + 2},//set方法 赋值set(val) {age.value = val - 2console.log('打印value', val)}})return { age, newAge }}
}
</script>

九、watch函数

  • 1.监听ref定义的响应式数据
  • 2.监听多个响应式数据
  • 3.监听reactive定义的响应式数据
  • 4.监听reactive定义的响应式数据,某一个属性
  • 5.深度监听和默认执行
<template><div><div>count的数量{{ count }}</div><button @click="watchCount">监听ref</button><hr><div>名字:{{ obj.name }}</div><div>年龄:{{ obj.age }}</div><button @click="watchMore">监听多个响应式</button><hr><button @click="watchDeep">深度监听</button></div>
</template><script>
import { reactive, ref, watch } from 'vue';
export default {name: 'App',setup() {//1.监听ref定义的响应式数据const count = ref(18)const watchCount = () => {count.value++}//第一个参数是监听的目标 //第二个参数为改变后触发的函数//第三个参数为配置项watch(count, (newval, oldval) => {console.log('ref变化了', newval, oldval)})//2.监听多个响应式数据const obj = reactive({name: '张三',age: '18',brand: {id: 1,name: '宝马'}})const watchMore = () => {obj.name = '李四'}watch(obj, (newVal, oldVal) => {console.log('多个响应式改变了', newVal, oldVal)})//3.监听多个响应式数据的变化watch([obj, count], (newVal, oldVal) => {console.log('监听多个响应式数据的变化', newVal, oldVal)})//4.监听reactive定义的某一个属性 例如obj.namewatch(obj.name, (newVal, oldVal) => {console.log('监听reactive定义的某一个属性', newVal, oldVal)})//5.深度监听 和默认执行//()=>obj.brand return返回watch(() => obj.brand, (newVal, oldVal) => {console.log('深度监听并且默认执行', newVal, oldVal)}, {deep: true, //深度监听immediate: true //默认执行})const watchDeep = () => {obj.brand.id = 2}return { count, obj, watchCount, watchMore, watchDeep }}
}
</script>

十、ref属性

  • 单个元素:先申明ref响应式数据,返回给模版使用,通过ref绑定数据
  • 遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模版使用,通过ref绑定这个函数
    • 有一个边界问题:组件更新的时候(增加li标签)会重复的设置dom元素给数组
// ref获取v-for遍历的DOM元素,需要在组件更新的时候重置接受dom元素的数组。onBeforeUpdate(()=>{list = []})

实例代码

<template><div><!-- vue2.0获取div元素 --><!-- 1. 通过ref属性绑定该元素 --><!-- 2. 通过this.$refs.box获取元素 --><!-- <div ref="box">vue2.0获取div元素</div> --><!-- vue2.0 获取v-for遍历的多个元素 --><!-- 1. 通过ref属性绑定被遍历元素 --><!-- 2. 通过this.$refs.li 获取所有遍历元素  --><!-- <ul><li v-for="i in 4" :key="i" ref="li">{{i}}</li></ul> --><!-- vue3.0获取div元素 --><!-- 单个元素 --><div ref="onebox">单个元素</div><hr><!-- 获取v-for遍历的DOM或者组件 --><ul><li v-for="i in 4" :key="i" :ref="setDom">{{ i }}</li></ul></div>
</template><script>
import { ref } from 'vue';
export default {name: 'App',setup() {//获取单个dom//1.先定义一个空的响应式数据ref定义的 并返回//2.想获取那个dom元素,在该元素使用ref绑定即可const onebox = ref(null)console.log('onebox', onebox);// 获取多个 v-for遍历//1.定义一个空数组 接收所有的li标签const domList = []//2.定义一个函数,往数组中插入domconst setDom = (li) => {console.log('setDom', li)domList.push(li)console.log('domList', domList)}return { onebox, setDom }}
}
</script>

十一、父子通讯

1.父传子

父组件

<template><div class="container"><h1>父组件</h1><p>{{money}}</p><hr><Son :money="money" /></div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {name: 'App',components: {Son},// 父组件的数据传递给子组件setup () {const money = ref(100)return { money }}
}
</script>

子组件

<template><div><h1>子组件</h1><p>money{{ money }}</p></div>
</template><script>
import { onMounted } from 'vue';export default {//子组件接收父组件传过来的值props: {money: {type: Number,default: 0}},setup(props) {//获取父组件的数据 moneyconsole.log('props传参', props.money)//获取失败onMounted(() => {// console.log('子组件money', this.money);})}
}
</script>

2.子传父

父组件

<template><div><h1>父组件</h1><p>money{{ money }}</p><hr><Son :money="money" @changeBtn="changeBtn"></Son></div>
</template><script>
import { ref } from 'vue';
import Son from './components/son.vue';
export default {components: {Son},name: 'App',setup() {//1.父组件数据 传递给子组件const money = ref(100)//定义子组件调用父组件的方法const changeBtn = (newMoney) => {console.log('子组件调用父组件的方法', newMoney)money.value = newMoney}return { money, changeBtn }}
}
</script>

子组件

<template><div><h1>子组件</h1><p>money{{ money }}</p><button @click="changeBtn()">花费50</button></div>
</template><script>
import { onMounted } from 'vue';export default {//子组件接收父组件传过来的值props: {money: {type: Number,default: 0}},//props父组件数据 //context 发现(包含emit方法) 触发自定义事件的函数//可解构 {emit}setup(props, context) {//获取父组件的数据 moneyconsole.log('props传参', props.money)//定义函数const changeBtn = () => {console.log('花费50元', context)//通知父组件context.emit('changeBtn', 50)}return { changeBtn }}
}
</script>

补充

  • 在vue2.x的时候 .sync 除去v-model实现双向数据绑定的另一种方式
<!-- <Son :money='money' @update:money="fn"  /> -->
<Son :money.sync='money'  />
  • 在vue3.0的时候,使用 v-model:money="money" 即可
//子组件 改值方法内//简写
context.emit('update:money', 50)//父组件
<!-- 简写前 --><!-- <Son :money="money" @update:money="changeBtn"></Son> --><!-- 简写后 --><Son v-model:money="money"></Son>

十二、依赖注入

使用场景

  • 有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。
  • 父组件
<template><div class="container"><h1>父组件 {{money}} <button @click="money=1000">发钱</button></h1><hr><Son /></div>
</template>
<script>
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {name: 'App',components: {Son},setup () {const money = ref(100)const changeMoney = (saleMoney) => {console.log('changeMoney',saleMoney)money.value = money.value - saleMoney}// 将数据提供给后代组件 provideprovide('money', money)// 将函数提供给后代组件 provideprovide('changeMoney', changeMoney)return { money }}
}
</script>
  • 子组件
<template><div><h2>子组件</h2><p>money{{ money }}</p><Sun></Sun></div>
</template><script>
import Sun from './sun.vue';
import { inject } from 'vue'
export default {components: {Sun},setup() {//接收祖先传递的数据 injectconst money = inject('money')return { money }}
}
</script>
  • 孙组件
<template><div class="container"><h3>孙组件 {{money}} <button @click="fn">消费20</button></h3></div>
</template>
<script>
import { inject } from 'vue'
export default {name: 'GrandSon',setup () {const money = inject('money')// 孙组件,消费50,通知父组件App.vue组件,进行修改// 不能自己修改数据,遵循单选数据流原则,大白话:数据谁定义谁修改const changeMoney = inject('changeMoney')const fn = () => {changeMoney(20)}return {money, fn}}
}
</script>

总结

  • provide函数提供数据和函数给后代组件使用
  • inject函数给当前组件注入provide提供的数据和函数

十三、补充 v-model语法糖(简写)

  • 在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />
  • 在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

父组件

<template><div class="container"><!-- 如果你想获取原生事件事件对象 --><!-- 如果绑定事函数 fn fn(e){ // e 就是事件对象 } --><!-- 如果绑定的是js表达式  此时提供一个默认的变量 $event --><h1 @click="$event.target.style.color='red'">父组件 {{count}}</h1><hr><!-- 如果你想获取自定义事件  --><!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } --><!-- 如果绑定的是js表达式  此时 $event代表触发自定义事件的传参 --><!-- <Son :modelValue="count" @update:modelValue="count=$event" /> --><Son v-model="count" /></div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {name: 'App',components: {Son},setup () {const count = ref(10)return { count }}
}
</script>

子组件

<template><div class="container"><h2>子组件 {{modelValue}} <button @click="fn">改变数据</button></h2></div>
</template>
<script>
export default {name: 'Son',props: {modelValue: {type: Number,default: 0}},setup (props, {emit}) {const fn = () => {// 改变数据emit('update:modelValue', 100)}return { fn }}
}
</script>
  • 总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue
  • 补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx 子传父 @update:xxx 在vue3.0 使用 v-model:xxx 代替

十四、补充 mixins语法

  • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
  • 理解全局混入:所有组件混入了这些逻辑代码
// 全局混入 全局mixin
// vue2.0 写法  Vue.mixin({})
app.mixin({methods: {say () {console.log(this.$el,'在mounted中调用say函数')}},mounted () {this.say()}
})
<template><div class="container1"><h1> 作者:周杰伦  <a href="javascript:;">关注</a> </h1><hr><Son /></div>
</template>
<script>
import Son from './Son.vue'
export default {name: 'App',components: {Son}
}
</script>
<template><div class="container2"><h2> 作者:周杰伦  <button>关注</button> </h2></div>
</template>
<script>
export default {name: 'Son'
}
</script>
<style scoped lang="less"></style>
  • 理解局部混入:通过mixins选项进行混入
// 配置对象
export const followMixin =  {data () {return {loading: false}},methods: {followFn () {this.loading = true// 模拟请求setTimeout(()=>{// 省略请求代码this.loading = false},2000)}}
}
<template><div class="container1"><h1> 作者:周杰伦  <a href="javascript:;" @click="followFn">{{loading?'请求中...':'关注'}}</a> </h1><hr><Son /></div>
</template>
<script>
import Son from './Son.vue'
import {followMixin} from './mixins'
export default {name: 'App',components: {Son},mixins: [followMixin]
}
</script>
<template><div class="container2"><h2> 作者:周杰伦  <button @click="followFn">{{loading?'loading...':'关注'}}</button> </h2></div>
</template>
<script>
import {followMixin} from './mixins'
export default {name: 'Son',mixins: [followMixin]
}
</script>
<style scoped lang="less"></style>
  • 总结: 在vue2.0中一些可复用的逻辑可以使用mixins来封装,当是需要考虑逻辑代码冲突问题。vue3.0的组合API很好的解决了这个问题,就不在推荐使用mixins了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26309.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【grasshopper】【犀流堂】【算法】Anemone雨水径流模拟-笔记

文章目录 Anemone雨水路径模拟available options可用选项grasshopper面切线几何原理 案例1&#xff1a;surface地形1. 拾取地形曲面surface2. 曲面上根据divide surface划分点points3.将曲面上的划分点用surface closest point投影到曲面上4.align plane旋转平面x轴与世界Z夹角…

OCPM和CPM有什么区别?

CPM和OCPM这两种收费模式的对比 Cpm&#xff1a;表示千次展示费用&#xff0c;是数据指标&#xff0c;也是一种出价方式。代表展现一千次的消费&#xff0c;也就是你展现1000次要给媒体多少钱 例如某企业广告曝光量是50万&#xff0c;总广告价格为10000元&#xff0c;那么千人…

mongodb练习---增删改查

环境&#xff1a; 1. 创建一个数据库 名字grade 2. 数据库中创建一个集合名字 class 3. 集合中插入若干数据 文档格式如下 &#xff5b;name:zhang,age&#xff1b;10,sex:m,hobby:[a,b,c]&#xff5d; hobby: draw sing dance basketball football pingpong compu…

计算机网络-应用层

目录 一、应用层概述 二、客户-服务器方式(C/S方式)和对等方式(P2P方式) &#xff08;一&#xff09;客户/服务器 (Client/Server&#xff0c;C/S) 方式 &#xff08;二&#xff09;对等(Peer-to-Peer&#xff0c;P2P) 方式 &#xff08;三&#xff09;总结 三、动态主机…

云原生TDengine-v3.0部署手册

云原生TDengine-v3.0部署手册 一、管理namespace1.1 创建namespace1.2 namespaces列表 二、配置3份yaml文件2.1 tdengine3-storage-class.yaml2.2 taosd-service.yaml2.3 taosd-tdengine.yaml 三、服务部署3.1 部署StorageClass3.2 部署Service3.3 部署StatefulSet3.4 查看启动…

记一次JVM调优过程

文档修订记录 版本 日期 撰写人 审核人 批准人 变更摘要 & 修订位置 JVM相关理论 JVM内存 可分配内存&#xff1a; JVM可以调度使用的总的内存数&#xff0c;这个数量受操作系统进程寻址范围、系统虚…

dede去掉列表推荐文档的粗体字效果的修改方法

这样看起来多么的不美观了&#xff0c;现在我们本帖教程就是去掉列表这个粗体字效果。 DedeCMSv5.6具体操纵方法如下&#xff1a; 找到 /include/arc.listview.class.php 打开找到743 - 746 行下列代码&#xff1a; if(ereg(c,$row[flag])) {$row[title] "<b>"…

用Maven的exec插件执行Java程序

Maven的exec插件介绍 利用maven的exec插件可以执行系统和Java程序。 官网资源 exec插件官网&#xff1a;https://www.mojohaus.org/exec-maven-plugin/java-mojo.html Goals exec:exec表示在一个单独的进程内执行系统和Java程序。 exec:java表示在当前的Java虚拟机内执行J…

CVE-2023-1454注入分析复现

简介 JeecgBoot的代码生成器是一种可以帮助开发者快速构建企业级应用的工具&#xff0c;它可以通过一键生成前后端代码&#xff0c;无需写任何代码&#xff0c;让开发者更多关注业务逻辑。 影响版本 Jeecg-Boot<3.5.1 环境搭建 idea 后端源码&#xff1a; https://git…

使用Mybatis-plus-join做多表查询

使用Mybatis-plus-join做多表查询 我们做多表查询都是要自己写sql的&#xff0c;还是比较麻烦的&#xff0c;下面介绍一种不用自己写sql的方式来完成多表查询。 这个第三方工具是一个大佬封装的一个jar包&#xff0c;即mybatis-plus-join架包&#xff0c;这个架包可以支持MyB…

AWS MSK集群认证和加密传输的属性与配置

通常&#xff0c;身份认证和加密传输是两项不相关的安全配置&#xff0c;在Kafka/MSK上&#xff0c;身份认证和加密传输是有一些耦合关系的&#xff0c;重点是&#xff1a;对于MSK来说&#xff0c;当启用IAM, SASL/SCRAM以及TLS三种认证方式时&#xff0c;TLS加密传输是必须的&…

深入分析Spring的IoC容器:从底层源码探索

前言&#xff1a; 博主在最近的几次面试中&#xff0c;大中小厂都问到了Spring的ioc容器相关问题&#xff0c;这块知识确实是面试中的重点内容&#xff0c;因此结合所看的书籍&#xff0c;在这篇文章中总结下。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读&#xff0…