Vue 运行原理分析

发布于 2022-09-20 23:06:32 字数 6317 浏览 123 评论 0

第一步完成深度观察

class Vue {
  constructor (options) {
    this.$el = options.el;
    this.$options = options;
    this.$data = options.data;
    if (this.$el) {
      new Observer(this.$data)
    }
  }
}

class Observer {
  constructor(data) {
    this.observe(data)
  }
  observe (obj) {
    if (obj && typeof obj === 'object') {
      for (const key in obj) {
        this.defineReactive(obj, key, obj[key])
      }
    }
  }
  defineReactive (obj, key, value) {
    this.observe(value)
    Object.defineProperty(obj, key, {
      get () {
        return value
      },
      set: (newValue) => {
        if (value !== newValue) {
          value = newValue
          this.observe(newValue)
        }
      }
    })
  }
}

第二步将 DOM 放到内存中

class Vue {
  constructor (options) {
    this.$el = options.el;
    this.$options = options;
    this.$data = options.data;
    if (this.$el) {
      new Observer(this.$data)
      new Compiler(this.$el, this)
    }
  }
}

class Compiler {
  constructor (el, vm) {
    this.vm = vm;
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    let fragment = this.nodeFragment(this.el);
    this.compile(fragment)
    this.el.appendChild(fragment)
  }
  compile (node) {
    console.log(node, '开发分析DOM节点')
  }
  nodeFragment (node) {
    let fragment = document.createDocumentFragment()
    let firstChild;
    while (firstChild = node.firstChild) {
      fragment.appendChild(firstChild)
    }
    return fragment
  }
  isElementNode (node) {
    return node.nodeType === 1;
  }
}

第三步分析模板里面的内容

let CompileUtil = {
  text (node, expr, vm) {
    let handler = this.updater['text']
    let content = expr.replace(/\{\{(.+?)\}\}/, (...args) => {
      return this.getValue(args[1], vm)
    })
    handler(node, content)
  },
  getValue(expr, vm) {
    return expr.split('.').reduce((data, current) => {
      return data[current]
    }, vm.$data)
  },
  updater: {
    text (node, value) {
      node.textContent = value
    }
  }
}

class Compiler {
  constructor (el, vm) {
    this.vm = vm;
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    let fragment = this.nodeFragment(this.el);
    this.compile(fragment)
    this.el.appendChild(fragment)
  }
  compile (node) {
    let nodeList = node.childNodes;
    Array.from(nodeList, child => {
      if (this.isElementNode(child)) {
        this.compileElement(child)
        this.compile(child)
      } else {
        this.compileText(child)
      }
    })
  }
  compileElement (node) {
    // 分析元素节点
  }
  compileText (node) {
    // 分析文本节点
    // 1. 小胡子语法里面要替换成我们想要的内容
    let content = node.textContent;
    if (/\{\{(.+?)\}\}/.test(content)) {
      CompileUtil.text(node, content, this.vm)
    }
  }
  nodeFragment (node) {
    let fragment = document.createDocumentFragment()
    let firstChild;
    while (firstChild = node.firstChild) {
      fragment.appendChild(firstChild)
    }
    return fragment
  }
  isElementNode (node) {
    return node.nodeType === 1;
  }
}

第三步观察者模式进行绑定

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.oldVale = this.get()
  }
  get () {
    Dep.target = this;
    // 取值操作
    let value = CompileUtil.getValue(this.expr, this.vm)
    Dep.target = null;
    return value
  }
  update () {
    let newValue = CompileUtil.getValue(this.expr, this.vm)
    if (newValue !== this.oldVale) {
      // 当比较两个值不相等的情况下执行回调
      this.cb(this.newValue)
    }
  }
}

class Vue {
  constructor(options) {
    this.$el = options.el;
    this.$options = options;
    this.$data = options.data;
    if (this.$el) {
      new Observer(this.$data)
      new Compiler(this.$el, this)
    }
  }
}

class Observer {
  constructor(data) {
    this.observe(data)
  }
  observe(obj) {
    if (obj && typeof obj === 'object') {
      for (const key in obj) {
        this.defineReactive(obj, key, obj[key])
      }
    }
  }
  defineReactive(obj, key, value) {
    this.observe(value)
    let dep = new Dep()
    Object.defineProperty(obj, key, {
      get() {
        Dep.target && dep.addSub(Dep.target)
        return value
      },
      set: (newValue) => {
        if (value !== newValue) {
          value = newValue
          this.observe(newValue)
          dep.notify()
        }
      }
    })
  }
}

let CompileUtil = {
  text(node, expr, vm) {
    let handler = this.updater['text']
    let content = expr.replace(/\{\{(.+?)\}\}/, (...args) => {
      new Watcher(vm, args[1], () => {
        // 处理函数
        handler(node, this.getContentValue(vm, expr))
      })
      return this.getValue(args[1], vm)
    })
    handler(node, content)
  },
  getContentValue (vm, expr) {
    return expr.replace(/\{\{(.+?)\}\}/, (...args) => {
      return this.getValue(args[1], vm)
    })
  },
  getValue(expr, vm) {
    return expr.split('.').reduce((data, current) => {
      return data[current]
    }, vm.$data)
  },
  updater: {
    text(node, value) {
      node.textContent = value
    }
  }
}

class Compiler {
  constructor(el, vm) {
    this.vm = vm;
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    let fragment = this.nodeFragment(this.el);
    this.compile(fragment)
    this.el.appendChild(fragment)
  }
  compile(node) {
    let nodeList = node.childNodes;
    Array.from(nodeList, child => {
      if (this.isElementNode(child)) {
        this.compileElement(child)
        this.compile(child)
      } else {
        this.compileText(child)
      }
    })
  }
  compileElement(node) {
    // 分析元素节点
  }
  compileText(node) {
    // 分析文本节点
    // 1. 小胡子语法里面要替换成我们想要的内容
    let content = node.textContent;
    if (/\{\{(.+?)\}\}/.test(content)) {
      CompileUtil.text(node, content, this.vm)
    }
  }
  nodeFragment(node) {
    let fragment = document.createDocumentFragment()
    let firstChild;
    while (firstChild = node.firstChild) {
      fragment.appendChild(firstChild)
    }
    return fragment
  }
  isElementNode(node) {
    return node.nodeType === 1;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

悍妇囚夫

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文