Vue 服务式Loading组件

components 下 loading 下 Loading.vue

<template>
  <transition name="fade">
    <div class="loading_container" v-show="visible">
      <div class="loading_wrapper">
        <div class="sk-folding-cube">
          <div class="sk-cube1 sk-cube"></div>
          <div class="sk-cube2 sk-cube"></div>
          <div class="sk-cube4 sk-cube"></div>
          <div class="sk-cube3 sk-cube"></div>
        </div>
        <div class="loading_title">{{ title }}</div>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  name: 'Loading',
  data() {
    return {
      visible: false
    }
  },
  props: {
    title: {
      type: String,
      default: 'loading'
    }
  },
  watch: {
    visible(val) {
      document.body.style.overflow = val ? 'hidden' : null
    }
  }
}
</script>

<style scoped lang="scss">
.fade-enter,
.fade-leave-to {
  opacity: 0;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity .6s ease;
}

@keyframes sk-foldCubeAngle {
  0%, 10% {
    transform: perspective(140px) rotateX(-180deg);
    opacity: 0;
  }
  25%, 75% {
    transform: perspective(140px) rotateX(0deg);
    opacity: 1;
  }
  90%, 100% {
    transform: perspective(140px) rotateY(180deg);
    opacity: 0;
  }
}

.loading_container {
  position: fixed;
  z-index: 1000;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;

  .loading_wrapper {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 120px;
    height: 120px;
    background-color: rgba(0, 0, 0, .8);
    border-radius: 6px;
  }

  .loading_title {
    overflow: hidden;
    width: 100%;
    box-sizing: border-box;
    padding: 0 10px;
    font-size: 14px;
    line-height: 2em;
    color: #fff;
    text-align: center;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  .sk-folding-cube {
    width: 24%;
    height: 24%;
    margin: 16px 0;
    position: relative;
    transform: rotateZ(45deg);

    .sk-cube {
      float: left;
      width: 50%;
      height: 50%;
      position: relative;
      transform: scale(1.1);

      &:before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        animation: sk-foldCubeAngle 2.4s infinite linear both;
        transform-origin: 100% 100%;
        background-color: #fff;
      }
    }

    .sk-cube2 {
      transform: scale(1.1) rotateZ(90deg);

      &:before {
        animation-delay: .3s;
      }
    }

    .sk-cube3 {
      transform: scale(1.1) rotateZ(180deg);

      &:before {
        animation-delay: .6s;
      }
    }

    .sk-cube4 {
      transform: scale(1.1) rotateZ(270deg);

      &:before {
        animation-delay: .9s;
      }
    }
  }
}
</style>

components 下 loading 下 index.js

import LoadingComponent from './Loading'

let loadingInstance = null // 单例

const Loading = {
  install(Vue) {
    Vue.prototype.$loading = {
      show(title = 'loading') {
        if (!loadingInstance) {
          const LoadingConstructor = Vue.extend(LoadingComponent)
          loadingInstance = new LoadingConstructor({
            props: {
              title: {
                type: String,
                default: title
              }
            }
          }).$mount() // 调用$mount 得到真实dom
          document.body.appendChild(loadingInstance.$el)
        }
        if (!loadingInstance.visible) loadingInstance.visible = true
      },

      hide() {
        if (loadingInstance?.visible) loadingInstance.visible = false
      }
    }
  }
}

export default Loading

main.js

impotarnt Loading form './components/loading'

Vue.use(Loading)

demo

// 组件中
showLoading() {
  this.$loading.show('加载中...')
  setTimeout(() => {
    this.$loading.hide()
  }, 2000)
}
posted @ 2020-12-14 10:42  demo_you  阅读(327)  评论(0编辑  收藏  举报