【vue3新特性,与vue2不同】

介绍

vue3最大的改变就是组合式API,我们在setup中可以分功能,分模块写代码(类似vue2的minxis), 不像vue2,把所有数据都丢在data中, 把所有的方法都丢在methods中等等, 代码量多了, 我们要找一个功能模块的代码很难.

setup的使用以及注意事项

* 1.setup在创建组件之前执行

* 2.setup选项中没有this

* 3.setup的参数(props,context)
注意:vue2配置中(data,methods,computed…)可以访问到vue3的setup中的属性和方法,但是setup里面不能访问到vue2中的配置,如果有重名,setup优先,所以,vue3和vue2尽量不要混用。

setup参数解析:props,context
a. props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。
如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作

setup(props) {
		//这里先不要管里面的语法,后面会介绍
      const { title } = toRefs(props)
      console.log(title.value)
}

b. context 是一个普通的 JavaScript 对象(它不是响应式的,可以解构),它暴露三个组件的 property

setup(props, context) {
      // Attribute (非响应式对象)
      console.log(context.attrs)
      // 插槽 (非响应式对象)
      console.log(context.slots)
      // 触发事件 (方法)
      console.log(context.emit)
    }

常用Api

1.ref:定义一个响应式数据

ref对我们的值创建了一个引用对象,响应式(ref用来定义响应式的 字符串、 数值、 数组、Bool类型)

let msg = ref("这是setup中的msg");  setup中使用时:msg.value(注意:模板中会自动解析,不用加.value)

注意:

  • ref可以接收基本数据类型,也可以接收引用类型
  • ref处理基本数据类型的响应式时的原理(defineProperty的getter和setter),但处理复杂类型引用了下面的reactive(原理:proxy)
2.reactive: 定义一个对象类型的响应式数据

用来定义响应式的对象,使用时无需.value

let setupData = reactive({
        title: "reactive定义响应式数据的title",
        userinfo: {
          username: "张三",
          age: 20
        }
    })
3.toRefs与toRef

解构响应式对象数据

//toRef
setup() {
    const user = reactive({
      username: "张三",
      age: 10000,
    });
    return {
        //toRef(拿值的对象,拿值的对象的具体属性) 特点:一次拿一个
      username:toRef(user,'username') 
    };
  },
 
//toRefs
setup() {
    const user = reactive({
      username: "张三",
      age: 10000,
    });
    return {
        //toRefs(拿值的对象) 特点(可直接拿一整个对象,其中的属性都是refImpl对象)
      ...toRefs(user)
    };
  },
      //  模板中可以直接使用username和age
4.readonly

“深层”的只读代理

const original = reactive({ count: 0 });
const copy = readonly(original);  

copy为只读,不能修改

5.setup中computed的使用
setup(){
    let person = resctive({
        firstName:'谢',
        lastName:'小雨'
    })
    //computed的简写(只能读取,不能修改)
    let person.finName = computed(()=>{
        return person.firstName+person.lastName
    })
    //computed的完整写法(可以读取,可以修改)   eg:input框中为计算的属性,可以修改  123-456789
    let person.finName = computed(()=>{
        get(){
            return person.firstName+'-'+person.lastName
        }
        set(value){
            let name = value.split('-')
            person.firstName = name[0]
            person.lastName = name[1]
        }
    }) 
    return {
        persion
    }
}
6.setup中watch的使用
watchEffect
import {watchEffect,watch} from 'vue'
setup(){
    let lastName = ref('三')
    let firstName = ref('张')
    let person = reactive({
        name:'李四',
        age:18,
        job:{
            xinzi:'1k',
            
        }
    })
    //watch(监视的属性,监视的回调,[参数配置(例如:{immediate:true})])
    //情况一:监听一个ref数据
        watch(firstName,(newVal,oldVal)=>{

        })
    //情况二:监听多个ref数据
        watch(lastName,(newVal,oldVal)=>{

        })
        watch(lastName,(newVal,oldVal)=>{

        })
        //或者简写为(监听的值为数组)
        watch([firstName,lastName],(newVal,oldVal)=>{
            console.log(newVal,oldVal)//这时的newVal和oldVal为数组  [firstName的						NewVal,lastName的		NewVal],[firstName的oldVal,lastName的oldVal]
            //如果一个改变一个没有改变,则没有改变的NewVal = oldVal
        })
    //情况三:监听一个reactive数据,
        //注意:
        //1.此处oldVal无法正确获取(引用数据)
        //2.无论对象中属性的层次有多深,都可以监听到(就像vue2中开启了deep:true)
        watch(person,(newVal,oldVal)=>{
            console.log(newVal) 
            console.log(oldVal)//oldVal与newVal一样
        })
    //情况四:监听一个reactive数据中的某一个属性,
    //注意:
    //1.此处的监听的值若直接写成person.age,那就是监听18,不正确(监听的值必须为ref属性)
    //2.无论对象中属性的层次有多深,都可以监听到(就像vue2中开启了deep:true)
    watch(()=>person.age,(newVal,oldVal)=>{
        console.log(newVal) 
        console.log(oldVal)

    })
    //情况五:监听一个reactive数据中的某些属性,
     watch([()=>person.age,()=>person.name],(newVal,oldVal)=>{
        console.log(newVal) 
        console.log(oldVal)
    })
    
    //watchEffect(监视的回调)监视回调中用到哪个变量就监听哪个变量
    watchEffect(()=>{
        let name = lastName.value + firstName.value
    })
}
7.shallowReactive和shallowRef

