記錄--Vue自定義指令實現載入中效果v-load(不使用Vue.extend)

来源:https://www.cnblogs.com/smileZAZ/archive/2023/03/09/17199475.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 網站效果演示:ashuai.work:8888/#/myLoad GitHub倉庫地址代碼:github.com/shuirongshu… 載入中思路分析 實現載入中效果,一般有兩種方式: 第一種是:搞一個load組件,然後使用Vue.e ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

Vue自定義指令實現載入中效果v-load(不使用Vue.extend)

網站效果演示:ashuai.work:8888/#/myLoad

GitHub倉庫地址代碼:github.com/shuirongshu…

載入中思路分析

實現載入中效果,一般有兩種方式:

  • 第一種是:搞一個load組件,然後使用Vue.extend()方法去繼承一個載入組件去使用,比如筆者的這篇文章:juejin.cn/post/702172…
  • 第二種是:直接使用指令去在需要載入的dom上去創建一個載入中的dom元素,並指定相應的樣式即可。本篇文章說的是第二種。

我們先看一下效果圖

v-load效果圖

v-load.gif

實現步驟一:加上自定義指令

假設我有一個dom元素,我給其加上一個自定義的指令v-load="loading",綁定一個具體的布爾值loading,用於控制開啟載入中和關閉載入中

<div class="box" v-load="loading">111</div>

loading: true

.box {
  width: 160px;
  height: 80px;
  border: 2px solid #666;
}

接下來,我就要在自定義指令的相關鉤子函數中去操作這個dom元素。

關於自定義指令的入門基礎知識可以看官方文檔,或者參見筆者之前的關於自定義指令的文章:juejin.cn/post/702960…

實現步驟二:給目標元素創建一個子元素dom用於載入

在自定義指令的初始化bind鉤子函數中,我們可以拿到這個dom元素,首先給這個目標元素開始相對定位,讓用於載入中的子元素dom去絕對定位,以這個相對定位的父元素進行參考

bind(el, binding) {
    const target = el;
    // 父元素相對定位
    target.style.position = "relative";
    // 子元素遮罩層部分
    let loadChild = document.createElement("div");
    loadChild.className = "loadClass";
}

上述代碼中給載入中的子元素loadChild指定一個樣式類名loadClass

在這裡小伙伴可能有疑問了,這個自定義指令的樣式怎麼寫呢?自定義指令中也沒有style標簽啊?

是的,自定義指令中不能直接寫樣式,不過沒關係,我們可以先寫好一個css樣式,然後引入過來使用啊,如下:

// 引入拆分的樣式,便於自定義指令中使用
import './index.css'

bind(el, binding) {
    ......
    loadChild.className = "loadClass";
}

這樣的話,className的樣式,可以在引入的同級目錄下的./index.css文件中設置了,loadClass樣式如下:

.loadClass {
    /* 寬高百分百 */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    /* 預設背景色和顏色 */
    background-color: rgba(255, 255, 255, 0.99);
    color: #0b6ed0;
    /* 透明度過渡使用搭配display:none; */
    opacity: 0.8;
    transition: all 0.3s;
    /* 居中 */ 
    display: flex;
    align-items: center;
    justify-content: center;
}

註意,載入中效果開啟和消失,不用使用vue自帶的過渡組件transition,咱們可以使用透明度搭配搭配display:none;去設置

註意,載入中要以父元素為邊界去控制,可不能滿屏載入哦

然後初始化的時候,看看v-load綁定的值是true還是false,同時加上一個用於隱藏的類名:load-hide。再把這個載入中的dom元素追加到目標父元素身上。

loadChild.classList.add('load-hide') // 添加類名
target.appendChild(loadChild); // 追加載入中子元素

/* 通過透明度實現過渡動畫 */
.load-hide {
    opacity: 0;
}

這樣的話,初始化的載入中就做好了。v-load綁定的值是false的時,就隱藏之

實現步驟三:當組件更新時,去添加或移除這個load-hide類名

componentUpdated(el, binding, vnode, oldVnode) {
        let flag = binding.value
        let loadChild = el.querySelector('.loadClass')
        if (flag) { // v-load綁定的值為true,就移除這個類名,就能看到了
            loadChild.style.display = 'flex'
            setTimeout(() => {
                loadChild.classList.remove('load-hide')
            }, 0);
        } else { // 綁定的值為false時,再添加這個類名,同時隱藏dom
            loadChild.classList.add('load-hide')
            setTimeout(() => {
                loadChild.style.display = 'none'
            }, 360);

        }
    },

註意上述代碼中為啥不直接隱藏,而是使用定時器延長360毫秒再去隱藏,因為筆者設置的載入dom的過渡時間是0.3秒,即要等到透明度過渡完了以後,再隱藏載入中dom,這樣看著就自然一些了。

