vue指令源码实现

806 阅读1分钟

1.v-if

本文章详细讲解vue的directive指令,实现几个基本指令

import Vue from 'vue'

Vue.directive('my-if', {
  bind: function(el, binding, vNode, oldVNode) {},
  inserted: function(el, binding, vNode, oldVNode) {
    let comment = document.createComment('')
    const index = Array.from(el.parentNode.childNodes).findIndex(i => i === el)
    el.domIndex = index
    el.pNode = el.parentNode
    if (binding.value) {
      el.parentNode.replaceChild(comment, el)
    }
  },
  update: function(el, binding, vNode, oldVNode) {
    let comment = document.createComment('')
    binding.value
      ? el.pNode.replaceChild(el, el.pNode.childNodes[el.domIndex])
      : el.pNode.replaceChild(comment, el)
  },
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})

2.v-show

import Vue from 'vue'

Vue.directive('my-show', {
  bind: function(el, binding, vNode, oldVNode) {},
  inserted: function(el, binding, vNode, oldVNode) {
    binding.value ? (el.style.display = 'block') : (el.style.display = 'none')
  },
  update: function(el, binding, vNode, oldVNode) {
    binding.value ? (el.style.display = 'block') : (el.style.display = 'none')
  },
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})

3.v-model

import Vue from 'vue'

Vue.directive('my-model', {
  bind: function(el, binding, vNode, oldVNode) {
    el.value = binding.value
  },
  inserted: function(el, binding, vNode, oldVNode) {
    el.addEventListener('keyup', function(event) {
      if (vNode.context[binding.expression] !== el.value) {
        vNode.context[binding.expression] = el.value
      }
    })
  },
  update: function(el, binding, vNode, oldVNode) {
    if (el.value !== binding.value) {
      el.value = binding.value
    }
  },
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})

v-loading

import Vue from 'vue'
import LoadingComponent from '@/components/ContentLoading'

let LoadingConstructor = Vue.extend(LoadingComponent)
let initComponent

Vue.directive('loading', {
  bind: function(el, binding, vNode, oldVNode) {},
  inserted: function(el, binding, vNode, oldVNode) {
    el.style.position = 'relative'
    if (binding.value) {
      initComponent = new LoadingConstructor()
      initComponent.$mount()
      el.appendChild(initComponent.$el)
    }
  },
  update: function(el, binding, vNode, oldVNode) {
    if (binding.value) {
      initComponent = new LoadingConstructor()
      initComponent.$mount()
      el.appendChild(initComponent.$el)
    } else {
      el.removeChild(initComponent.$el)
    }
  },
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})

clickOutside

import Vue from 'vue'

Vue.directive('outerside', {
  bind: function(el, binding, vNode, oldVNode) {},
  inserted: function(el, binding, vNode, oldVNode) {
    document.addEventListener('click', (e) => {
      if (el.contains(e.target)) {
        return false
      }
      if (binding.value) {
        binding.value(e)
      }
    }, false)
  },
  update: function(el, binding, vNode, oldVNode) {
  },
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})

numberAnimation

import Vue from 'vue'
Vue.directive('numberAnimate', {
  bind: function(el, binding, vNode, oldVNode) {},
  inserted: function(el, binding, vNode, oldVNode) {
    let from = binding.value.from
    let to = binding.value.to
    let index = 0
    let step = () => {
      index += 4
      el.innerHTML = index
      if (index < to) {
        requestAnimationFrame(step)
      }
    }
    requestAnimationFrame(step)
  },
  update: function(el, binding, vNode, oldVNode) {},
  componentUpdated: function(el, binding, vNode, oldVNode) {},
  unbind: function(el, binding, vNode, oldVNode) {}
})