汇总→:
Vue2对比Vue3
- 响应式原理api的改变 Vue2响应式原理采用的是defineProperty,(defineProperty的缺点!!!)而vue3选用的是proxy。
这两者前者是修改对象属性的权限标签,后者是代理整个对象。性能上proxy会更加优秀。
- diff算法,渲染算法的改变 Vue3优化diff算法。不再像vue2那样比对所有dom,而采用了block tree的做法。
此外重新渲染的算法里也做了改进,利用了闭包来进行缓存。这使得vue3的速度比vue2快了6倍。
vue3更好的Tree-shaking,也使得性能大幅提升。
- 建立数据 data 这里就是Vue2与Vue3 最大的区别 — Vue2使用`选项类型API(Options API)`对比Vue3`
合成型API(Composition API)` 旧的选项型API在代码里分割了不同的属性(properties):data,computed属性,
methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便
和整洁。理论上更易于维护变量和方法。
Vue3的一些新特性--
说起Vue3,不得不提起一些老生常谈,可以脱口而出的V3的特点。
1. Vue3支持向下兼容,可兼容Vue2语法,同时青出于蓝而胜于蓝。
2. 性能的提升,大幅提升。据相关不可靠数据统计,打包大小减少41%,初次渲染快55%,热更新快133%,内存使用减少54%。
3. Composition Api的加持,让你的代码可维护性进一步提升。它是一系列Api的集合。
4. 优化很好的Tree-shaking、充分体现了权衡的艺术。
5. 更好的Typescript支持。
书写方式的变更:
Vue3生命周期
将 Vue2 的生命周期钩子代码更新到 Vue3
这个从Vue2 到Vue3的生命周期映射是直接从Vue 3 Composition API文档中获得的:
介绍:Composition Api之setUp(props,context)
props:组件外部传递过来,且组件内部声明接收了的属性。 context:上下文对象
1、attrs: 相当于this.$attrs
2、emit: 相当于this.$emits
3、solts: 相当于this.$slot
<template>
<div>
<h2>Vue3新语法之setUp()</h2>
<div>{{Car}}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "App",
setup(props,context) {
const Car = ref('Mercedes-Benz');
return {
Car
};
},
});
</script>
vue2中声明的变量需要放在data中声明使用。而vue3中通过ref声明变量,并且在setup函数中返回出去才可以在页面上使用。
export default defineComponent({
name: "App",
setup() {
const Car = ref('Mercedes-Benz');
//在setUp里定义方法
const changCar = () => {
Car.value = 'Porsche'
}
return {
Car,
changCar
};
},
});
通过ref声明的变量在赋值的时候需要通过变量.value去进行赋值和读取操作。并且事件方法不在需要声明在methods中了。 而是直接写在setup函数中就可以了。
<template>
<div>
<h2>vue3新语法reactive</h2>
<div>{{ data.car }}</div>
<button @click="data.changeCar">改变我的车</button>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
export default defineComponent({
name: "App",
setup() {
const data = reactive({
car: "Mercedes-Benz",
changeCar: () => {
data.car = "BMW";
},
});
return {
data
};
},
});
</script>
setUp语法糖
直接在script标签中添加setup属性就可以直接使用setup语法糖了。
使用setup语法糖后,不用写setup函数;组件只需要引入不需要注册;属性和方法也不需要再返回,可以直接在template模板中使用。
1.它只是简化了以往的组合API(compositionApi)的必须返回(return)的写法,并且有更好的运行时性能。
2.在setup函数中所有 ES 模块导出都被认为是暴露给上下文的值,并包含在 setup() 返回对象中。相对于之前的写法,使用后,语法也变得更简单。
<template>
<my-component @click="func" :numb="numb"></my-component>
</template>
<script lang="ts" setup> //直接在script标签中使用setUp语法糖
import {ref} from 'vue';
import myComponent from '@/component/myComponent.vue';
//此时注册的变量或方法可以直接在template中使用而不需要导出
const numb = ref(0);
let func = ()=>{
numb.value++;
}
</script>
介绍-- ref和reactive
reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型 ref 和 reactive 本质我们可以简单地理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value
使用ref定义基本数据类型,ref也可以定义数组和对象。
注:ref定义基本数据类型,形成响应式依赖于Object.defineProperty( )
reactive: 用proxy 定义响应式
注:使用reactive定义响应式数据时,若数据不是对象类型直接就返回了,就不会进行后续的数据响应式处理了
介绍-- watch:
watch改进可以监听多个属性:
setup() {
const car = ref('BNMW')
const list= reactive({
name: '张三',
nickName: '三儿',
soulmate: {
name: '李四',
nickName: '四儿'
}
})
//1. watch监听单个属性*
watch(car,(newVal,oldVal)=>{
console.log(newVal,oldVal)
})
//2.---监听对象里面的某一个属性---
watch(()=>list.name,(newValue,oldValue)=>{
console.log('watch innier', newValue)
})
//3. 注意这里是箭头函数,加了deep为true,对象里的子属性孙属性都会监听到
watch(()=>list,(newValue,oldValue)=>{
console.log('watch innier', newValue)
},
{deep: true
//添加immediate,会让监听立即执行
immediate:true
},
)
//4.监听多个属性,以数组的形式,返回数组***
watch([car,list],([newCar,newList],[oldCar,oldList])=>{
console.log(.....)
})
}
watchEffect 与 watch的immediate类似 :传入的一个函数,当依赖项变化的时候,重新执行该函数。
watchEffect(() => {
//'pre' 在组件更新更新前运行,默认为'pre'
//'post'在组件更新更新后运行
//'sync'强制效果始终同步触发。然而,这是低效的,应该很少需要。
flush:'post'
console.log(`${sum.person.age} 的值变化了!`)
}, {
onTrack(e) { //追踪其依赖的时候触发,只能在开发者模式下使用
console.log(e.target)
},
onTrigger(e) { //依赖项被改变的时候触发,只能在开发者模式下使用
console.log(e.target)
}
})
## watchPostEffect():使用 `flush: 'post'` 选项时的别名。
## watchSyncEffect(): 使用 `flush: 'sync'` 选项时的别名。
简介computed
<template>
<div>
<div>姓:<input type="text" v-model="per.surname"></div>
<div>名:<input type="text" v-model="per.name"></div>
<div>姓名:<input type="text" v-model="per.fullName"></div>
</div>
</template>
<script>
import { computed, reactive } from 'vue'
export default {
setup(){
let per=reactive({
surname:'王',
name:'小陈'
})
per.fullName=computed(()=>{
return per.surname+'~'+per.name
})
return{
per
}
}
}
2.setup语法糖中新增的api
defineProps:子组件接收父组件中传来的props
defineEmits:子组件调用父组件中的方法
defineExpose:子组件暴露属性,可以在父组件中拿到
defineProps:案例
1.接收值什么也不定义
<script setup>
import { defineProps, withDefaults } from "vue";
const definepr = defineProps(["width", "height"]);
console.log(definepr);
</script>
2.接收值定义类型和默认值
<script setup>
import { defineProps, withDefaults } from "vue";
const propsObj = defineProps({
width: {
type: Number,
default: "200",
},
height: {
type: Number,
default: "100",
},
name:{
type:Array,
default:()=>[]
}
});
console.log(propsObj.width) //200;
</script>
3.接收值 ts定义类型和默认值 ---withDefaults
type Props = {
id: string
placeholder?: string
label?: string
labelWidth: string
modelValue: string
// 小数点位数
fix: number
// 最大输入位数
maxlength: number
disabled?: boolean
inputAlign?: 'left' | 'center' | 'right'
}
const props = withDefaults(defineProps<Props>(), {
placeholder: '请输入金额',
label: '金额',
fix: 2,
maxlength: 14,
inputAlign: 'left',
modelValue: '',
disabled: false,
})
defineExpose:案例
原因:使用 <script setup> 语法糖的组件是默认关闭的,也即通过模板 ref 或者 \$parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。
方法:为了在 <script setup> 语法糖组件中明确要暴露出去的属性,,使用 defineExpose 编译器宏将需要暴露出去的变量与方法放入暴露出去就可以
!!!!!
简单说:父组件要调用子组件的方法或变量。需要子组件defineExpose暴露出实例或者方法。否则,会报错变量/方法不存在
const emit = defineEmits<{
(e: 'confirm', value: unknown, index: number, columns: Array<any>): void
(e: 'cancel', value: unknown, index: number, columns: Array<any>): void
}>()
//使用
emit('confirm', 参数paramsObj)
emit('cancel', 参数)
介绍 toRef/toRefs:
ref和toRef区别:
ref->复制,修改响应式数据不会影响以前的数据
toRef->引用,修改响应式数据会影响以前的数据
ref->数据发生改变,界面就会自动更新
toRef->数据发生改变,界面也不会自动更新
使用场景:如果想让响应式数据和以前的数据关联起来,并且更新响应数据之后不想更界面UI,就用toRef
toRef --- 代理一个对象
toRefs --- 代理多个对象
案例:
const obj = reactive({
name:'张三';
sex:'男'
})
let {name,sex} = toRefs(obj) //toRefs用解构的方式,把响应式对象的属性新建为多个新的ref
name = '牛二'
sex = '女'
console.log(obj) // {name:'牛二',sex:'女'} 说明原始对象也被改变,仍然具有响应式
介绍:shallowReactive 与 shallowRef:
shallowReactive 与 shallowRef
shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
什么时候使用?
如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。
谨慎使用!!!!!
浅层数据结构应该只用于组件中的根级状态。请避免将其嵌套在深层次的响应式对象中,因为
它创建的树具有不一致的响应行为,这可能很难理解和调试。
作用:性能优化!!!
介绍:readonly:
接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 用来做响应性追踪
console.log(copy.count)
})
// 更改源属性会触发其依赖的侦听器
original.count++
// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning!
使用useAttrs和useSlots
在 `<script setup>` 使用 `slots` 和 `attrs` 的情况应该是相对来说较为罕见的
,因为可以在模板中直接通过 `$slots` 和 `$attrs` 来访问它们。在你的确需要使用它们的罕见
场景中,可以分别用 `useSlots` 和 `useAttrs` 两个辅助函数:
// 旧
<script setup>
import { useContext } from 'vue'
const { slots, attrs } = useContext()
</script>
// 新
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>
概括:
useAttrs是获取defineProps父级没有传过来的其他属性 --- defineProps剩余的属性
若defineProps未声明任何属性,则useAttrs可获取所有属性
useSlots:拿到从父组件插槽传过来的值
详情可参考vue.js官方文档: cn.vuejs.org/guide/intro…
........