手擼一個Vue(看不懂可以舉報)
手擼一個Vue
背景
vue是啥,有哪些基本功能,模板,script, style, 雙向綁定一大堆,太多東西了,太難了,直接開始動手吧
倉庫
https://github.com/listen80/two-way-binding
體驗一下(pc上使用)
https://listen80.github.io/two-way-binding/public/
單文件
通過ajax獲取類似.vue .html .tpl文件
const parser = new DOMParser();
export default (template) => {
const doc = parser.parseFromString(`<body>${template}</body>`, 'text/html');
const body = doc.querySelector('body')
return {
template: body.querySelector('template')?.content,
script: body.querySelector('script'),
style: body.querySelector('style'),
}
};
構建vue實例
- 把script文本變成script運行
- 把原始data變成reactive的形式,增加依賴收集
- 解析template,扣出來指令,屬性,方法,子組件等為了區分指令前綴使用@而不是v-
- 掛載style樣式增加
- 替換當前實例掛載的元素,目前為止所有的元素(html, script, style)都已經使用上來了
// ...上面還有
/**
* 創建組件,加載組件腳本、樣式和模板,并進行渲染
*/
create() {
// 從配置選項中解構出目標元素和屬性
const { el, props = {} } = this.options
// 從組件屬性中解構出腳本、模板和樣式
const { script, template, style } = this.componentProperties
// 1. 獲取的ES6代碼是模
// 獲取腳本標簽中的 ES6 模塊代碼
const es6ModuleCode = script.textContent;
// 2. 將代碼轉為blob URL(模擬模塊文件)
// 創建一個包含 ES6 模塊代碼的 Blob 對象
const blob = new Blob([es6ModuleCode], { type: 'text/javascript' });
// 為 Blob 對象創建一個 URL
const url = URL.createObjectURL(blob);
// 3. 用動態import()加載該模塊
// 動態導入模塊
import(url).then(module => {
// 將樣式添加到文檔中
document.head.append(style)
// console.log(module.default); // 輸出 'ES6 Module'
// 獲取模塊中的數據,若不存在則使用空對象
const data = module.default.data || {};
// 獲取模塊中的方法,若不存在則使用空對象
const methods = module.default.methods || {};
// 獲取模塊中的子組件,若不存在則使用空對象
const components = module.default.components || {};
// 將屬性和數據合并到當前實例
Object.assign(this, props, data);
// 對當前實例進行數據觀測
observe(this);
// this.data = data
// 編譯模板并渲染
compile(template, this, methods, components);
// 終于明白這里為什么是replace
// 用模板替換目標元素
el.replaceWith(template)
}).catch(err => {
// 捕獲模塊加載失敗的錯誤并打印
console.error('加載模塊失敗', err);
});
}
總結
就這么結束了,是不是很簡單,當然其中的細節很多,上文主要是描述核心思想點
本demo是沒有使用虛擬dom,是dom跟數據直接綁定的,跟進vue3.6 vapor
水平有限,本文只是為了學習分享簡單的示例,目的是為了了解運作機制,如果有紕漏請聯系我
本文來自博客園,作者:彩虹刀法,轉載請注明原文鏈接:http://www.rzrgm.cn/listen80/p/19026582

浙公網安備 33010602011771號