插件
在Vue项目中,插件通常用来为 Vue 添加全局功能,我们通常会通过全局方法Vue.use()
使用插件。插件相关概念及开发规范可以参考文档。
这里主要记录如何实现一个全局loading插件,以此可以熟悉Vue中开发插件的详细过程。
实现
在项目目录src/components
下新建VLoading
文件夹,文件目录结构如下
├─VLoading
│ │ index.js
│ │
│ └─src
│ loading.vue
│ main.js
- 模板文件
VLoading/src/loading.vue
查看代码
vue
<template>
<transition name="loading-fade">
<div v-show="visible" class="v-loading">
<div class="mask" />
<!-- loading bubble -->
<div v-if="options.bubble" class="loading-bubble-wrapper">
<div class="loading-bubble" />
</div>
<!-- 默认loading方式 -->
<div v-else class="loading-content">
<!-- loading.svg为需要引用的loading图案,可自行替换 -->
<img class="loading-icon" src="./loading.svg">
<p
v-show="options.text !== ''"
class="loading-text"
:style="{ 'color': options.color }"
>
{{ options.text }}
</p>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'JiuLoading',
data() {
return {
visible: false,
options: {
color: '', // loading文字颜色
text: '',
bubble: false // 是否切换loading类型为bubble
}
}
}
}
</script>
<style lang="scss" scoped>
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
width: 100%;
min-height: 100vh;
background: rgba(0, 0, 0, 0.4);
}
.v-loading {
.loading-content {
width: 1.2rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
.loading-icon {
width: 100%;
height: 1.2rem;
animation-name: loading;
animation-duration: 1s;
animation-timing-function: linear;
animation-delay: 0;
animation-iteration-count: infinite;
}
.loading-text {
width: 100%;
text-align: center;
height: 1.2rem;
line-height: 1.2rem;
font-size: 0.3rem;
font-weight: 500;
}
}
}
@keyframes loading {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
.loading-fade-enter-active,
.loading-fade-leave-active {
transition: opacity 0.6s ease-in-out;
}
.loading-fade-enter,
.loading-fade-leave-to {
opacity: 0;
}
/* loading bubble */
.loading-bubble-wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
}
.loading-bubble {
width: 1.5rem;
height: 0.5rem;
position: relative;
}
.loading-bubble::before,
.loading-bubble::after {
content: '';
display: block;
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
position: absolute;
transform: translate3d(0, 0, 0);
}
.loading-bubble::before {
animation: loading-bubbleL 2s ease-in-out infinite;
background: #ee6362;
}
.loading-bubble::after {
animation: loading-bubbleR 2s ease-in-out infinite;
background: #2cb0b2;
}
@keyframes loading-bubbleL {
0% {
left: 0;
transform: scale(1.1);
}
50% {
left: calc(100% - 0.5rem);
transform: scale(1);
}
100% {
left: 0;
transform: scale(1.1)
}
}
@keyframes loading-bubbleR {
0% {
left: calc(100% - 0.5rem);
transform: scale(1.1);
}
50% {
left: 0;
transform: scale(1);
}
100% {
left: calc(100% - 0.5rem);
transform: scale(1.1)
}
}
</style>
VLoading/src/main.js
js
import Vue from 'vue'
import Loading from './loading.vue'
// 创建构造函数
const LoadingConstructor = Vue.extend(Loading)
// 插件默认配置
const defaultOpt = {
text: '',
color: '',
zIndex: 100
}
// 绑定原型方法--关闭
LoadingConstructor.prototype.close = function() {
// 异步销毁
setTimeout(() => {
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el)
}
// 销毁loading实例
this.$destroy()
}, 600)
this.visible = false
document.body.style.overflow = ''
}
// 核心方法
const loading = (options = {}) => {
if (Vue.prototype.$isServer) return
// 合并配置
options = Object.assign({}, defaultOpt, options)
// 创建实例
const instance = new LoadingConstructor(options)
// 挂载dom元素
const vm = instance.$mount()
document.body.appendChild(vm.$el)
document.body.style.overflow = 'hidden'
// 确保dom完全更新后显示组件
Vue.nextTick(() => {
instance.visible = true
instance.options = options
const maskEle = vm.$el.firstElementChild
maskEle.style.zIndex = options.zIndex
})
// 返回实例,可在创建loading后调用instance.close关闭loading
return instance
}
export default loading
VLoading/index.js
js
import loading from './src/main'
// 暴露对象,提供install方法
export default {
install(Vue) {
Vue.prototype.$loading = loading
}
}
- 注册插件
src/main.js
js
import VLoading from '@/components/VLoading'
Vue.use(VLoading)
new Vue({
// ...
})
- 项目中使用
js
// 创建
const loading = this.$loading({
bubble: true
})
// you can do something...
// 关闭
loading.close()