vue-toy200 行左右代碼模擬 vue 實現(xiàn)
vue-toy
npm install --save vue-toy
200行左右代碼模擬vue實現(xiàn)。
Vue(options)
interface Options { el: HTMLElement | string; propsData?: Record<string, any>; props?: string[]; name?: string; data?: () => Record<string, any>; methods?: Record<string, (e: Event) => void>; computed?: Record<string, () => any>; watch?: Record<string, (newValue: any, oldValue: any) => any>; render: (h: typeof React.createElement) => React.ReactNode; renderError?: (h: typeof React.createElement, error: Error) => React.ReactNode; mounted?: () => void; updated?: () => void; destroyed?: () => void; errorCaptured?: (e: Error, vm: React.ReactInstance) => void; }
示例:
import Vue from "vue-toy";
new Vue({
el: document.getElementById("root"),
data() {
return {
msg: "hello vue toy"
};
},
render(h) {
return h("h1", null, this.msg);
}
});
注1:vue-toy不包含template的編譯實現(xiàn),因為vue的template最終是編譯成類似代碼:
render(h) {
with(this){
return h("h1", null, msg);
}
}
本教程中使用了嚴格模式無法使用with,所以在render里無法省略this。
注2:vue-toy的視圖渲染使用的react,所以render方法的使用同react#render,如:
import Vue from "vue-toy";
import React from "react";
new Vue({
el: document.getElementById("root"),
data() {
return {
msg: "hello vue toy"
};
},
render() {
return <h1>{this.msg}</h1>
}
});
全局 API
Vue.component(ComponentOptions)
interface ComponentOptions { props?: string[]; name?: string; data?: () => Record<string, any>; methods?: Record<string, (e: Event) => void>; computed?: Record<string, () => any>; watch?: Record<string, (newValue: any, oldValue: any) => any>; render: (h: typeof React.createElement) => React.ReactNode; renderError?: (h: typeof React.createElement, error: Error) => React.ReactNode; mounted?: () => void; updated?: () => void; destroyed?: () => void; errorCaptured?: (e: Error, vm: React.ReactInstance) => void; }
示例:
const Hello = Vue.component({ props: ["msg"], render(h){ return h('div', null, this.msg); } }); export default Hello;
基本原理
// 創(chuàng)建觀察對象 // 觀察對象主要使用的是Object.defineProperty或Proxy來實現(xiàn), // 也可使用類似angular.js的臟檢測(不過需要額外的檢測調(diào)用), // 如果不在意寫法也可以參考knockout或 setXXX getXXX的方式 const data = observable({ name: 'vue-toy', }); // 渲染模版 const render = function(){ return <h1>{data.name}</h1> } // 計算render的依賴屬性, // 依賴屬性改變時,會重新計算computedFn,并執(zhí)行監(jiān)控函數(shù)watchFn, // 屬性依賴計算使用棧及可以了。 // watch(computedFn, watchFn); watch(render, function(newVNode, oldVNode){ update(newVNode, mountNode); }); //初始渲染 mount(render(), mountNode); // 改變觀察對象屬性,如果render依賴了該屬性,則會重新渲染 data.name = 'hello vue toy';
視圖渲染部分(既render)使用的是vdom技術(shù),vue2+使用
Snabbdom庫,vue-toy使用的是react來進行渲染,所以在render函數(shù)里你可以直接使用React的JSX語法,不過別忘記import React from 'react',當然也可以使用preactinferno等 vdom庫。
由于vue的template的最終也是解析并生成render函數(shù),模版的解析可用
htmleParser庫來生成AST,剩下就是解析指令并生產(chǎn)代碼,由于工作量大,這里就不具體實現(xiàn),直接使用jsx。
評論
圖片
表情
