layout: center
VUE2.0回顾
Object.defineProperty
- Vue 2 响应式并不是真正意义上的代理,而是基于 Object.defineProperty() 实现的。
1.无法检测到对象的新增、删除。
2.无法检测到Array数据的变化。
const obj = {};
Object.defineProperty(obj, 'a', {
set(val) {
console.log(`开始设置新值: ${val}`)
},
get() {
console.log(`开始读取属性`)
return 1;
},
writable : true
})
obj.a = 2 // 开始设置新值: 2
obj.a // 开始获取属性
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// ...
if (Dep.target) {
// 收集依赖
dep.depend()
}
return value
},
set: function reactiveSetter (newVal) {
// ...
// 通知视图更新
dep.notify()
}
})
开发效率问题
-
Vue2 对TS支持不友好,Vue 2 是使用 Flow.js 来做类型校验,Flow.js 已经停止维护了。Vue2 需要vue-class-component强化vue原生组件,也需要vue-property-decorator增加更多结合Vue特性的装饰器,写法比较繁琐。
-
Option API 在组织代码较多组件的时候不易维护。
-
通用逻辑代码不好复用,虽然提供了mixin,还会带来命名冲突的问题。
layout: center
Proxy
new Proxy(obj, {
get(target, propKey, receiver) {
return Reflect.get(target, propKey, receiver)
},
set(target, propkey, value, proxy) {
return Reflect.set(target, propkey, value, proxy)
},
...
})
Proxy 存在一些兼容性问题, 不兼容 IE11 以下的浏览器
TypeScript
- 全部模块使用 TypeScript 重构,TS可以带来更方便的代码提示,并且让我们的代码能够更健壮。
let name:string = 'vuejs'
name = 1 // 报错
interface Person {
name: string;
age: number;
}
let me:Person = {
name:'vue',
age:18
}
me.age = '18' // 报错
layout: center
Composition API
Composition API
Ref
import { ref } from 'vue'
let foo = 0
let bar = ref(0)
foo = 1
bar = 1 // ts-error
bar.value = 1 // success
Reactive
import { reactive } from 'vue'
const foo = { prop: 0 }
const bar = reactive({ prop: 0 })
foo.prop = 1
bar.prop = 1
Composition API
setup
import { ref } from 'vue'
setup() {
const count = ref(0)
// 返回值会暴露给模板和其他的选项式 API 钩子
return {
count
}
}
setup
import { ref } from 'vue'
setup(props, { attrs, slots, emit, expose }) {
...
}
Composition API
toRefs
import { reactive, toRefs } from "vue"
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:{
foo: Ref<number>,
bar: Ref<number>
}
*/
// 这个 ref 和源属性已经“链接上了”
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
toRefs
import { reactive } from "vue"
const state = reactive({
foo: 1,
bar: 2
})
// ...基于状态的操作逻辑
// 在返回时都转为 ref
return toRefs(state)
Composition API
watch
import { reactive,watch } from 'vue'
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
},
)
watchEffect
import { ref,watchEffect } from 'vue'
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 输出 0
count.value++
// -> 输出 1
Composition API
computed
import { ref, computed } from 'vue'
//创建一个只读的计算属性 ref:
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
computed
//创建一个可写的计算属性 ref:
import { ref, computed } from 'vue'
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
Composition API
Composition API带来的好处
- 所有 API 都是 import 引入的,用到的功能都 import 进来,没有用到的打包的时候会被清理掉 ,减小包的大小。
- 可以把一个功能模块的 methods、data 都放在一起书写,方便维护。
- 代码方便复用
CompositionAPI VS optionsApi
layout: center
可组合函数 HOOKS
可组合函数 HOOKS
useDOMCreate
import { onUnmounted } from 'vue'
function useDOMCreate(nodeId: string) {
const node = document.createElement('div')
node.id = nodeId
document.body.appendChild(node)
onUnmounted(() => {
document.body.removeChild(node)
})
}
export default useDOMCreate
useClickOutside
import { ref, onMounted, onUnmounted, Ref } from 'vue'
const useClickOutside = (elementRef: Ref<null | HTMLElement>) => {
const isClickOutside = ref(false)
const handler = (e: MouseEvent) => {
if (elementRef.value) {
if (elementRef.value.contains(e.target as HTMLElement)) {
isClickOutside.value = false
} else {
isClickOutside.value = true
}
}
}
onMounted(() => {
document.addEventListener('click', handler)
})
onUnmounted(() => {
document.removeEventListener('click', handler)
})
return isClickOutside
}
export default useClickOutside
可组合函数使用
import { defineComponent, ref, watch } from 'vue'
import useClickOutside from './useClickOutside'
export default defineComponent({
setup() {
const isClickOutside = useClickOutside(dropdownRef)
return {}
}
})
其他新功能
- Vue3.0生态(Vite、Pinia、VueRouter、SSR)
- 新的组件,Vue 3 内置了 Fragment、Teleport 和 Suspense 三个新组件
- 自定义渲染器
<script setup>
click here