简要实现Vue

【简要实现Vue】实现:

/* * Time: 2021/09/09 * Author: tony_cyt * About: 简要实现Vue */class Vue { /** * @description: Vue构造函数 * @param {*} options * @return {*} */ constructor(options) { // 赋值el和data const { el, data, computed } = options; this.$el = el; this.$data = https://www.it610.com/article/data; // 如果$el存在,就走编译流程 if (this.$el) { new Observer(this.$data); for (const key in computed) { Object.defineProperty(this.$data, key, { get: () => { return computed[key].call(this); } }) } this.proxyData(this.$data); new Compiler(this.$el, this); } } proxyData(data) { for (const key in data) { Object.defineProperty(this, key, { get: () => { return data[key]; } }) } } }/** * @description: 自定义指令集 * @param {*} * @return {*} */ CompilerUtil = { getVal(vm, expr) { return expr.split('.').reduce((data, current) => { return data[current]; }, vm.$data) }, setVal(vm, expr, value) { expr.split('.').reduce((data, current, index, arr) => { if (index === arr.length - 1) { return data[current] = value; } return data[current]; }, vm.$data); }, model(node, expr, vm) { const value = https://www.it610.com/article/this.getVal(vm, expr); const fn = this.updater['modeUpdater']; new Watcher(vm, expr, newValue => { fn(node, newValue); }) node.addEventListener('input', e => { this.setVal(vm, expr, e.target.value); }) fn(node, value); }, getContentValue(vm, expr) { return expr.replace(/\{\{(.+?)\}\}/g, (...args) => { return this.getVal(vm, args[1]); }) }, text(node, expr, vm) { const fn = this.updater['textUpdater']; const content = expr.replace(/\{\{(.+?)\}\}/g, (...args) => { new Watcher(vm, args[1], () => { fn(node, this.getContentValue(vm, expr)); }) return this.getVal(vm, args[1]); }) fn(node, content); }, html() {}, updater: { modeUpdater(node, value) { node.value = https://www.it610.com/article/value; }, textUpdater(node, value) { node.textContent = value; }, htmlUpdater() {} } }class Compiler { /** * @description: 编译器构造函数 * @param {*} el * @param {*} vm * @return {*} */ constructor(el, vm) { this.vm = vm; this.el = this.isElementNode(el) ? el : document.querySelector(el); const fragment = this.nodeToFragment(this.el); this.compile(fragment); this.el.append(fragment); } /** * @description: 判断是不是元素节点 * @param {*} node * @return {*} */ isElementNode(node) { return node.nodeType === 1; } /** * @description: 生成文档片段 * @param {*} node * @return {*} */ nodeToFragment(node) { const fragment = document.createDocumentFragment(); let firstChild; while (firstChild = node.firstChild) { fragment.append(firstChild); } return fragment; } /** * @description: 根据类型编译 * @param {*} node * @return {*} */ compile(node) { [...node.childNodes].forEach(child => { if (this.isElementNode(child)) { this.compileElement(child); // 递归节点遍历 this.compile(child); } else { this.compileText(child); } }) } /** * @description: 编译文本节点 * @param {*} node * @return {*} */ compileText(node) { const reg = /\{\{(.+?)\}\}/; if (reg.test(node.textContent)) { CompilerUtil['text'](node, node.textContent, this.vm); } } /** * @description: 判断是否是指令 * @param {*} attrName * @return {*} */ isDirective(attrName) { return attrName.startsWith('v-'); } /** * @description: 编译元素节点 * @param {*} node * @return {*} */ compileElement(node) { [...node.attributes].forEach(attr => { const { name, value: expr } = attr; if (this.isDirective(name)) { const [, directive] = name.split('-'); CompilerUtil[directive](node, expr, this.vm); } }) } }/** * @description: 实现数据响应式 * @param {*} * @return {*} */ class Observer { constructor(data) { this.observer(data); } observer(data) { if (data && typeof data =https://www.it610.com/article/=='object') { for (const key in data) { this.defineReactive(data, key, data[key]); } } } defineReactive(obj, key, value) { this.observer(value); const dep = new Dep(); Object.defineProperty(obj, key, { get() { Dep.target && dep.subs.push(Dep.target); return value; }, set: (newValue) => { if (newValue !== value) { this.observer(newValue); value = https://www.it610.com/article/newValue; dep.notify(); } } }) } }/** * @description: 存储观察者 * @param {*} * @return {*} */ class Dep { constructor() { this.subs = []; } addSub(watcher) { this.subs.push[watcher]; } notify() { this.subs.forEach(watcher => { watcher.update(); }) } }class Watcher { constructor(vm, expr, cb) { this.vm = vm; this.expr = expr; this.cb = cb; this.oldValue = https://www.it610.com/article/this.get(); } get() { Dep.target = this; const value = CompilerUtil.getVal(this.vm, this.expr); Dep.target = null; return value; } update() { const newValue = CompilerUtil.getVal(this.vm, this.expr); if (newValue !== this.oldValue) { this.cb(newValue); } } }

使用:
MVVM - 锐客网 {{school.name}} {{school.age}} {{newName}}
  • 1
  • 2

效果:
简要实现Vue
文章图片

    推荐阅读