【v-loading】vue3自定义指令v-loading的封装,预制菜可直接食用

loading样式更改在createLoadingVNode ()函数更改
欢迎拍砖讨论

import './index.less'

import { App, Directive, DirectiveBinding, h, render, VNode } from 'vue'

interface OptionType {
  show?: object
  text?: string
  icon?: string
}

interface LoadingHTMLElement extends HTMLElement {
  __loadingElement?: HTMLElement | undefined
}

// 创建loading vNode 根据自己的需求更改这里
const createLoadingVNode = ({
  text = 'Loading...',
  icon = 'vxe-icon-spinner roll vxe-loading--default-icon'
}: OptionType = {}): VNode => {
  return h('div', { class: 'loading--chunk' }, [
    h('i', { class: icon }),
    h('div', { class: 'loading--text' }, `${text}`)
  ])
}

// 挂载/卸载
const setLoading = (el: LoadingHTMLElement, binding: DirectiveBinding<boolean | OptionType>) => {
  const show: boolean = typeof binding.value === 'boolean' ? binding.value : !!binding.value.show
  const option: OptionType = typeof binding.value === 'object' ? binding.value : {}

  if (!show) {
    removeLoading(el)
    return
  }

  const loadingVNode = createLoadingVNode(option)
  const loadingElement = document.createElement('div')
  loadingElement.className = 'loading is--visible'

  //没有使用 render直接挂载在el上,是预防卸载时需要删除_vnode影响到其他的挂载,不删除 再次使用render(loadingVNode, el)时_vnode没有变化会不渲染
  render(loadingVNode, loadingElement)
  el.appendChild(loadingElement)
  el.__loadingElement = loadingElement
}

// 在指令解绑时移除 loading 元素
const removeLoading = (el: LoadingHTMLElement) => {
  const loadingElement = el.__loadingElement

  if (loadingElement && el.contains(loadingElement)) {
    el.removeChild(loadingElement)
  }

  delete el.__loadingElement
}

// 自定义指令
const loadingDirective: Directive = {
  mounted(el: LoadingHTMLElement, binding: DirectiveBinding<boolean | OptionType>) {
    setLoading(el, binding)
  },
  updated(el: LoadingHTMLElement, binding: DirectiveBinding<boolean | OptionType>) {
    setLoading(el, binding)
  },
  beforeUnmount(el: LoadingHTMLElement) {
    removeLoading(el)
  },
  deep: true
}

export function setupLoadingDirective(app: App) {
  app.directive('loading', loadingDirective)
}

export default loadingDirective


index.css

.loading {
  display: none;
  position: absolute;
  width: 100%;
  min-height: 200px;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 99;
  user-select: none;
  background-color: rgba(255, 255, 255, 0.9);
  &.is--visible {
    display: block;
  }
  & > .loading--chunk,
  & > .loading--warpper {
    width: 100%;
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    text-align: center;
    color: #409eff;
  }
  .loading--default-icon {
    font-size: 1.4em;
  }
  .loading--text {
    padding: 0.4em 0;
  }
  .loading--spinner {
    display: inline-block;
    position: relative;
    width: 56px;
    height: 56px;
    &:before,
    &:after {
      content: '';
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background-color: #409eff;
      opacity: 0.6;
      position: absolute;
      top: 0;
      left: 0;
      animation: bounce 2s infinite ease-in-out;
    }
    &:after {
      animation-delay: -1s;
    }
  }
  @keyframes bounce {
    0%,
    100% {
      transform: scale(0);
    }
    50% {
      transform: scale(1);
    }
  }
}

.size--mini {
  .loading {
    .loading--spinner {
      width: 38px;
      height: 38px;
    }
  }
}
.size--small {
  .loading {
    .loading--spinner {
      width: 44px;
      height: 44px;
    }
  }
}
.size--medium {
  .loading {
    .loading--spinner {
      width: 50px;
      height: 50px;
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值