vue3通用型类似loading自定义指令

448 阅读1分钟

//create-loading-like-directive.js

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

const relativeCls = 'g-relative'
//g-relative为样式,即position:relative

export default function createLoadingLikeDirective(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] = {}
      }
      el[name].instance = instance
      const title = binding.arg
      if (typeof title !== 'undefined') {
        instance.setTitle(title)
      }
      if (binding.value) {
        append(el)
      }
    },
    updated (el, binding) {
      const title = binding.arg
      const name = Comp.name
      if (typeof title !== 'undefined') {
        el[name].instance.setTitle(title)
      }
      if (binding.value !== binding.oldValue) {
        binding.value ? append(el) : remove(el)
      }
    }
  }
  function append(el) {
    const name = Comp.name
    const style = getComputedStyle(el)
    if (['absolute', 'fixeed', 'relative'].indexOf(style.position) === -1) {
      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)
  }
}

//loading.vue

<template>
  <div class="loading">
    <div class="loading-content">
      <img src="./loading.gif" width="24"  height="24">
      <p class="desc">
        {{title}}
      </p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'loading',
  data () {
    return {
      title: '正在载入...'
    }
  },
  methods: {
    setTitle(title) {
      this.title = title
    }
  }
}
</script>

<style scoped lang="scss">
  .loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    .loading-content {
      text-align: center;
      .desc {
        line-height: 20px;
        font-size: $font-size-small;
        color: $color-text-l;
      }
    }
  }
</style>

//directive.js

import Loading from './loading'
import createLoadingLikeDirective from '@/assets/js/create-loading-like-directive'

const loadingDirective = createLoadingLikeDirective(Loading)

export default loadingDirective

注意,要在全局注册才行

import loadingDirective from '@/components/base/loading/directive.js'

createApp(App).use(store).use(router).use(lazyPlugin, {
  loading: require('@/assets/images/default.png')
}).directive('loading', loadingDirective).mount('#app')

//使用方式 支持自定义文案

    <scroll
    class="list"
    :style="scrollStyle"
    v-loading="loading"
    v-no-result:[noResultText]="noResult"
    >
    </scroll>

遇到类似的,比如暂无图片的提示就可以复用create-loading-like-directive.js,直接像loading那样创建使用即可。 最后加载图片在这里

loading.gif