vue3实现一个自定义loading方法和指令

311 阅读1分钟

vue3实现一个自定义loading

组件实现

import { h, ref, render, createApp, nextTick } from 'vue'

/* loading svg动画 */
const loadingSvg = <svg xmlns="http://www.w3.org/2000/svg" width="60px" height="60px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-ellipsis">
  <circle cx="84" cy="50" r="0" fill="#cbe86b">
    <animate attributeName="r" values="11;0;0;0;0" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
    <animate attributeName="cx" values="84;84;84;84;84" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
  </circle>
  <circle cx="40.0957" cy="50" r="11" fill="#1c140d">
    <animate attributeName="r" values="0;11;11;11;0" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="-0.5s"/>
    <animate attributeName="cx" values="16;16;50;84;84" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="-0.5s"/>
  </circle>
  <circle cx="16" cy="50" r="7.79567" fill="#f2e9e1">
    <animate attributeName="r" values="0;11;11;11;0" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="-0.25s"/>
    <animate attributeName="cx" values="16;16;50;84;84" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="-0.25s"/>
  </circle>
  <circle cx="84" cy="50" r="3.20433" fill="#600473">
    <animate attributeName="r" values="0;11;11;11;0" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
    <animate attributeName="cx" values="16;16;50;84;84" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
  </circle>
  <circle cx="74.0957" cy="50" r="11" fill="#30BCED">
    <animate attributeName="r" values="0;0;11;11;11" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
    <animate attributeName="cx" values="16;16;16;50;84" keyTimes="0;0.25;0.5;0.75;1" keySplines="0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1" calcMode="spline" dur="1s" repeatCount="indefinite" begin="0s"/>
  </circle>
</svg>

/* loading组件封装 */
const renderLoading = {
  /* 这里可以自定义一些传进来的参数,我这里没有写,
  需要可以自己修改一下,在组件中接受一下传进来的参数 */
  props: {
    background: String,
    text: String
  },
  setup (props) {
    return () => {
      return (
        <div class="dwloadingmain absolute top-0 left-0 wh-full flex-col flex-center">
          <loadingSvg />
        </div>
      )
    }
  }
}

/* 创建loading函数 */
const createInstance = async (trigger, binding) => {
  const { value, oldValue } = binding
  if (oldValue !== value) {
    if (value && !oldValue) {
      const vnode = h(renderLoading, { background: '#000', text: '加载中' })
      const app = createApp(vnode)
      const loadingEl = app.mount(document.createElement('div')).$el
      loadingEl.setAttribute('id', 'dwLoadingId')
      trigger.style.position = 'relative'
      trigger.appendChild(loadingEl)
      nextTick(() => {
        const triggerH = trigger.offsetHeight
        if (triggerH < 200) {
          trigger.classList.add('!h-320px')
        }
      })
    } else {
      const childDiv = trigger.querySelector('#dwLoadingId')
      trigger.removeChild(childDiv)
      trigger.classList.remove('!h-320px')
    }
  }
}

/* 导出loading指令 */
export default {
  mounted (el, binding) {
    if (binding.value) {
      createInstance(el, binding)
    }
  },
  updated (el, binding) {
    createInstance(el, binding)
  },
  unmounted (el) {

  }
}

/* 导出loading方法 */
export const DwLoading = {
  el: null,
  service ({ text, background = '#ccc' } = { }) {
    const vnode = h(<renderLoading />)
    const div = document.createElement('div')
    render(vnode, div)

    document.body.appendChild(div)
    this.el = div
    return DwLoading
  },
  close () {
    document.body.removeChild(this.el)
  }
}


样式 其它的样式使用的原子化css,自己引入就可使用,如有不懂,可以留言

.dwloadingmain {
  background: rgba($color: #f7f5f1, $alpha: 0.6);
  z-index: 9999;
}