shallowReactive:只处理对象最外层的响应式(浅响应式)

shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理 (基本数据类型时.与ref作用相同)

使用场景:

  • 一个对象数据,结构比较深,但变化时只是外层属性变化 ===> shallowReactive
  • 一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef
8.readonly和shallowReadonly

readonly(接收一个响应式数据)

shallowReadonly(接收一个响应式数据) (只影响最外层)

使用场景:

  • 使用别人定义号的组件时,定义的有些变量不能更改,不然别人的地方回受影响,这时,我们可以用readonly()的返回值,控制台会报警告,修改不了值.
import {ref,reactive,readonly,shallowReadonly} from 'vue'
setup(){
    let person = reactive({
        name:'张三',
        age:18,
        
    })
    person = readonly(person)  //person中的任何属性都不能更改
    person = shallowReadonly(person)  //person中的最外层属性不能更改
}
9.toRow和markRow

toRow(接收一个由reactive生成的响应式对象) 响应式对象转换为普通对象

使用场景:

  • 读取响应式对象的普通对象,对这个普通对象的所有操作,页面不会更新.

markRow(对象) 标记一个对象,使其永远不会成为响应式对象

使用场景:

  • 有些值不应被设置为响应式(如:第三方插件库等).

  • 当渲染具有不可变数据源的大列表时(如:一个非常复杂,层次很深的对象),跳过响应式转换可以提高性能

import {toRaw,markRow,reactive} from 'vue'
setup(){
    let person = reactive({
        name:'张三',
        age:18,
        
    })
    let car = {
        ...
    }
    person = toRaw(person)  //person中的任何属性都不能更改
    person = markRow(car)  //person中的最外层属性不能更改
}
10.customRef自定义ref
html场景:input框输入什么,h3隔1s后展示输入的值
<input v-model="keywords">
<h3>{{keywords}}</h3>

import {customRef,ref} from 'vue'
setup(){
  
    //自定义一个ref
    function myRef (value){
        let timer //定义一个定时器
        //customRef的参数:
        //track:通知vue去追踪数据的改变
        //tirgger:通知vue去重新解析模板
        return customRef((track,trigger)=>{
            get(){
                track() //通知vue去追踪value的改变
                return value
            }
            set(newValue){
                clearTimeOut(timer)
                timer=setTimeOut(()=>{
                    value = newValue
                	trigger() //通知vue去重新解析模板
                },1000)
            }
        })
    }
    let keywords = myRef('hello')
    return {
        keywords
    }
}
11.provide与inject
//父
setup(){
	let person = reactive({
		name:'张三',
		age:12
	})
	provide('person',person)
}
//子
setup(){
	//也可以使用,但一般不这么用
}
//孙
setup(){
	let x = inject('person')
	//所有后背都可以通过inject拿到provide定义的值
}

12.响应式数据的判断

  • isRef:判断一个值是否为ref对象
  • isReactive:判断一个对象是否为reactive对象
  • isReadonly:判断一个对象是否由readonly创建的只读代理
  • isProxy:判断一个对象是否为由reactive或readonly创建的代理

vue3的生命周期

与vue2的不同之处:

  • beforeDestory ===> beforeUnMount
  • destoryed ===> unMounted

组合api形式的生命周期使用:

import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnMount,onUnMounted} from 'vue'
setup(){
    //setup中没有beforeCreat和created的组合式api,因为setup就相当于beforeCreat和created的组合式api
    onBeforeMount(()=>{
        
    }),
    onMounted(()=>{
        
    }),
    onBeforeUpdate(()=>{
        
    }),
    onUpdated(()=>{
        
    }),
    onBeforeUnMount(()=>{
        
    }),
    onUnMounted(()=>{
        
    }),
}

vue3自定义hook函数

