携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
她说,Vue2/3、React、NodeJs 都精通的男生真的很帅 于是我连夜把它们都过了一遍...
先举个计算器的小demo,对比一下组合式 API和选项式 API的写法差异
- Vue2的 Options API
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<div>{{count}} 的平方是: {{square}}</div>
<button @click="add">+</button>
<button @click="subtract">-</button>
</div>
<script>
const App = {
data() {
return {
count: 0
}
},
methods: {
add() {
this.count++
},
subtract() {
this.count--
}
},
computed: {
square() {
return Math.pow(this.count, 2)
}
}
}
Vue.createApp(App).mount('#app')
</script>
- Vue3的Composition API
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<div>{{state.count}} 的平方是: {{square}}</div>
<button @click="add">+</button>
<button @click="subtract">-</button>
</div>
<script>
const { reactive, computed } = Vue
const App = {
setup() {
const state = reactive({
count: 1
})
const add = () => state.count++
const subtract = () => state.count--
const square = computed(() => Math.pow(state.count, 2))
return { state, add, subtract, square }
}
}
Vue.createApp(App).mount('#app')
</script>
-
我们可以直观地看出,当业务逻辑不复杂时,选项式 API 数据和方法分离的特点,使得代码结构上比组合式 API更清晰,更好入手;但当组件变得庞大的时候,反而会使
methods、data、computed的列表变得很长,比如代码超过了300行后,开发经常需要上下跳转,来搜集某个业务逻辑关心的数据以及方法 -
我们可以得到一个结论,也就是
Options API把某个业务逻辑关心的数据以及方法分离开了,而Composition API把同一个业务逻辑相关的代码封装进一个独立的函数,也就是说开发不再需要上下跳转,能更好维护我们的代码 -
Options API的组件抽离通用逻辑只能用mixin,且存在命名冲突的困扰,而Composition API通过独立函数进行封装,复用性更强 -
我们可以任意拆分组件的功能
(自定义Hooks),提高代码的可维护性
然后说下setup函数
setup函数会在beforeCreate之前执行- 语法糖是
<srcipt setup> - 接收
props父组件传入的属性 和context上下文对象 - 自定义Hooks是把 setup组合函数之中的
ref、reactive、computed、watch、生命周期钩子等进行了封装抽离代码(公共代码,公共组件等),这样使得代码更加简洁。自定义Hooks相当于vue2中的mixin,我们约定这些自定义 Hooks 函数以use作为前缀,和普通的函数加以区分
接着是Vue的核心 -> 响应式方案
- Vue2 的 defineProperty
const obj = {};
let current = 1,sum = 0;
const add = n => n += 1;
Object.defineProperty(obj, "current", {
get() {
return current;
},
set(val) {
current = val;
sum = add(val);
},
});
console.log(sum); //0
obj.current = 2;
console.log(sum); //3
delete obj.current
console.log(sum); //3 还是之前的值,这说明Vue2的defineProperty监听不到属性的删除,需要专门的$delete函数来清理数据
- Proxy(用于Vue3 的 reactive )
const obj = {};
let current = 1,sum = 0;
const add = n => n += 1;
const proxy = new Proxy(obj, {
get(target, prop) {
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
if (prop === "current") {
sum = add(value);
}
},
deleteProperty(target, prop) {
delete target[prop];
if (prop === "current") {
sum = -1;
}
},
});
console.log(obj.current, sum); //undefined 0
proxy.current = 2;
console.log(obj.current, sum); // 2 3
delete proxy.current;
console.log(obj.current, sum); //undefined -1 删除后值更新,说明Proxy可以监听到属性的删除
const obj = reactive({ count: 0 }) //深层的响应式对象,影响所有嵌套property
//类比一下react的usestate~
const [ state, setState ] = useState({ count: 0 })
- value setter(用于Vue3 的 ref)
const add = n => n += 1;
let current = 1,sum = 0
const obj = {
get value() {
return current;
},
set value(val) {
current = val;
sum = add(current);
},
};
console.log(obj.value, sum); //1 0
obj.value = 2;
console.log(obj.value, sum); //2 3
const count = ref(0)
console.log(count.value) // 0
//类比一下react的useRef~
const _count = useRef(0)
console.log(count.current) // 0
新版生命周期
- 可按需导入到组件中,且只能在 setup() 函数中使用
<script lang="ts">
import {
defineComponent,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onErrorCaptured,
onMounted,
onUnmounted,
onUpdated,
} from "vue";
export default defineComponent({
setup(props, context) {
onBeforeMount(() => {
console.log("beformounted----");
});
onMounted(() => {
console.log("mounted----");
});
onBeforeUpdate(() => {
console.log("beforupdated----");
});
onUpdated(() => {
console.log("updated----");
});
onBeforeUnmount(() => {
console.log("beforunmounted----");
});
onUnmounted(() => {
console.log("unmounted----");
});
onErrorCaptured(() => {
console.log("errorCaptured----");
});
return {};
},
});
</script>
Vue3 所有模块使用 TypeScript 重构
- TypeScript 类型系统带来了更方便的提示,并且让我们的代码能够更健壮,能够带来更好的可维护性
- Vue 2 使用 Flow.js 来做类型校验。但现在 Flow.js 已经停止维护了
Vue3 新增了 Fragment、Teleport 和 Suspense 等组件
- 本文不再介绍,可以自行了解