1.计算属性(computed)computed的返回值是一个响应式ref对象import{ref,computed}from'vue'constcount=ref(10)//写法1:默认getter函数的返回值是一个read-onlyrefobjectconstdoubleCount=computed(()=>count.value*2)//因为返回值是ref对象的值,所以需要获取它的值console.log(doubleCount.value)//20//注意:这里控制台会报警告,因为我们只设置了getter函数doubleCount.value=20//warn:readonly(只读)属性不能被修改//写法二:withgetterandsetterfunctionsconstdoubleCount=computed({get:()=>count.value*2,set:(val)=>count.value=val-2})console.log(doubleCount.value)//20//不会报Warning,因为我们手动设置setter函数doubleCount.value=10//修改doubleCount的值触发set函数//所以count的值为10-2=8console.log(count.value)//82.Responsivelistening(watch)①.监控基本数据类型:import{ref,watch,reactive}from'vue'setup(){//写法一:监控一个普通值constdata=reactive({count:100})//No.一个参数写入作为函数watch(()=>data.count,(newVal,oldVal)=>{console.log(newVal,'newVal')console.log(oldVal,'oldVal')})//方法2:听refobjectconstcount=ref(100)//第一个参数写成函数watch(()=>count,(newVal,oldVal)=>{console.log(newVal,'newVal')console.log(oldVal,'oldVal')})//方法三:同时监控多个值constnum=ref(200)//第一个参数写成数组形式,代表要监控的值watch([count,num],(newVals,oldVals)=>{//这里是一个数组值对应:[count,num]console.log(newVals,'newVals')console.log(oldVals,'oldVals')})count.value=300//newVals:[300,200]oldVals:[100,200]num.value=400//newVals:[300,400]oldVals:[300,200]}②.监控引用数据类型:import{watch,reactive}from'vue'setup(){constlist=reactive([1,2,3,4,5])//这里需要复制引用数据类型watch(()=>[...list],(newVal,oldVal)=>{console.log(newVal,'newVal')console.log(oldVal,'oldVal')})list.push(6)//newVal:[1,2,3,4,5,6]oldVal:[1,2,3,4,5]}不出意外,vue3的watch也支持deep和immediate属性,只是用法变了constuserInfo=reactive({username:'kyrieirving',email:'123@qq.com',like:{isBasketball:true}})//传入一个对象作为第三启用deep/immediatewatch(()=>userInfo,(newVal,oldVal)=>{console.log(newVal.like.isBasketall)console.log(oldVal.like.isBasketall)},{deep:true})的参数//修改状态的deep属性的值userInfo.like.isBasketball=false//打印日志:false,false看到日志输出了两个false,是不是觉得哪里不对?注意:如果想在修改后的状态下获取前一个状态的值,需要深拷贝原因:watch的返回值是:当前状态(newVal)和前一个状态的引用(oldVal)//正确写法(引用数据类型的深拷贝)(这里使用Vue官方推荐的lodash深拷贝方式,当然也可以这样写(手动狗头)import_from'lodash'watch(()=>_.cloneDeep(userInfo),(newVal,oldVal)=>{console.log(newVal.like.isBasketall)console.log(oldVal.like.isBasketall)})//这里修改state的deep属性的值like.isBasketball=false//Printlog:false,true3.组合API(核心知识点)假设我们要开发一个todoList,那么在vue2的optionsAPI中,代码大致如下所示:,数据(){return{value:'',}},computed:{finallyValue(){}},满足hods:{addTodo(data){}},mounted(){this.init()}}很明显,我们可以看到我们写的代码分为(data,computed,methods,mounted...),当它是组件小的时候还好,但是当我们开发一个大组件的时候,我们会发现我们的组件变得很难维护了。将编译器“跳”上跳下寻找相关代码块进行读写显然不是很好的开发体验。如果有什么东西可以解决本次开发中代码过于碎片化,逻辑不易复用的问题,是否可以提高我们的开发效率呢?而这也是vue3推出组合API的原因。在Vue3的正确打开方式中(上图),我们已经使用了组合API,定义了响应式对象(ref,reactive)...补充一些关于生命周期和props的知识...生命周期(vue3不会再需要了:beforeCreate,created,原因见下)//vue3中,为了性能,很多API(方法)都支持TreeShaking//所以需要显式从vue导入,生命周期也不例外import{onBeforeMount,(对应tobeforeMount)onMounted,(对应mounted)onBeforeUpdate,(对应beforeUpdate)onUpdated,(对应updated)onBeforeUnmount,(对应beforeUnmount)onUnmounted,(对应unmounted)onErrorCaptured,(对应errorCaptured)基本不用onRenderTracked,(对应renderTracked)基本不用onRenderTriggered(对应renderTriggered)基本不用}from'vue'//第一个参数props,第二个参数是context(包括slots,attrs,emit)setup(props,context){//用法和vue类似,区别在于它接受一个回调函数,在hook时执行onMounted(()=>{console.log('mounted')})被组件调用,//其他hook类似,这里就不一一列举了...}tips:vue3的setup是围绕beforeCreate和createdlifehooks运行的,所以不需要显式定义这两个钩子函数。很容易理解,之前写在这两个钩子里的代码现在应该写在setup函数里。props(responsivereference)import{toRefs}from'vue'//像vue2一样接收类型验证和默认值设置props:{username:{type:String,default:''},email:{type:String,default:''}}//第一个参数是props,第二个参数是context(包括slots,attrs,emit)//所以可以使用解构。注意:有attrs和slots状态对象//所以你应该使用attrs.x或slots.xx,它们是无响应的。setup(props,{slots,attrs,emit}){//注意:解构会失去响应性const{username,email}=propsconsole.log(username,email)//需要调用toRefs()解决问题响应性损失const{username,email}=toRefs(props)}4.Provide/Injectprovide(name,value)name(Stringtype)inject(name,defaultvalue(optional))inject的名字和provide的名字要对应Parent。Vue父组件 App数量:{{count}} App用户名:{{userInfo.username}} 注入计数:{{count}} 注入用户名:{{userInfo.username}} Inject的邮箱:{{userInfo.email}}App
Child
