Vue2中的options API和Vue3.0中composition API
options API示例
composition API是一组基于函数的API,可以更灵活的组织组件的逻辑
createAPP函数的第一个参数即composition API对象用于创建应用实例
createApp({
setup () {
const count=ref(0)
return {
count
}
}
}).mount('#app')
ref,reactive,watch,watchEffect,computed的使用示例
reactive 用于创建一个响应式的对象。
import { reactive } from 'vue';
const state = reactive({
count: 0,
double: computed(() => state.count * 2) // 依赖于 count 的计算属性
});
// 修改 state 对象的属性
state.count++;
watch 用于观察一个数据的变化,并在其变化时执行回调函数。
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count 变化:${oldValue} -> ${newValue}`);
});
watchEffect 用于创建一个立即执行的响应式效果,并在其依赖的响应式数据变化时重新执行。
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
console.log(`count 的值为:${count.value}`);
});
Vue3编程注重面向过程编程,将过程抽象为一个函数,例如添加待办事项,首先有一个input,在输入敲击键盘Enter键时执行添加待办事项的方法,若Vue2中在data中声明input绑定的值,在输入敲击键盘Enter键时Object对象然后将对象存储起来,而用了Vue3的composition API之后input绑定的值和添加事件放在同一个函数中,编程如下,函数中仍可使用ref,reactive,watch,watchEffect,computed
// 1. 添加待办事项
const useAdd = todos => {
const input = ref('')
const addTodo = () => {
const text = input.value && input.value.trim()
if (text.length === 0) return
todos.value.unshift({
text,
completed: false
})
input.value = ''
}
return {
input,
addTodo
}
}
// 5. 存储待办事项
const useStorage = () => {
const KEY = 'TODOKEYS'
const todos = ref(storage.getItem(KEY) || [])
watchEffect(() => {
storage.setItem(KEY, todos.value)//监听todos.value,一旦todos.value重新改变便会重新再storage中设值
})
return todos
}
export default {
name: 'App',
setup () {
const todos = useStorage()
return {
todos,
...useAdd(todos),
}
},
directives: {
editingFocus: (el, binding) => {
binding.value && el.focus()
}
}
}
Vue3的响应式系统
Vue3中使用Proxy对象重写响应式系统,可以监听动态新增的属性,可以监听删除的属性,可以监听数组的索引和length属性
Proxy 可以用来拦截并定义对象的基本操作(比如属性查找、赋值、删除等)。通过 Proxy,你可以监视并对对象的操作进行自定义处理。
Object.defineProperty 用于在对象上定义新的属性,或修改现有属性的特性(比如可枚举性、可写性、可配置性等)。它只能针对单个属性进行拦截,而不能拦截整个对象的操作
Reflect 是 ES6 中引入的一个新的内置对象,常用get,set方法
响应原理在读取(GET操作)时,自动执行track()函数收集依赖,在修改(SET操作)时,自动执行trigger()函数来执行所有的副作
const isObject = val => val !== null && typeof val === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target, key)
export function reactive (target) {
if (!isObject(target)) return target
const handler = {
get (target, key, receiver) {
// 收集依赖
track(target, key)
const result = Reflect.get(target, key, receiver)
return convert(result)
},
set (target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver)
let result = true
if (oldValue !== value) {
result = Reflect.set(target, key, value, receiver)
// 触发更新
trigger(target, key)
}
return result
},
deleteProperty (target, key) {
const hadKey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if (hadKey && result) {
// 触发更新
trigger(target, key)
}
return result
}
}
return new Proxy(target, handler)
}
let activeEffect = null
export function effect (callback) {
activeEffect = callback
callback() // 访问响应式对象属性,去收集依赖
activeEffect = null
}
let targetMap = new WeakMap()
export function track (target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
dep.add(activeEffect)
}
export function trigger (target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const dep = depsMap.get(key)
if (dep) {
dep.forEach(effect => {
effect()
})
}
}
自写响应式原理使用示例
import { reactive, effect } from './reactivity/index.js'
const product = reactive({
name: 'iPhone',
price: 5000,
count: 3
})
let total = 0
effect(() => {
total = product.price * product.count
})
console.log(total)
product.price = 4000