.loadClass { transition: all 0.3s; }

到這裡,咱們的v-load自定義指令的載入中效果,就初步完成了。不過功能有點少,自定義載入中我還想,去動態控制:

  • 自定義載入圖標名
  • 自定義載入文字
  • 自定義載入文字顏色
  • 自定義載入背景色

那這樣怎麼辦呢?

實現步驟四:優化自定義指令,支持傳入更多的參數

此時,我的v-load自定義指令,就不用綁定一個布爾值了。可以考慮綁定一個對象啊,通過控制這個對象的具體值,來動態控制載入中的效果。

  • 原來自定義指令綁定:v-load = loading // typeof loading == 'boolean'
  • 現在自定義指令綁定:v-load = loading2 // typeof loading2 == 'object'
<div class="box" v-load="loading2">222</div>

// 如果想要有更多的配置項,就傳一個對象,註意要指定欄位
loading2: {
    value: true,
    icon: "el-icon-eleme", // 自定義載入圖標名
    text: "客官稍等哦...", // 自定義載入文字
    color: "red", // 自定義載入文字顏色
    bgColor: "#baf", // 自定義載入背景色
}

傳參指定相應欄位,自定義指令中接參,就要在相關的鉤子中去接收並處理這些參數。

如何處理這些參數?

  • v-load綁定的值的類型的判斷,是布爾值,還是對象,執行不同的操作
  • 使用原生js的方式去,創造dom元素、給dom元素指定類名(或添加刪除類名)
  • 考慮到性能緣故,可以使用文檔碎片優化document.createDocumentFragment()
  • 最後丟入遮罩層dom內部即可

完整代碼

自定義指令樣式文件index.css

