美文网首页
Vue 双向绑定原理+图解

Vue 双向绑定原理+图解

作者: ThunderChen | 来源:发表于2021-09-11 22:50 被阅读0次

    回顾下双向绑定的原理~,此段代码仅为复习笔记.简书不倒,知识永存!

       <div id="app">
          <input type="text" v-model="message" />
          {{message}}
        </div>
        <script>
          class ThunderVue {
            constructor(options) {
              //保存数据
              this.$options = options;
              this.$data = options.data;
              this.$el = options.el;
              //将data添加到响应式系统当中
              new Observer(this.$data);
              //代理this.$data中的数据
              Object.keys(this.$data).forEach((key) => {
                this._proxy(key);
              });
              //处理el
              new Compiler(this.$el, this);
            }
            _proxy(key) {
              Object.defineProperty(this, key, {
                configurable: true,
                enumerable: true,
                set(nv) {
                  this.$data[key] = nv;
                },
                get() {
                  return this.$data[key];
                },
              });
            }
          }
    
          class Observer {
            //观察者
            constructor(data) {
              if (
                !data ||
                !Object.prototype.toString.call(data).indexOf('Object')
              ) {
                throw new Error('data错误');
              }
              this.data = data;
              Object.keys(data).forEach((key) => {
                this.defineReactive(this.data, key, data[key]);
              });
            }
    
            defineReactive(data, key, val) {
              const dep = new Dep();
              Object.defineProperty(data, key, {
                enumerable: true,
                configurable: true,
                get() {
                  if (Dep.target) {
                    dep.addSub(Dep.target);
                  }
                  return val;
                },
                set(nv) {
                  if (nv === val) {
                    return;
                  }
                  console.log(nv, val);
                  val = nv;
                  dep.notify();
                },
              });
            }
          }
    
          class Dep {
            constructor() {
              this.subs = [];
            }
            addSub(sub) {
              this.subs.push(sub);
            }
            notify() {
              this.subs.forEach((sub) => {
                sub.update();
              });
            }
          }
          class Watcher {
            constructor(node, name, vm) {
              this.node = node;
              this.name = name;
              this.vm = vm;
    
              Dep.target = this;
              this.update();
              Dep.target = null;
            }
            update() {
              this.node.nodeValue = this.vm[this.name];
            }
          }
          const reg = /\{\{(.+)\}\}/;
          class Compiler {
            constructor(el, vm) {
              this.el = document.querySelector(el);
              this.vm = vm; //指的是Vue实例
              this.frag = this._createFragment();
              this.el.appendChild(this.frag);
            }
            _createFragment() {
              const frag = document.createDocumentFragment();
              let child;
    
              while ((child = this.el.firstChild)) {
                this._compile(child);
                frag.appendChild(child);
              }
              return frag;
            }
            _compile(node) {
              console.log(node);
              if (node.nodeType === 1) {
                //标签节点
                const attrs = node.attributes; //
                if (attrs.hasOwnProperty('v-model')) {
                  const name = attrs['v-model'].nodeValue;
                  console.log(name);
                  node.addEventListener('input', (e) => {
                    this.vm[name] = e.target.value;
                  });
                }
              }
              if (node.nodeType === 3) {
                if (reg.test(node.nodeValue)) {
                  console.log(RegExp.$1);
                  const name = RegExp.$1.trim();
                  new Watcher(node, name, this.vm);
                }
              }
            }
          }
        </script>
        <script>
          const app = new ThunderVue({
            el: '#app',
            data: {
              message: 'thunder',
            },
          });
        </script>
    

    图解:


    Vue响应式图解.png

    师承coderwhy,预想善其事,必先利其器;了解真相才是获取真正的自由;

    相关文章

      网友评论

          本文标题:Vue 双向绑定原理+图解

          本文链接:https://www.haomeiwen.com/subject/sygawltx.html