目录
拉开序幕的setup:是所有Composition API(组合API)“表演舞台”
一、组件中所用刀的:数据、方法等等,均要配置在setup中。
Vue3——监视属性watch,监视ref数据 (可以传递三个参数)
情况五、监视reactive所定义的一个响应式数据中的某些属性
Vue3中可以继续使用Vue2中的生命周期钩子,但有两个更名:
Vue3中也提供了Composi API形式的生命周期钩子,与Vue2中钩子对应关系如下:
Vue3——shallowReactive与shallowRef
Vue3——readonly与shallowReadonly
简介:
Vue3——使用vite构建对比图
优势:
1、传统构建
2、vite构建
3、构建vite步骤:
Vue3——Composition API
拉开序幕的setup:是所有Composition API(组合API)“表演舞台”
一、组件中所用刀的:数据、方法等等,均要配置在setup中。
二、setup函数的两种返回值:
(1)若返回一个对象,对象中的属性、方法,在模板中都可以直接使用。
(2)若返回一个函数,则可以指定以渲染内容。
三、注意:
1、尽量不要与vue2配置混用。
(1)vue2配置(data,methods,computed)等都可以访问vue3中setup中的属性,方法。
(2)但在setup中不能访问vue2的配置。
(3)如果有重名,setup优先
2、setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性和方法。
Vue3——ref函数_处理基本类型
<template> <h1>ref函数的基本处理</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <button @click="changeInfo">修改人的信息<button> </template> <script> import {ref} from 'vue' export default{ name:'App', setup(){ //数据 let name=ref("张三") let age=ref(18) //方法 function changeInfo(){ name.value="李四" age.value="25" } //返回一个对象 return { name, age, changeInfo } } } </script> <style></style>
Vue3——ref处理对象类型
<template> <h1>ref函数的基本处理</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <h3>薪资:{{salary}}</h3> <h3>职位:{{type}}</h3> <button @click="changeInfo">修改人的信息<button> </template> <script> import {ref} from 'vue' export default{ name:'App', setup(){ //数据 let name=ref("张三") let age=ref(18) let job=ref{ type:'前端实习生', salary:'4k' } //方法 function changeInfo(){ name.value="李四" age.value="25" job.value.type="前端开发工程师", job.value.salary:'10k' } //返回一个对象 return { name, age, changeInfo } } } </script> <style></style>
小结:
ref函数作用:
定义一个响应式数据。
语法:const xxx = ref(initValue)
(1)创建一个包含响应式数据的引用对象,简称ref对象。
(2)JS中操作数据:xxx.value
(3)模板中读取数据,不需要.value,直接<div>{{xxx}}</div>
备注:
(1)接收的数据可以使:基本类型,也可以是对象类型。
(2)基本类型的数据:响应式依然靠的是Object.defineProperty()的get与set完成的。
(3)对象类型的数据:内部“使用”了Vue3中的一个函数——reactive函数。
reactive函数
ref方式定义数据与reactive方式定义数据的对比
<template> <h1>ref函数的基本处理</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <h3>薪资:{{salary}}</h3> <h3>职位:{{type}}</h3> <button @click="changeInfo">修改人的信息<button> </template> <script> import {ref} from 'vue' export default{ name:'App', setup(){ //数据 let name=ref("张三") let age=ref(18) let job=reactive{ type:'前端实习生', salary:'4k' } //方法 function changeInfo(){ //ref方法 name.value="李四" age.value="25" ------------------------------------------------- //reactive方法 job.type="前端开发工程师", job.salary:'10k' } //返回一个对象 return { name, age, changeInfo } } } </script> <style></style>
reactive方式:
<template> <h1>ref函数的基本处理</h1> <h2>姓名:{{person.name}}</h2> <h2>年龄:{{person.age}}</h2> <h3>薪资:{{person.salary}}</h3> <h3>职位:{{person.type}}</h3> <button @click="changeInfo">修改人的信息<button> </template> <script> import {ref,reactive} from 'vue' export default{ name:'App', setup(){ age:18, job:{ type:'前端工程师', salary:'10k', } //方法 function changeInfo(){ person.name="李四" person.age="25" person.job.type="前端开发工程师", person.job.salary:'10k' } //返回一个对象 return { name, age, changeInfo } } } } </script> <style></style>
reactive函数
1、作用:定义一个对象类型的相应数据(基本类型不要用它,要用ref函数);
2、语法:const 代理对象 = reactive(源对象)接收一个对象(或数组),返回一个代理对象(proxy的实例对象,简称proxy对象)对象;
3、reactive定义的响应式数据是“深层次的”;
4、内部基于ES6的Proxy实现,通过代理对象的操作源对象内部数据进行操作。
Vue3——回顾Vue2的响应式原理
<template> <div> <h1>vue2响应式效果</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <button @click="addsex">添加一个sex属性</button> <button @click="deleteName">删除name属性</button> </div> </template> <script> import Vue from 'vue' //第二种方法 export default{ name:'App', data(){ return{ person:{ name:'张三', age:18, hobby:['学习','敲代码'] } } }, methods:{ addSex(){ this.$set(this.person,'性别','女') ------------------------------- vue.set(this.person,'性别','女') }, deleteName(){ this.$delete(this.person,'性别','女') ----------------------------------------- vue.delete(this.person,'性别','女') }, updateHobby(){ this.$set(this.person.hobby,1,'学习前端') //把爱好数组索引1的修改 ------------------------- this.person.hobby.splice(0,1,'看书') //修改第0个 } } } </script> <style></style>
Vue3的响应式原理
<template> <div> <h1>vue2响应式效果</h1> <h2 v-show="person.name">姓名:{{person.name}}</h2> <h2>年龄:{{person.age}}</h2> <h2 v-show="person.sex">性别:{{person.sex}}</h2> <button @click="addsex">添加一个sex属性</button> <button @click="deleteName">删除name属性</button> </div> </template> <script> import Vue from 'vue' //第二种方法 export default{ name:'App', setup(){ let person = reactive({ name:'', age:18, }), job:{ type:'前端工程师', salary:'10k', }, //方法 function changeInfo(){ person.name="李四" person.age="25" person.job.type="前端开发工程师", person.job.salary:'10k' }, function addSex(){ person.sex='男' }, function deleteName(){ delete.person.name } //返回一个对象 return { name, addSex, deleteName, changeInfo } } } </script> <style></style>
响应式原理——proxy
<head></head> <body> <script> let person = { name:'张三', age:18 } const p = new Proxy(person,{ get(target,propName){ console.log(`有人读取了p身上的属性 ${propName}`) return target[propName] }, set(target,propNmae,value){ console.log(`有人修改,增加时,p身上的属性 ${propName}`) target[propName]=value }, deleteProperty(target,propName){ console.log(`有人删除了p身上的属性 ${propName}`) return delete target[propName] } }) </script> </body>
Vue3——响应式原理_Reflect
try....catch....方式判断代码执行
Object.defineProperty()
<head></head> <body> <script> let person = { name:'张三', age:18 }, let obj={a:1,b:2} try{ Object.defineProperty(obj,'c',{ get(){ return 3 } }) Object.defineProperty(obj,'c',{ get(){ return 5 } }) } catch(error){ console.log(error) } </script> </body>
Reflect方式二:Reflect.defineProperty(),反射对象
<head></head> <body> <script> let person = { name:'张三', age:18 }, let obj={a:1,b:2} const x1 = Reflect.defineProperty(obj,'c',{ get(){ return 3 } }) const x2 = Reflect.defineProperty(obj,'c',{ get(){ return 5 } }) </script> </body>
示例:
<head></head> <body> <script> let person = { name:'张三', age:18 }, const p = new Proxy(person,{ //创建代理对象 get(target,propName){ return Reflect.get(target,propName) //返回反射对象 }, set(target,propName,value){ Reflect.set(target,propName,value) }, deleteProperty(target,propName){ return Reflect.deleteProperty(target,propName) } }) </script> </body>
Vue3——reactive对比ref
Vue3的两个注意点:
Vue3——computed计算属性
<template> 姓:<input type='text' v-model="person.firstName"> 名:<input type='text' v-model="person.lastName"> <span>全名:{{person.fullName}}</span> 全名:<input type="text" v-model="person.fullName"> </template> <script> import {reactive,computed} from 'vue' export default{ name:'', setup(){ let person = reactive({ firstName:'张', lastName:'三' }), //计算属性的简写形式(没有考虑计算属性被修改的情况) person.fullName=computed(()=>{ return person.fristName +'-'+ person.lastName }), //---------------------------------------- //计算属性的完整写法(考虑读写) person.fullName=computed({ get(){ return person.firstName+'-'+person.lastName }, set(value){ const nameArr = value.split('-') person.firstName=nameArr[0] person.lastName=nameArr[1] ] }) } } </script> <style></style>
Vue3——监视属性watch,监视ref数据 (可以传递三个参数)
情况一、监视ref所定义的一个响应式
可以获取oldValue,可以开启deep
<template> <h2>当前信息为:{{msg}}</h2> <button @click="msg+='!'">修改信息</button> </template> <script> import {ref,watch} from 'vue' export default{ name:'Demo', setup(){ let sum = ref(0) let msg = ref('你好啊') watch(sum,,(newValue,oldValue)=>{ console.log('sum或者msg的值变化了',newValue,oldValue) },{immediate:true}) } } </script> <style></style>
情况二、监视ref所定义的多个响应式
<template> <h2>当前值为:{{sum}}</h2> <h2>当前信息为:{{msg}}</h2> <button @click="sum++">点击加1</button> <button @click="msg+='!'">修改信息</button> </template> <script> import {ref,watch} from 'vue' export default{ name:'Demo', setup(){ let sum = ref(0) let msg = ref('你好啊') watch([sum,msg],(newValue,oldValue)=>{ console.log('sum或者msg的值变化了',newValue,oldValue) },{immediate:true}) } } </script> <style></style>
情况二、监视ref所定义的多个响应式数据
可以获取oldValue,可以开启deep
<template> <h2>当前和是:{{sum}}</h2> <button @click="sum++">点击+1</button> <h2>当前信息为:{{msg}}</h2> <button @click="msg+='!'">修改信息</button> </template> <script> import {ref,watch} from 'vue' export default{ name:'Demo', setup(){ let sum = ref(0) let msg = ref('你好啊') watch([sum,msg],(newValue,oldValue)=>{ console.log('sum或者msg的值变化了',newValue,oldValue) },{immediate:true}) } } </script> <style></style>
情况三、监视reactive所定义的一个响应式数据
监视属性watch时,value的问题:
1、监视的是一个简单类型时,不能加“value”属性;
2、监视的不是一个对象属性时:
处理方式一:“对象名.value” 此时相当于在对象里使用reactive处理了数据。
处理方式二:开启deep:true
注:此处无法正确获取oldValue
<template> <h2>姓名:{{person.name}}</h2> <h2>年龄{{person.sum}}</h2> <h2>薪资{{person.job.j1.salary}}</h2> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">涨薪</button> </template> <script> import {reactive,watch} from 'vue' export default{ name:'Demo', setup(){ let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) watch(person,(newValue,oldValue)=>{ /监视的是reactive直接创建的属性 console.log('person变化了',newValue,oldValue) /old属性没法获取 },{deep:true}), return { name, sum, person } } } </script> <style></style>
情况四、监视reactive所定义的一个响应式数据中的某个属性,
oldValue同样无效
强制开启了深度监视
<template> <h2>姓名:{{person.name}}</h2> <h2>年龄{{person.sum}}</h2> <h2>薪资{{person.job.j1.salary}}</h2> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">涨薪</button> </template> <script> import {reactive,watch} from 'vue' export default{ setup(){ let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) watch(()=>person.age,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue) }), return { name, sum, person } } } </script> <style></style>
情况五、监视reactive所定义的一个响应式数据中的某些属性
oldValue同样无效
强制开启了深度监视
<template> <h2>姓名:{{person.name}}</h2> <h2>年龄{{person.sum}}</h2> <h2>薪资{{person.job.j1.salary}}</h2> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">涨薪</button> </template> <script> import {reactive,watch} from 'vue' export default{ setup(){ let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue) }), return { name, sum, person } } } </script> <style></style>
特殊情况:
由于此处监视的是reactive定义的对象中的某个属性,且此属性任然是一个对象,
所以deep有效,
无法读取oldValue
<template> <h2>姓名:{{person.name}}</h2> <h2>年龄{{person.sum}}</h2> <h2>薪资{{person.job.j1.salary}}</h2> <button @click="person.age++">增长年龄</button> <button @click="person.job.j1.salary++">涨薪</button> </template> <script> import {reactive,watch} from 'vue' export default{ setup(){ let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) watch(()=>person.job,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue) },{deep:true}) 此时deep属性生效 return { name, sum, person } } } </script> <style></style>
Vue3——WatchEffect函数
Vue3——声明周期
Vue3中可以继续使用Vue2中的生命周期钩子,但有两个更名:
Vue3中也提供了Composi API形式的生命周期钩子,与Vue2中钩子对应关系如下:
Vue3中hook函数
本质:是一个函数,把setup函数使用Composition API进行了封装。
类似于Vue2中的mixin函数
优势:复用代码,让setup中的逻辑更清楚易懂。
(不使用hook函数)
<template> <h2>当前和为:{{sum}}</h2> <button @click="sum++">点击+1</button> <hr> <h2>当前点击鼠标位置:x:{{point.x}} y:{{point.y}}</h2> </template> <script> import {ref,reactive,onMounted} from 'vue' export default{ name:'Demo', setup(){ let sum = ref(0) let point = reactive({ x:0, y:0 }) function savePoint(event){ point.x=event.pageX, point.y=event.pageY onMounted(()=>{ window.addEventListener('click',savePoint} }) onBeforeUnmount(()=>{ window.removeEventListener('click',savePoint) }) return{sum,point} } } </script>
(使用hook函数)
创建hook文件夹,创建.js文件
import {reactive,onMounted,onBeforeUnmount} from 'vue' export default function(){ 数据 let point = reactive({ x:0, y:0 }) 方法 function savePoint(event){ point.x=event.pageX, point.y=event.pageY } 生命周期钩子 onMounted(()=>{ window.addEventListener('click',savePoint} }) onBeforeUnmount(()=>{ window.removeEventListener('click',savePoint) }) return point }
组件中引用:
<template> <h2>当前和为:{{sum}}</h2> <button @click="sum++">点击+1</button> <hr> <h2>当前点击鼠标位置:x:{{point.x}} y:{{point.y}}</h2> </template> <script> import {ref} from 'vue' import usePoint from '../hooks/usePoint' export default{ name:'Demo', setup(){ let sum = ref(0) let point = usePoint() return{sum,point} } } </script>
Vue3——toRef与toRefs
toRef实例:
<template> <h3>{{person}}</h3> <h3>姓名{{name}}</h3> <h3>年龄:{{age}}</h3> <h3>薪资:{{salary}}</h3> <button @click="name+='~'">点击修改姓名</button> <button @click="age++">点击增长年龄</button> <button @click="job.j1.salary++">涨薪</button> <template> <script> import {reactive,toRef} from 'vue' setup(){ let person=reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) return { name:toRef(person,'name') age:toRef(person,'age') salary:toRef(person.job.j1,'salary') } } </script>
toRefs实例:
<template> <h3>{{person}}</h3> <h3>姓名{{name}}</h3> <h3>年龄:{{age}}</h3> <h3>薪资:{{salary}}</h3> <button @click="name+='~'">点击修改姓名</button> <button @click="age++">点击增长年龄</button> <button @click="job.j1.salary++">涨薪</button> <template> <script> import {ref,reactive,toRef,torefs} from 'vue' setup(){ let person=shallowReactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) return { person, ...toRefs(person) } } </script>
toRef小结:
作用:创建一个ref对象,其value值指向另一个对象中的某个属性;
语法:const name = toRef(person,'name'),
应用:要将响应式对象中的某个属性单独提供给外部使用时。
扩展:toRefs与toRef功能一致,但可以批量创建多个ref对象,语法:toRefs(person)
Vue3——shallowReactive与shallowRef
shallowReactive实例:
<template> <h3>当前x.y的值是{{x.y}}</h3> <button @click="x={y:888}">点我y会替换</button> <button @click="x.y++">点击y并不会加</button> <template> <script> import {shallowReactive} from 'vue' export default{ name:'Demo', setup(){ let x = shallowRef({ y:0 }) console.log("******",x) return { x } } } </script>
shallowRef实例:
<template> <h3>当前x.y的值是{{x.y}}</h3> <button @click="x={y:888}">点我y会替换</button> <button @click="x.y++">点击y并不会加</button> <template> <script> import {shallowRef} from 'vue' export default{ name:'Demo', setup(){ let x = shallowRef({ y:0 }) console.log("******",x) return { x } } } </script>
Vue3——readonly与shallowReadonly
readonly只读属性
<template> <h3>{{person}}</h3> <h3>姓名{{name}}</h3> <h3>年龄:{{age}}</h3> <h3>薪资:{{salary}}</h3> <button @click="name+='~'">点击修改姓名</button> <button @click="age++">点击增长年龄</button> <button @click="job.j1.salary++">涨薪</button> <template> <script> import {ref,reactive,toRef,torefs,radyonly} from 'vue' export default{ name:'Demo', setup(){ let sum = ref() let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) person = readonly(person) return { sum, ...toRefs(person) } } } </script>
shallowReadonly,浅层次只读实例
<template> <h3>{{person}}</h3> <h3>姓名{{name}}</h3> <h3>年龄:{{age}}</h3> <h3>薪资:{{salary}}</h3> <button @click="name+='~'">点击修改姓名</button> <button @click="age++">点击增长年龄</button> <button @click="job.j1.salary++">涨薪</button> <template> <script> import {ref,reactive,toRef,toRefs,shallReadonly} from 'vue' export default{ name:'Demo', setup(){ let sum = ref() let person = reactive({ name:'张三', age:18, job:{ j1:{ salary:20 } } }) person = shallReadonly(person) return { sum, ...toRefs(person) } } } </script>
Vue3——toRaw与markRaw
Vue3——customRef(自定义ref)
作用:创建一个自定义ref,并对其依赖项跟踪和更新触发进行显式控制。
<template> <input type = "text" v-model="keyWord"> <h3>{{keyword}}</h3> </template> <script> import {ref,customRef,} from 'vue' export default{ name:'App', setup(){ function myRef(value,delay){ //定义一个自定义函数,接收keyword参数与延迟时间 let timer //定义一个全局定时器 return customRef((value,trigger)=>{ //返回一个自定义ref,并接收参数 return{ get(){ //获取,读取数据 console.log("有人读取数据了,${{value}}" track() //告诉Vue这个value需要跟踪 return value }, set(newValue){ //设置值 console.log("有人修改了数据") clearTimeout(timer) //每次设置值之前清楚定时器 timer=setTimeout(()=>{ //创建一个定时器 value=newValue //接收修改的值并重新传给value trigger() //通知vue重新解析模板 },delay) } } }) } let keyWord = myRef('hello',500) //设置延迟的时间,并传给函数中 return {keyWord} } } </script> <style></style>
Vue3——provide(提供)与inject(注入)
祖父组件:
<template> <div> <h3>我是App组件,{{name}}--{{price}}</h3> <Child/> </div> </template> <script> import {reactive,toRefs} from 'vue' import Child from './Child' export default{ name:'', components:[Child], setup(){ let car = reactive({name:'问界',price:'30w'}) provide('carValue',car) //通过provide给Son组件注入数据,数据名为carValue return {...toRefs(car)} } } </script> <style></style>
父组件:
<template> <div class="child"> <h3>我是Child组件(子)</h3> <Son/> </div> </template> <script> import Son from './Son' export default{ name:'Child', components:{Son}, } </script> <style></style>
子组件:
<template> <div> <h3>我是Son组件,{{car.name}--{{car.price}}}</h3> </div> </template> <script> import {inject} from 'vue' export default{ name:'Son', setup(){ let car = inject('carValue') //接收从祖父组件传过来的值 return {car} } } </script> <style></style>
小结:
Vue3——响应式数据判断
返回值都是true
Vue3——组合式API优势
Vue3——Fragment组件
Vue3——Teleport组件
<template> <div> <button @click="isShow=true">点击弹窗</button> <teleport to="body"> <div v-if="isShow" class="mask"> //遮罩层 <div class="dialog"> <h2>我是一个弹窗</h2> <h3>一些内容</h3> <h3>一些内容</h3> <button @click="isShow = false">关闭弹窗</button> </div> </div> </teleport> </div> </template> <script> import {ref} from 'vue', export default{ name:'Dialog', setup(){ let isShow=ref(false) return {isShow} } } </script> <style></style>
Vue3——Suspense组件
<template> <div class="app"> <h3>我是App组件</h3> <Suspense> 、、使用Suspense包裹组件,并配置好default与fallback <template v-slot:default> //固定写法,这个插槽中放入的是放入的组件 <Child/> </template> <template v-slot:fallback> //这个组件中放提示信息 <h3>正在加载中</h3> </template> </Supense> </div> </template> <script> import {defineAsyncComponent} from 'vue' 导入异步组件 const Child = defineAsyncComponent(()=>import('./components/Child')) export default{ name:'App', components:{Child} } </script> <style></style>
Child组件
<template> <div class="child"> <h3>我是child组件</h3> {{sum}} </div> </template> <script> import {ref} from 'vue' export default{ name:'Child', saync setup(){ let sum = ref(0) let p = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve({sum}) },3000) }) return await p } } </script> <style></style>
setup不能是一个async函数,因为返回值不再是return 对象,而是promise,模板看不到return对象中的属性,但是后期可以返回一个promise实例,需要异步组件()和Suspense配合。
Vue3——其他改变