vue 自定义指令 封装 v-loading指令

vue 自定义指令 封装 v-loading指令

**创建 工程:
H:\java_work\java_springboot\vue_study

ctrl按住不放 右键 悬着 powershell

H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day05\准备代码\05-自定义指令-指令的值

vue --version
vue create v-define-loading-cmd-demo
cd v-define-loading-cmd-demo
npm install --save axios
npm run serve

App.vue


<template>
  <div class="main">
    <div class="box" v-loading="isLoading">
      <ul>
        <li v-for="item in list" :key="item.id" class="news">
          <div class="left">
            <div class="title">{{ item.title }}</div>
            <div class="info">
              <span>{{ item.source }}</span>
              <span>{{ item.time }}</span>
            </div>
          </div>

          <div class="right">
            <img :src="item.img" alt="" />
          </div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
// 安装axios =>  yarn add axios
import axios from "axios";

// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
export default {
  data() {
    return {
      list: [],
      isLoading: true,
    };
  },
  async created() {
    // 1. 发送请求获取数据
    const res = await axios.get("http://hmajax.itheima.net/api/news");

    setTimeout(() => {
      // 2. 更新到 list 中
      this.list = res.data.data;
      this.isLoading = false;
      console.log("this.isLoading = " + this.isLoading);
    }, 2000);
  },
  directives: {
    loading: {
      inserted(el, binding) {
        console.log("binding.value = " + binding.value);
        binding.value
          ? el.classList.add("loading")
          : el.classList.remove("loading");
      },
      update(el, binding) {
        binding.value
          ? el.classList.add("loading")
          : el.classList.remove("loading");
      },
      // update(el, binding) {},
    },
  },
};
</script>

<style>
/* 伪类 - 蒙层效果 */
.loading:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: #fff url("./loading.gif") no-repeat center;
}

/* .box2 {
  width: 400px;
  height: 400px;
  border: 2px solid #000;
  position: relative;
} */

.box {
  width: 800px;
  min-height: 500px;
  border: 3px solid orange;
  border-radius: 5px;
  position: relative;
}
.news {
  display: flex;
  height: 120px;
  width: 600px;
  margin: 0 auto;
  padding: 20px 0;
  cursor: pointer;
}
.news .left {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-right: 10px;
}
.news .left .title {
  font-size: 20px;
}
.news .left .info {
  color: #999999;
}
.news .left .info span {
  margin-right: 20px;
}
.news .right {
  width: 160px;
  height: 120px;
}
.news .right img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
</style>
<think>好的,我现在需要帮助用户在Vue3中实现一个v-loading指令的示例代码。首先,我需要回顾一下Vue3的自定义指令相关知识。Vue3的自定义指令Vue2有所不同,生命周期钩子有所变化,比如从bind改为mounted,unbind改为unmounted等。 用户提供的引用中,引用[3]提到了使用自定义指令封装v-loading,但那是针对Vue2的示例。我需要调整代码以适应Vue3的语法。在Vue3中,自定义指令的注册方式也变了,使用app.directive来全局注册。 首先,我需要创建一个自定义指令,当元素绑定该指令时,显示加载状态。加载状态通常包括显示一个加载动画,比如旋转的圆圈或GIF图片。用户可能需要控制加载状态的显示与隐藏,通常通过一个布尔值来控制,比如v-loading="isLoading"。 接下来,我需要考虑指令的参数和生命周期。在Vue3中,指令的生命周期钩子包括mounted、updated、unmounted等。当绑定的值变化时,updated钩子会被触发,这里需要处理加载状态的显示或隐藏。 然后,我需要处理加载动画的DOM结构。当指令绑定到元素时,应该在目标元素上添加一个遮罩层,并显示加载动画。当加载完成时,移除这个遮罩层。需要注意的是,遮罩层需要覆盖整个元素,可能需要设置position为relative或absolute,并调整样式。 另外,用户可能需要自定义加载提示的文字或样式,所以指令可以支持参数,比如v-loading:loading-text="'加载中...'"。但根据用户的问题,可能只需要基本的实现,所以先处理核心功能。 在代码实现上,首先在main.js或者单独的指令文件中定义指令。全局注册的话,可以在main.js中使用app.directive。指令定义对象中,mounted和updated钩子用来处理初始化和更新时的逻辑。在钩子函数中,通过binding.value获取当前的值,判断是否需要显示加载状态。 对于样式部分,需要动态添加或移除包含加载动画的DOM元素。例如,当加载时,创建一个div元素作为遮罩层,并插入到目标元素内部。当加载结束时,移除这个div。需要注意的是,目标元素需要设置position: relative,以便遮罩层相对于其定位。 可能还需要处理多个加载状态同时存在的情况,但基础示例可能不需要考虑这些。此外,加载动画的样式可以通过CSS类来实现,例如使用旋转的圆圈或者GIF图片作为背景。 最后,测试指令是否正常工作,确保当绑定的值变化时,加载状态正确显示和隐藏。同时,确保样式正确应用,不影响原有布局。 总结步骤: 1. 创建自定义指令v-loading。 2. 在mounted和updated钩子中处理加载状态的显示与隐藏。 3. 动态插入或移除遮罩层元素。 4. 定义加载动画的CSS样式。 5. 在组件中使用指令,通过布尔值控制加载状态。 可能遇到的问题包括样式覆盖、定位问题以及指令更新时的性能问题。需要确保每次更新时正确清理之前的元素,避免内存泄漏。此外,考虑到Vue3的响应式系统,确保指令能够正确响应绑定的值的变化。</think>在Vue3中实现v-loading指令可通过自定义指令结合动态DOM操作实现,以下是分步实现方案: ### 一、基础指令实现 ```javascript // main.js import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.directive('loading', { mounted(el, binding) { const loadingOverlay = document.createElement('div') loadingOverlay.className = 'loading-overlay' loadingOverlay.innerHTML = ` <div class="loading-spinner"></div> ${binding.arg ? `<div class="loading-text">${binding.arg}</div>` : ''} ` el.style.position = 'relative' el.loadingElement = loadingOverlay if (binding.value) { el.appendChild(loadingOverlay) } }, updated(el, binding) { if (binding.value !== binding.oldValue) { if (binding.value) { el.appendChild(el.loadingElement) } else { el.contains(el.loadingElement) && el.removeChild(el.loadingElement) } } } }) app.mount('#app') ``` ### 二、添加CSS样式 ```css /* 全局样式 */ .loading-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); display: flex; justify-content: center; align-items: center; flex-direction: column; } .loading-spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .loading-text { margin-top: 10px; color: #666; } ``` ### 三、组件中使用示例 ```vue <template> <div v-loading="isLoading" :style="{ height: '300px' }"> <!-- 内容区域 --> <button @click="loadData">加载数据</button> </div> </template> <script setup> import { ref } from 'vue' const isLoading = ref(false) const loadData = () => { isLoading.value = true setTimeout(() => { isLoading.value = false }, 2000) } </script> ``` ### 四、高级功能扩展 1. **自定义提示文本**: ```vue <div v-loading:[loadingText]="isLoading"></div> <script setup> const loadingText = '数据加载中...' </script> ``` 2. **自定义颜色**: ```javascript app.directive('loading', { mounted(el, binding) { // ... if (binding.modifiers.blue) { loadingOverlay.style.background = 'rgba(225, 240, 255, 0.9)' } } }) ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值