.loadClass {
    /* 寬高百分百 */
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    /* 預設背景色和顏色 */
    background-color: rgba(255, 255, 255, 0.99);
    color: #0b6ed0;
    /* 透明度過渡使用搭配display:none; */
    opacity: 0.8;
    transition: all 0.3s;
    /* 禁止文字選擇 */
    user-select: none;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* 通過透明度實現過渡動畫 */
.load-hide {
    opacity: 0;
}

.loadClass>i {
    margin-right: 4px;
}

自定義指令的js文件index.js

註意,自定義指令還需要註冊一下才能使用哦

// 引入拆分的樣式,便於自定義指令中使用
import './index.css'
export default {
    // 初始化綁定dom鉤子函數
    bind(el, binding) {
        const target = el;
        // 傳參類型判斷變數控制
        let flag;
        let isObj;
        if (typeof binding.value == 'boolean') {
            flag = binding.value
            isObj = false
        }
        if (typeof binding.value == 'object') {
            flag = binding.value.value
            isObj = true
        }
        // 有dom元素才去做操作
        if (target) {
            // 父元素相對定位
            target.style.position = "relative";
            // 子元素遮罩層部分
            let loadChild = document.createElement("div");
            loadChild.className = "loadClass";

            // 創建文檔碎片性能稍微優化一點點
            let fragment = document.createDocumentFragment()
            // 孫子元素1載入圖標部分
            let iSun = document.createElement("i");
            iSun.className = isObj ? binding.value.icon : "el-icon-loading";
            // 孫子元素2文字提示部分
            let spanSun = document.createElement("span");
            spanSun.innerHTML = isObj ? binding.value.text : '載入中...'
            // 使用文檔碎片將iSun和spanSun裝起來
            fragment.appendChild(iSun);
            fragment.appendChild(spanSun);
            // 將文檔碎片丟入子元素遮罩層內
            loadChild.appendChild(fragment);
            // 樣式判斷設置
            if (isObj) {
                loadChild.style.color = binding.value.color
                loadChild.style.backgroundColor = binding.value.bgColor
            }
            // 若為false,就隱藏
            if (!flag) {
                loadChild.classList.add('load-hide')
                loadChild.style.display = 'none'
            }

            // 父元素添加子元素遮罩層使用
            target.appendChild(loadChild);
        }
    },
    // dom組件更新操作控制顯示和隱藏
    componentUpdated(el, binding, vnode, oldVnode) {
        let flag = typeof binding.value == 'boolean' ? binding.value : binding.value.value
        let loadChild = el.querySelector('.loadClass')
        if (flag) {
            loadChild.style.display = 'flex'
            setTimeout(() => {
                loadChild.classList.remove('load-hide')
            }, 0);
        } else {
            loadChild.classList.add('load-hide')
            setTimeout(() => {
                loadChild.style.display = 'none'
            }, 360);

        }
    },
}

使用自定義load指令的地方

<template>
  <div>
    <h3>指令方式載入中...</h3>
    <br />
    <button @click="loadFn">點一下</button>
    <br />
    <br />
    <el-table v-load="loading" border :data="tableData" style="width: 80%">
      <el-table-column prop="name" label="姓名"></el-table-column>
      <el-table-column prop="age" label="年齡"></el-table-column>
      <el-table-column prop="home" label="家鄉"></el-table-column>
      <el-table-column prop="like" label="愛好"></el-table-column>
    </el-table>
    <br />
    <div class="box" v-load="loading">111</div>
    <br />
    <div class="box" v-load="loading2">222</div>
  </div>
</template>

<script>
export default {
  name: "myLoadName",
  data() {
    return {
      // 自定義指令方式,預設綁定的值是布爾值
      loading: true,
      // 如果想要有更多的配置項,就傳一個對象,註意要指定欄位
      loading2: {
        value: true,
        icon: "el-icon-eleme", // 自定義載入圖標名
        text: "客官稍等哦...", // 自定義載入文字
        color: "red", // 自定義載入文字顏色
        bgColor: "#baf", // 自定義載入背景色
      },
      tableData: [
        {
          name: "孫悟空",
          age: 500,
          home: "花果山水簾洞",
          like: "桃子",
        },
        {
          name: "豬八戒",
          age: 88,
          home: "高老莊",
          like: "肉包子",
        },
        {
          name: "沙和尚",
          age: 1000,
          home: "通天河",
          like: "游泳",
        },
      ],
    };
  },
  methods: {
    loadFn() {
      this.loading = !this.loading;
      this.loading2.value = !this.loading2.value;
    },
  },
};
</script>

<style lang='less' scoped>
.box {
  width: 160px;
  height: 80px;
  border: 2px solid #666;
  box-sizing: border-box;
}
</style>

本文轉載於:

https://juejin.cn/post/7182375025368891429

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1 mysql邏輯架構 mysql邏輯架構圖: Mysql伺服器、存儲引擎 是兩個獨立的組件,彼此通過api交互 第一層:連接處理、授權認證、安全管理 第二層:核心服務功能 查詢解析、分析、優化、緩存以及所有的內置函數(日期、時間、數學、加密函數等) 跨存儲引擎的功能:存儲過程、觸發器、視圖等。 第 ...
  • 數據治理是推動大型集團企業轉型升級、提升競爭優勢、實現高質量發展的重要引擎。通過全鏈數據結構化,實現業務對象、業務規則、業務流程數字化,推進全鏈業務深度數字化,夯實數據運營底座。 廈門國貿集團股份有限公司(簡稱“國貿股份”)是國有控股上市公司,同時也是首批全國供應鏈創新與應用示範企業,在“十四五”規 ...
  • 摘要:其實游戲客戶對資料庫的訴求是很明確的,資料庫應當“放心存放心用”。 本文分享自華為雲社區《華為雲GaussDB(for Redis)揭秘第27期:聊聊游戲業務怎麼用高斯Redis》,作者:高斯Redis官方博客。 華為雲資料庫團隊是比較重視技術洞察的,對客戶真實的業務場景也比較看重。年初出差了 ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 花家舍 文章來源:GreatSQL社區原創 前文回顧 實現一個簡單的Database系列 譯註:cstack在github維護了一個簡單的、類似 ...
  • 生活中存在同時使用兩個微信的情況,一個工作一個生活,這時希望同時在電腦上登錄兩個賬號。如何做到呢?步驟如下: 右鍵單擊“微信”圖標,選擇屬性,目標框內的路徑就是微信安裝路徑,複製目標框里的內容。 將如下命令複製到 TXT 文件保存,再將該文件重命名,主要是將尾碼名改成“.bat”文件。 @echo ...
  • 好家伙,本篇為做題思考 書接上文 題目如下: 1.請給出下列代碼的輸出結果,並配合"消息隊列"寫出相關解釋 async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } ...
  • 一般來說,項目由子模塊組成,拿到後端提供過來的介面,一般也是按照子模塊來分類提供的.請教一下各位,你們前端項目是如何管理api的? 希望各位貼點你們的優秀代碼段上來學習學習. 常見: 各個模塊的api存放到單獨的js文件里,返回一個請求實例promise對象 使用的時候根據需求引入相應的請求方法 / ...
  • 其他章節請看: webgl 系列 變換矩陣和動畫 動畫就是不停地將某個東西變換(transform)。例如將三角形不停地旋轉就是一個動畫 和 CSS transform 類似,變換有三種形式:平移、縮放和旋轉。 簡單的變換用普通表達式容易實現,如果事情複雜,比如旋轉後平移,這時就可以使用變換矩陣。 ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...