vue3.o源码分析
[[toc]]
前言 调研的预览版本,很多api还没完善,但大致架构已经成形, 暂时还不能用于生产。
优势
函数式编程,函数对ts兼容性好【react-hooks】
static tree hoisting 功能 (检测静态语法,进行提升) 【diff】
基于 Proxy 实现的数据变更检测 【不需要递归了,节省内存】
支持 Fragments 【 react 空标签,当根元素用】
支持 Portals 【react 允许在DOM的其它位置进行渲染】
同时支持 Composition API 和 Options API 【单文件兼容vue2.o】
Custom Renderer API 【自定义渲染器API】
源码目录 ├── packages │ ├── compiler-core # 所有平台的编译器(weex也是基于这个) │ ├── compiler-dom # 针对浏览器的编译器 │ ├── compiler-ssr # ssr │ ├── compiler-sfc # 针对单文件 │ ├── reactivity # 数据响应式系统 │ ├── runtime-core # 渲染器,一些核心的api │ ├── runtime-dom # 针对浏览器的runtime,包括处理原生DOM │ ├── runtime-test # 专门为测试写的runtime │ ├── server-renderer # 用于SSR │ ├── shared # 帮助方法 │ ├── template-explorer │ └── vue # 构建vue
composition-api Composition API纯粹是添加的,不会影响/弃用任何现有的2.x API,它是可以单独导入到项目中的
动机
Vue 3 使用ts实现了类型推断,新版api全部采用普通函数,在编写代码时可以享受完整的类型推断(避免使用装饰器)
解决了多组件间逻辑重用 问题 (解决:高阶组件、mixin、作用域插槽)
如果项目过于复杂的时候,mixin中的代码和外部组件的代码存在命名冲突的时候会被覆盖,而且如果有相同的生命周期函数也会被覆盖,所以会导致代码难以维护,容易出现bug
代码分散
// 安装 yarn add @vue/composition-api // 使用 import Vue from ‘vue’; import VueCompositionApi from ‘@vue/composition-api’; Vue.use(VueCompositionApi);
reactive Object.defineProperty() let oldProtoMehtods = Array .prototype;let proto = Object .create(oldProtoMehtods);['push' , 'pop' , 'shift' , 'unshift' , 'sort' , 'reverse' , 'splice' ].forEach(method => { proto[method] = function ( ) { updateView(); observer(...arguments); oldProtoMehtods[method].call(this , ...arguments) } }); function observer (target ) { if (!isObject(target)) return target; if (Array .isArray(target)) { target.__proto__ = proto; for (let i = 0 ; i < target.length; i++) { observer(target[i]) } return } for (let key in target) { defineReactive(target, key, target[key]) } } function defineReactive (target, key, value ) { observer(value); Object .defineProperty(target, key, { get () { return value }, set (newVal) { console .log('set方法' , newVal); if (newVal !== value) { updateView(); observer(newVal); } } }) } let data = {ary : [1 , 2 , {age : 22 }]};let result = observer(data);data.ary.push({age : 33 }); data.ary.push([1 , 2 , 3 ]); data.ary[4 ].push(1 ); data.ary[4 ].splice(1 , 1 , 22222 ); console .log(data.ary);
缺点
vm.items[indexOfItem] = newValue vm.items.length = newLength vm.$set (vm.items, indexOfItem, newValue) vm.items.splice(indexOfItem, 1, newValue) vm.items.splice(newLength)
Proxy
effect ref 下面是自己提炼的的核心代码,源码分析看这
const convert = (val ) => { return isObject(val) ? reactive(val) : val }; function ref (rawValue ) { let value = convert(rawValue); const result = { __v_isRef: true , get value() { return value }, set value(newVal) { console .log('视图更新' ); value = convert(newVal); } }; return result } function toRefs (object ) { const ret = {}; for (const key in object) { ret[key] = toRef(object, key) } return ret } function toRef (object, key ) { return { __v_isRef: true , get value() { return object[key] }, set value(newVal) { object[key] = newVal } } }
computed Beta升级使用 写demo可以,公司正式项目不建议,后期少不了小改动
安装3.o新版本
yarn add vue@next vue-router@next vuex@next yarn add @vue/compiler-sfc@next eslint-plugin-vue@next vue-cli-plugin-vue-next -D
逻辑复用 import { ref, onMounted, onUnmounted } from 'vue' export function useMousePosition ( ) { const x = ref(0 ) const y = ref(0 ) function update (e ) { x.value = e.pageX y.value = e.pageY } onMounted(() => { window .addEventListener('mousemove' , update) }) onUnmounted(() => { window .removeEventListener('mousemove' , update) }) return { x, y } } import { useMousePosition } from './mouse' export default { setup() { return { ...useMousePosition() } } }
参考文档 vue-next vue-cli-plugin-vue-nex vue-composition-api文档 vue3的编译工具 尤雨溪在Vue3.0Beta直播里聊到了这些 juejin segmentfault