项目目录结构
src/
├── assets/
│ └── css/
│ └── loading.css # 加载动画样式文件 (新增)
├── directives/ # 自定义指令目录 (新增)
│ └── loading.js # v-loading 指令逻辑 (新增)
├── plugins/ # 插件目录 (可选)
│ └── directives.js # 全局指令注册入口 (可选)
├── main.js # 项目入口文件
└── components/ # 组件目录
1. 样式文件 (src/assets/css/loading.css)
/* 加载层样式 */
.loading-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.7);
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
/* 加载动画 */
.loading-spinner {
width: 30px;
height: 30px;
border: 3px solid #f3f3f3;
border-radius: 50%;
border-top-color: #3498db;
animation: rotating 1s linear infinite;
}
@keyframes rotating {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
2. 指令逻辑 (src/directives/loading.js)
const toggleLoading = (el, binding) => {
if (binding.value) {
// 确保父元素有定位属性
if (window.getComputedStyle(el).position === 'static') {
el.style.position = 'relative'
}
// 添加加载层
if (!el.contains(el.loadingElement)) {
el.appendChild(el.loadingElement)
}
} else {
// 移除加载层
if (el.contains(el.loadingElement)) {
el.removeChild(el.loadingElement)
}
}
}
export default {
inserted(el, binding) {
// 创建加载层
const loadingDiv = document.createElement('div')
loadingDiv.className = 'loading-wrapper'
// 创建加载动画
const spinner = document.createElement('div')
spinner.className = 'loading-spinner'
loadingDiv.appendChild(spinner)
el.loadingElement = loadingDiv
toggleLoading(el, binding)
},
update(el, binding) {
if (binding.value !== binding.oldValue) {
toggleLoading(el, binding)
}
},
unbind(el) {
if (el.loadingElement && el.contains(el.loadingElement)) {
el.removeChild(el.loadingElement)
}
el.loadingElement = null
}
}
3. 全局注册 (src/plugins/directives.js) - 可选
import loadingDirective from '@/directives/loading'
export default {
install(Vue) {
Vue.directive('loading', loadingDirective)
}
}
4. 在入口文件注册 (src/main.js)
import Vue from 'vue'
import App from './App.vue'
import DirectivesPlugin from './plugins/directives' // 导入指令插件
import '@/assets/css/loading.css' // 导入样式
Vue.use(DirectivesPlugin) // 注册全局指令
new Vue({
render: h => h(App)
}).$mount('#app')
使用方式
在任意组件中直接使用:
<template>
<div v-loading="isLoading" class="content-box">
<!-- 你的内容 -->
</div>
</template>
<script>
export default {
data() {
return { isLoading: true }
}
}
</script>
项目结构优势说明:
1. 模块化分离:将指令逻辑、样式和注册逻辑分离
2. 可维护性:每个指令独立文件,方便后续扩展
3. 全局可用:通过入口文件注册后全项目可用
4. 样式统一管理:CSS 文件集中存放便于维护