v-if和v-show核心考点源码分析

371 阅读1分钟

!v.show && k.parentNode.replaceChild(v.comment, k);\

v.show ? (k.style.display = 'none') : (k.style.display = 'block');

class Xiaoye {
  
  constructor (options) {
    const { el, data, methods } = options;
    this.el = document.querySelector(el);
    this.data = data;
    this.methods = methods;
    this.showPool = new Map();
    this.eventPool = new Map();
    this.init();
  }



  init () {
    this.initData();
    this.initDom(this.el);
    this.initView(this.showPool);
    this.initEvent(this.eventPool);
  }

  // 1.代理数据与数据劫持
  initData () {
    for (let key in this.data) {
      // this.boxShow1 -> this.data.boxShow1
      Object.defineProperty(this, key, {
        get () {
          console.log('访问:', key, this.data[key]);
          return this.data[key];
        },
        set (newValue) {
          console.log('设置:', key, newValue);
          this.data[key] = newValue;
          this.domChange(key, this.showPool);
        }
      })
    } 
  }
  // 2. 初始化DOM

  initDom (el) {
    const _childNodes = el.childNodes;

    if (!_childNodes.length) {
      return;
    }

    _childNodes.forEach(dom => {
      if (dom.nodeType === 1) {
        const vIf = dom.getAttribute('v-if');
        const vShow = dom.getAttribute('v-show');
        const vEvent = dom.getAttribute('@click');
        if (vIf) {
          this.showPool.set(dom, {
            type: 'if',
            show: this.data[vIf],
            data: vIf
          })
        } else if (vShow) {
          this.showPool.set(dom, {
            type: 'show',
            show: this.data[vShow],
            data: vShow
          });
        }

        if (vEvent) {
          this.eventPool.set(dom, this.methods[vEvent]);
        }
      }

      this.initDom(dom);
    })
  }
  
   // 3. 初始化视图
  initView (showPool) {
    this.domChange(null, showPool);
  }
  
  domChange (data, showPool) {
    if (!data) {
      for (let [k, v] of showPool) {
        switch (v.type) {
          case 'if':
            v.comment = document.createComment(`v-if`);
            !v.show && k.parentNode.replaceChild(v.comment, k);
            break;
          case 'show':
            !v.show && (k.style.display = 'none')
            break;
          default:
            break;
        }
      }

      return;
    }

    for (let [k, v] of showPool) {
      if (v.data === data) {
        switch (v.type) {
          case 'if':
            v.show ? k.parentNode.replaceChild(v.comment, k)
                   : v.comment.parentNode.replaceChild(k, v.comment);
            v.show = !v.show;
            break;
          case 'show':
            v.show ? (k.style.display = 'none')
                   : (k.style.display = 'block');
            v.show = !v.show;      
            break;
          default:
            break;
        }
      }
    }
  }

   // 4. eventPool 事件处理函数的绑定
  initEvent (eventPool) {
    for (let [k, v] of eventPool) {
      k.addEventListener('click', v.bind(this), false);
    }
  }
   // 5. 改变数据的同时,改变DOM
}