为啥要升级到Vue3
- Vue2(选项式API/OptionsAPI)逻辑的组织和复用困难;
- 相同的数据逻辑散落在不同的选项中,逻辑分散而混乱,本身就难以维护
- 而且复用困难(唯一跨组件复用逻辑的方式就是mixin,而mixin的冲突和难追踪问题是很严重)
- Vue3的最主要更新就是组合式API(CompositionAPI),将各种选项都定义为可移植和复用的hook;
- 最终达到效果:生命周期可以复用,计算属性和监听器可复用,最终通过将自带【响应式数据】+【数据自变化逻辑】的业务模块封装为【自定义hook】,在不同组件间随意复用
- 最终散落的逻辑被收拢到一个【自定义hook】中,且【自定义hook】是可以跨组件复用的;
- 另外Vue3将底层的响应式数据监听模式由Object.defineProperties修改为了【代理Proxy+反射模式Reflect】,事实上通过浏览器的JS引擎的底层寻址功能轻易监听数据变化,实现了【更小、更快、更轻】;
组合式API
setup选项
- 入参props:父组件传入的props
- 入参context:能够结构得到以下内容:
{ attrs, slots, emit, expose }
生命周期变化
Vue2组件的8大生命周期
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
},
// beforeDestroy 改名
beforeUnmount() {
console.log('beforeUnmount')
},
// destroyed 改名
unmounted() {
console.log('unmounted')
}
Vue3组件的生命周期
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
export default {
...
// 等于 beforeCreate 和 created
setup() {
console.log("setup");
onBeforeMount(
() => {
console.log("onBeforeMount");
}
);
onMounted(() => {
console.log("onMounted");
});
onBeforeUpdate(() => {
console.log("onBeforeUpdate");
});
onUpdated(() => {
console.log("onUpdated");
});
onBeforeUnmount(() => {
console.log("onBeforeUnmount");
});
onUnmounted(() => {
console.log("onUnmounted");
});
},
}
响应式数据
ref
reactive toRef toRefs
获取DOM元素
<template>
<p ref="elemRef">我是一行文字</p>
</template>
import { ref, onMounted } from 'vue'
setup() {
// 创建一个响应式值(存储元素地址)
const elemRef = ref(null)
// 其它操作...
/* 向模板返回响应式数据 */
return {
elemRef
}
}
elemRef.value.innerText = "我是修改后的文本"
完整例子
<template>
<p ref="elemRef">我是一行文字</p>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
name: 'RefTemplate',
setup() {
// 创建一个响应式值(存储元素地址)
const elemRef = ref(null)
// 挂载成功后获取DOM元素
onMounted(() => {
console.log( elemRef.value)
elemRef.value.innerText = "我是修改后的文本"
})
/* 向模板返回响应式数据 */
return {
elemRef
}
}
}
</script>
computed
watch与watchEffect
监听单个数据
const numberRef = ref(100);
setTimeout(() => {
numberRef.value = 200;
}, 2000);
watch(
numberRef,
(newNumber, oldNumber) => {
console.log("ref watch", newNumber, oldNumber);
},
{
immediate: true, // 初始化之前就监听,可选
}
);
监听多个数据(自动收集依赖)
const numberRef = ref(100);
const state = reactive({
name: "张全蛋",
age: 20,
wife: {
money: 123,
friends: ["陈顶天", "陈顶地"],
},
});
setTimeout(() => {
state.age = 25;
}, 1500);
setTimeout(() => {
numberRef.value += 1;
}, 3000);
setInterval(() => (state.wife.money += 1), 1000);
watchEffect(() => {
console.log(numberRef.value);
console.log(state.age);
});
watchEffect(() => {
console.log("watch [state.wife.money]", state.wife.money);
});
深度监听
setTimeout(() => { // state.wife.money += 100 state.wife.friends.push("希哥"); }, 2000);
watch(
// 第一个参数,确定要监听哪个属性
() => state.wife,
// 第二个参数,回调函数
(newWife, oldWife) => {
console.log('watch wife deep', newWife, oldWife)
},
// 第三个参数,配置项
{
immediate: true, // 初始化之前就监听,可选
deep: true // 深度监听
}
)