什么是hook: 本质是一个函数 (就是把setup里面使用的组合式api封装到其他js文件,使代码复用,类似vue2的mixin),这里就不放代码了,可以自己试试.

vue3新特性

1.teleport传送门组件

直接传送指定的父元素下

<teleport to="body">
    ...需要传送的内容
	<div>hahahahah</div>
</teleport>
//例如:to属性,指定父元素

2.emits选项

自定义事件需要定义在emits选项中

export default {
	emits:['change']
}
好处:
a.如果和原生事件重名(如:click),声明emits选项后,只会触发一次emits事件,如果不声明,会触发2次
b.更好的指示组件的工作方式
c.对象形式校验(自行看文档)

suspense和异步组件

//父组件
<template>
    <suspense>
    	//默认加载
        <template v-slot:default>
			<Child/>
        </template>
		//组件还没有加载出来时展示的内容
		<template v-slot:fallback>
            <h3>正在加载,请稍后...</h3>
        </template>
    </suspense>
    <Child/>
</template>
//异步引入组件
//配合suspense的使用
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import(./components/Child))
//子组件
async setup(){
    let sum = ref(10)
    let p = new Promise((res,rej)=>{
        setTimeOut(()=>{
            res({sum})
        },1000)
    })
    return await p
}
//或者这样写

//子组件
setup(){
    let sum = ref(10)
    return new Promise((res,rej)=>{
        setTimeOut(()=>{
            res({sum})
        },1000)
    })
}

其他不同之处

1.全局的api改为实例的方法

vue2中有很多全局的方法(如:Vue.component,Vue.filter,Vue.directive,Vue.delete,Vue.set,Vue.nextTick,Vue.extend等)
vue2中使用 new Vue() 作为app,这样的话所有的创建的根实例都会共享相同的根实例(测试时会污染其他测试用例)

vue3使用 creatApp() 返回app实例

2.x全局API3.x实例API(app)
Vue.config.xxxxapp.config.xxxx
Vue.config.productionTip移除
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.prototypeapp.config.globalProperties

vue3的摇树优化

vue2中的一些没有用到的全局方法会静态挂载到vue的构造函数上(eg:Vue.nextTick),我们从来没使用过,这称之为 ‘dead code’ ,这类代码无法使用webpack的tree-shaking排除掉(也就是说:依然会打包)

import Vue from 'vue'
//使用
Vue.nextTick(()=>{
    //
})

vue3中把他们拆分成了独立函数,这样 ‘dead code’ 这类代码就可以使用webpack的tree-shaking排除掉

import {nextTick} from 'vue'
nextTick(()=>{
    //
})

受影响的api:

  • Vue.nextTick
  • Vue.observable(replaced by Vue.reactive)
  • Vue.version
  • Vue.compile
  • Vue.set
  • Vue.delete

v-model的变化

vue2中的v-model与.sync功能有重叠,容易混,vue3做了统一

vue3移除了.sync,v-model的使用有点变化:(写法更像sync)

//父组件:
<template>
	<div>
        <clide v-model="data"></clide>  (相当于vue2版本的写法:<clide :modelVaule="data" @update:modelValue="data=$event"></clide>)
    </div>
</template>
//子组件
<div @click="changeValue">{{modelValue}}</div>
...
props:['modelValue']
...
changeValue(){
	let newVlaue = 3
	this.$emit('update:modelValue',newVlaue)
}

如果要自定义接收的值:
//父组件:
<template>
	<div>
        <clide v-model:num="data"></clide>  (相当于vue2版本的写法:<clide :num="data" @update:num="data=$event"></clide>)
    </div>
</template>
//子组件
<div @click="changeValue">{{modelValue}}</div>
...
props:['num']
...
changeValue(){
	let newVlaue = 3
	this.$emit('update:num',newVlaue)
}

渲染函数的变化

vue3中的rander函数:

//插槽的使用
<RanderTest>
    <template v-slot:title>title</template>
    <template v-slot:content>content</template>
</RanderTest>
import {h} from 'vue'
components:{
    RanderTest:rander(){
        //插槽内容的获取
        //vue2:this.$scopeSlots.title()  
        //vue3 统一slots
        this.slots.title() //获取具名插槽
        this.slots.default() //获取默认插槽
        return h('div',[
            h('div',{
                onClick(){
                    //注意里面的this环境
                }
            },'woshi div'),
            h('button',{

            })
        ])
        }
    }
}

注意

vue3中的data必须是函数

vue3移除keyCode的修饰符,移除native修饰符(因为vue3有emits配置项)

vue3移除filter过滤器

o n , on, on,once,$off被移除

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值