【学习记录24】vue3自定义指令

一、在单vue文件中直接使用

1、html部分

 2、js部分

3、实现效果

【学习记录24】vue3自定义指令_第1张图片

二、全局注册使用

1、html部分

2、js部分

在components下创建loading文件夹,在loading文件夹里创建directive.js 

// direcitve.js

import imgSrc from "@/views/loading.gif";

const loadingDirective = {
  mounted(el, binding) {
    const div = document.createElement('div')
    div.className = 'loading'
    const img = document.createElement('img')
    img.src = imgSrc
    img.width = 40
    div.appendChild(img)
    el.appendChild(div)
  },
  updated(el, binding) {
    if (!binding.value) {
      const loadingDom = document.querySelector('.loading')
      el.removeChild(loadingDom)
    }
  }
}
export default loadingDirective

在main.js中全局注册指令

// 引入loading
import loadingDirective from './components/loading/directive'


let app = createApp(App)

app.use(ElementPlus).use(router)
app.directive('loading', loadingDirective) // 全局注册
app.mount('#app')

三、使用vue组件文件实现自定义指令

1、在components下创建loading文件夹,在loading文件夹里创建directive.js

2、在loading文件夹里创建loading.vue

3、在loading文件夹里放入一张GIF图(loading.gif)

 【学习记录24】vue3自定义指令_第2张图片

 1、loading.vue文件源码

// loading.vue






2、js部分(directive.js) 

// directive.js

// 引入vue方法createApp
import {createApp} from 'vue'
// 引入添加dom和删除dom的方法
import {addClass, removeClass} from '@/assets/js/dom'

const relativeCls = 'g-relative'
const loadingDirective = {
  mounted (el, binding) {
    // 创建一个loading的vue实例
    const app = createApp(Loading)
    // 挂载loading.vue 到div DOM上
    const instance = app.mount(document.createElement('div'))
    // 把instance挂到要用指令的element下
    el.instance = instance
    const title = binding.arg
    // 如果传了title就重新设置title的值
    if (typeof title !== 'undefined') {
      instance.setTitle(title)
    }
    // 指令绑定的值为true把自定义的vue实例下的dom节点$el添加到el下
    if (binding.value) {
      append(el)
    }
  },
  // 指令绑定的值更新以后
  updated (el, binding) {
    const title = binding.arg
    if (typeof title !== 'undefined') {
      el.instance.setTitle(title)
    }
    if (binding.value !== binding.oldValue) {
      // 指令绑定的值为true添加指令dom,否则删除指令的dom
      binding.value ? append(el) : remove(el)
    }
  }
}

function append(el) {
  const style = getComputedStyle(el)
  // 如果要绑定的dom没有定位就添加一个有定位的classi
  if (!['absolute', 'fixed', 'relative'].includes(style.position)) {
    addClass(el, relativeCls)
  }
  el.appendChild(el.instance.$el)
}

function remove(el) {
  removeClass(el, relativeCls)
  el.removeChild(el.instance.$el)
}

export default loadingDirective

 3、@/assets/js/dom.js源码

export function addClass(el, className) {
  if (!el.classList.contains(className)) {
    el.classList.add(className)
  }
}

export function removeClass(el, className) {
  el.classList.remove(className)
}

4、main.js源码 

// 引入loading
import loadingDirective from './components/loading/directive'


let app = createApp(App)

app.use(ElementPlus).use(router)
app.directive('loading', loadingDirective) // 全局注册
app.mount('#app')

四、进阶(有多个自定义指令)

1、封装一个通用的js

把自定义组件的方法拎出来单独弄一个js文件,我习惯放在src/assets/js/create-my-like-directive.js

// create-my-like-directive.js

import { createApp } from 'vue'
import { addClass, removeClass } from '@/assets/js/dom'

const relativeCls = 'g-relative'

export default function createMyLikeDirective (Comp) { // 改动的地方,变成可传参的方法
  return {
    mounted (el, binding) {
      const app = createApp(Comp)  // 传入变动参数
      const instance = app.mount(document.createElement('div'))
      const name = Comp.name
      if (!el[name]) {
        el[name] = {}
      }
      // 把实例挂载到dom的name下,防止多个自定义指令互相影响干扰出现bug
      el[name].instance = instance
      const title = binding.arg
      if (title) {
        instance.setTitle(title)
      }

      if (binding.value) {
        append(el)
      }
    },
    updated (el, binding) {
      const title = binding.arg
      const name = Comp.name
      if (title) {
        el[name].instance.setTitle(title)
      }
      if (binding.value !== binding.oldValue) {
        binding.value ? append(el) : remove(el)
      }
    }
  }

  function append (el) {
    const style = getComputedStyle(el)
    const name = Comp.name
    if (!['absolute', 'fixed', 'relative'].includes(style.position)) {
      addClass(el, relativeCls)
    }
    el.appendChild(el[name].instance.$el)
  }

  function remove (el) {
    const name = Comp.name
    removeClass(el, relativeCls)
    el.removeChild(el[name].instance.$el)
  }
}

2、directive.js修改

import Loading from './loading.vue'
import createMyLikeDirective from '@/assets/js/create-my-like-directive'
// 如果有不同的自定义好的vue文件,Loading变为别的vue文件即可
const loadingDirective = createMyLikeDirective(Loading)

export default loadingDirective

 3、main.js修改

// 引入loading
import loadingDirective from './components/loading/directive'

// 引入其他的
import AAAA from './components/AAAA/directive'
import BBBB from './components/BBBB/directive'


let app = createApp(App)

app.use(ElementPlus).use(router)
app.directive('loading', loadingDirective) // 全局注册
app.directive('aaaa', AAAA) // 全局注册
app.directive('bbbb', BBBB) // 全局注册
app.mount('#app')

你可能感兴趣的:(学习,vue.js,javascript)