最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3.0中一些好用的指令封裝總結(jié)

 更新時(shí)間:2026年04月01日 09:29:03   作者:嘗嘗你的優(yōu)樂美  
Vue指令是Vue.js框架的核心特性之一,通過在HTML標(biāo)簽上添加以v-為前綴的特殊屬性,開發(fā)者可以聲明式地將數(shù)據(jù)綁定到DOM、實(shí)現(xiàn)條件渲染、循環(huán)渲染等復(fù)雜交互邏輯,這篇文章主要介紹了Vue3.0中一些好用的指令封裝的相關(guān)資料,需要的朋友可以參考下

一. 前言

最近在維護(hù)一個(gè)老項(xiàng)目,發(fā)現(xiàn)項(xiàng)目中用了很多的自定義指令。突然發(fā)現(xiàn),自己已經(jīng)很久沒有封裝過指令了,特別是vue3.0時(shí)代以來,這個(gè)功能我好像用的越來越少了。其實(shí)以前在2.0時(shí)代的時(shí)候,封裝指令是很常見的寫法(勾起了當(dāng)年的回憶)。那現(xiàn)在既然遇到了,就封裝一些很常見的指令在日常開發(fā)中可以用到的。

二. 使用流程

2.1. 介紹

其實(shí)關(guān)于指令的使用,vue3.0的官網(wǎng)寫的已經(jīng)很仔細(xì)了,對(duì)新手很友好這里是地址。寫法主要還是在提供在不同鉤子函數(shù)中,執(zhí)行不同操作。

下面 這些是官網(wǎng)給出的鉤子函數(shù)的執(zhí)行時(shí)機(jī)

const myDirective = {
  // 在綁定元素的 attribute 前
  // 或事件監(jiān)聽器應(yīng)用前調(diào)用
  created(el, binding, vnode) {
    // 這個(gè)created可以拿到dom、但是binding不會(huì)檢測(cè)到響應(yīng)式數(shù)據(jù)的改變
  },
  // 在元素被插入到 DOM 前調(diào)用
  beforeMount(el, binding, vnode) {},
  // 在綁定元素的父組件
  // 及他自己的所有子節(jié)點(diǎn)都掛載完成后調(diào)用
  mounted(el, binding, vnode) {},
  // 綁定元素的父組件更新前調(diào)用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在綁定元素的父組件
  // 及他自己的所有子節(jié)點(diǎn)都更新后調(diào)用
  updated(el, binding, vnode, prevVnode) {},
  // 綁定元素的父組件卸載前調(diào)用
  beforeUnmount(el, binding, vnode) {},
  // 綁定元素的父組件卸載后調(diào)用
  unmounted(el, binding, vnode) {}
}

這里要注意幾個(gè)參數(shù):

  • el: 綁定到指令的dom元素
  • binding: 一個(gè)對(duì)象,包含以下屬性。
    • value: 傳遞給指令的值。(v-directive="[1,2,3]",這里的[1,2,3]就是值)
    • oldValue:之前的值。僅在 beforeUpdate 和 updated 中可用
    • arg: 傳遞給指令的參數(shù)。(v-directive:arg="", 這個(gè)arg就是參數(shù))
    • modifiers: 指令修飾符。(v-directive.foo="" 這里的foo就是修飾符)

這里就是要區(qū)分一下argmodifiers的區(qū)別。舉個(gè)例子:

v-directive:arg.foo="1"

這里的話,value就是1、 foo就是指令修飾符, arg就是指令參數(shù)。

這里要注意點(diǎn),指令的參數(shù)也可以是動(dòng)態(tài)的:

v-directive:[arg].foo="1"

這時(shí)候指令的參數(shù)會(huì)基于組件的 arg 數(shù)據(jù)屬性響應(yīng)式地更新。

2.2. 簡(jiǎn)單實(shí)用

這里簡(jiǎn)單實(shí)現(xiàn)一個(gè)v-if,順便把directive的結(jié)構(gòu)搭建了。

新建一個(gè)directives文件夾,里面新建一個(gè)myShow.ts

import type { Directive, DirectiveBinding } from 'vue'
const myShow: Directive = {
  updated(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding
    if (value) {
      el.style.display = 'block'
    }
    else el.style.display = 'none'
  }
}
export default myShow

根據(jù)外部傳來的binding.value,來控制當(dāng)前元素的顯示與隱藏。要注意一下,這里放在update中執(zhí)行,因?yàn)樵?code>mounted中,不會(huì)檢測(cè)到binding.value值的改變。

然后在同級(jí)目錄下,新建一個(gè)index.ts

import type { App, Directive } from "vue"
import myShow from "./myShow"
interface IdirectiveList<T> {
  [key: string]: T
}
const directiveList: IdirectiveList<Directive> = {
  myShow
}
const installDirectives = {
  install(app: App<Element>) {
    for(let key in directiveList) {
      app.directive(key, directiveList[key])   // 通過app.directive注冊(cè)
    }
  }
}
export default installDirectives

最后在main.ts中把directives導(dǎo)入:

import installDirectives from './directives'
app.use(installDirectives)

三. 常見指令實(shí)現(xiàn)

實(shí)現(xiàn)之前要提一句話,組件是主要的構(gòu)建模塊,而組合式函數(shù)則側(cè)重于有狀態(tài)的邏輯。自定義指令主要是為了重用涉及普通元素的底層 DOM 訪問的邏輯。 真不愧是官網(wǎng)的原話,講的很有深意!我們使用指令的目的是為了復(fù)用dom元素的一些操作方式。所以我們的注意點(diǎn)是 dom元素?。。?/p>

3.1 圖片懶加載

圖片懶加載的實(shí)現(xiàn)流程:

  • 判斷元素是否進(jìn)入可視區(qū)域 使用IntersectionObserver觀察
  • 進(jìn)入可視區(qū)后加載圖片預(yù)定url
  • 最后移除圖片觀察器

我們簡(jiǎn)單實(shí)現(xiàn)一下:新建一個(gè)lazyImage.ts:

import loadingImage from '../assets/loading.gif'
import errorImage from '../assets/error.jpeg'
import type { Directive, DirectiveBinding } from "vue";
const lazyImage: Directive = {
  mounted(el, binding: DirectiveBinding) {
    const {src, loading = loadingImage, error = errorImage } = binding.value
    el.src = loading   // 先個(gè)一個(gè)默認(rèn)的占位圖片
    const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => {
      entries.forEach((entry: IntersectionObserverEntry) => {
        if (entry.isIntersecting) {
          imageLoading(src).then(() => {
            el.src = src
            observer.unobserve(el)   // 去除觀察
          }).catch(() => {
            el.src = error
          })
        }
      })
    }, {
      rootMargin: '50px'    //圖片 距離50px的時(shí)候開始加載
    })
    observer.observe(el)
    el.dataset.observer = observer
  },
  unmounted(el) {
    if (el.dataset.observer) {
      el.dataset.observer.unobserve(el)
    }
  }
}
const imageLoading = (src: string) => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.src = src
    img.onload = resolve
    img.onerror = reject
  })
}
export default lazyImage

代碼簡(jiǎn)單講解一下:

  • el.src = loading 剛進(jìn)入的時(shí)候給個(gè)默認(rèn)值loading。
  • IntersectionObserver 來監(jiān)控每個(gè)img圖片。當(dāng)圖片進(jìn)入可視區(qū)域(entry.isIntersecting)的時(shí)候,加載data里面的src
  • observer.observe(el) 對(duì)當(dāng)前元素開啟觀察。
  • el.dataset.observer = observer 的意思是,把當(dāng)前的觀察者observer,放到dataset屬性中。這步操作的意思是,當(dāng)圖片加載正確的url后,移除對(duì)當(dāng)前圖片的觀察。
  • 在unmounted中卸載,放在一直觀察泄漏內(nèi)存。

然后我們更新一下index.ts文件。最后在頁面上使用一下:

<div class="text">
    <img
      width="600" height="400"
      v-for="(image, index) in arr"  
      v-lazyImage="{src: image}"
      :key="index"
    />
</div>
<script setup lang="ts">
import test from './assets/test.jpeg'
const arr = [test, test, test, test, test, test, test, test]
</script>

看一下最終的效果:

3.1 圖片懶加載

3.2 按鈕權(quán)限

這個(gè)在一些后臺(tái)管理的項(xiàng)目里面用到的很多。其實(shí)原理很簡(jiǎn)單,就是根據(jù)接口返回、自定義的白名單中,來判斷你當(dāng)前按鈕的權(quán)限標(biāo)識(shí)在不在里面,如果在顯示,否則隱藏。

新建一個(gè)permission.ts文件:

import { type Directive, type DirectiveBinding } from "vue";
// 這里可以自定義或者從接口拿
const whiteBlock = ["per:page:1", "per:page:2", "per:page:3", "per:page:4"]
const permission: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    if (!binding.value) return;
    else {
      console.log(binding.value)
      // 如果在白名單內(nèi),不做處理,不在直接隱藏。
      !whiteBlock.includes(binding.value) ? el.style.display = 'none' :  el.style.display = 'auto'
    }
  }
}
export default permission

沒什么好說的,很簡(jiǎn)單。就是通過傳入的值來判斷在不在白名單之內(nèi)就可以。在頁面上使用一下:

    <el-button v-permission="'per:page:1'">per:page:1</el-button>
    <el-button v-permission="'per:page:2'">per:page:2</el-button>
    <el-button v-permission="'per:page:10'">per:page:10</el-button>
    <el-button v-permission="'per:page:3'">per:page:3</el-button>
let whiteBlock: string[] = [];
setTimeout(() => {
  whiteBlock = ["per:page:1", "per:page:2", "per:page:3", "per:page:4"]
}, 3000)

3.2 按鈕權(quán)限

沒什么問題,per:page:10不在白名單內(nèi),就不會(huì)顯示。

但是這里有個(gè)優(yōu)化點(diǎn),需要提一下。如果你的白名單數(shù)據(jù)是從接口拿的,那不能在mounted階段處理邏輯問題。因?yàn)楫惒降膯栴},會(huì)出現(xiàn)el加載完成,但是whiteBlock還沒有獲取到。

比如我們把whiteBlock的賦值變成異步的。

let whiteBlock: string[] = [];
setTimeout(() => {
  whiteBlock = ["per:page:1", "per:page:2", "per:page:3", "per:page:4"]
}, 500)

這時(shí)候頁面就會(huì)變成空白。

3.2 按鈕權(quán)限_圖2

所以,這里需要對(duì)邏輯改造一下,把whiteBlock變?yōu)轫憫?yīng)式數(shù)據(jù),然后通過watchEffect監(jiān)聽一下whiteBlock。代碼如下:

import { type Directive, type DirectiveBinding } from "vue";
import { ref, watchEffect } from "vue"
// 這里可以自定義或者從接口拿
let whiteBlock = ref<string[]>([]);
setTimeout(() => {
  whiteBlock.value = ["per:page:1", "per:page:2", "per:page:3", "per:page:4"]
}, 500)
const permission: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    watchEffect(() => {
      if (whiteBlock.value.length === 0 || !binding.value) return
      !whiteBlock.value.includes(binding.value) ? el.style.display = 'none' :  el.style.display = 'auto'
    })
  }
}
export default permission

ok! 最后要注意一下,whiteBlock的獲取一般都放在登陸的時(shí)候和用戶信息一起返回,不然的話會(huì)出現(xiàn),按鈕閃爍消失的問題。

3.3 元素的拖拽

這個(gè)其實(shí)已經(jīng)有很好用的庫(kù)了,但是不妨礙我們?cè)趯?shí)現(xiàn)一下。新建一個(gè)drag.ts文件:

import type { Directive } from "vue";
const drag: Directive = {
  mounted(el: HTMLElement) {
    el.style.cursor = 'move'
    el.onmousedown = (e: MouseEvent) => {
      const disX: number = e.clientX - el.offsetLeft;
      const disY: number = e.clientY - el.offsetTop;
      document.onmousemove = (e: MouseEvent) => {
        el.style.left = `${e.clientX - disX}px`;
        el.style.top = `${e.clientY - disY}px`;
      };
      document.onmouseup = () => {
        document.onmousemove = null;
      };
    }
  },
}
export default dra

然后在項(xiàng)目中使用一下:

<el-button v-drag style="position: absolute;">拖拽</el-button>

這里注意一下,我這種寫法是需要當(dāng)前文件定位為absolute的。

3.4 無限滾動(dòng)

這個(gè)的實(shí)現(xiàn)原理,主要是判斷scrollHeightscrollTopclientHeight的關(guān)系。從網(wǎng)上找了一張圖:

3.4 無限滾動(dòng)

如果滾動(dòng)軸到達(dá) 視口底部 則執(zhí)行callback函數(shù)。所以要判斷一下: scrollHeight - scrollTop <= clientHeight

新建一個(gè)infiniteScroll.ts文件:

import type { Directive, DirectiveBinding } from "vue";
const infiniteScroll: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const { arg = 0, value } = binding
    const bottomDistance: number = el.clientHeight - Number(arg)
    if (el.scrollHeight - el.scrollTop <= bottomDistance) {
      value()   // 執(zhí)行回調(diào)
    }
  },
}
export default infiniteScroll

在項(xiàng)目中使用一下:

<div v-infiniteScroll:[distance]="callBack"> </div>

四. 總結(jié)

好用的一些指令還有很多,比如防抖、節(jié)流等。這里就不多說了。這里主要是提供一些好用的指令實(shí)現(xiàn)的方法。

到此這篇關(guān)于Vue3.0中一些好用的指令封裝的文章就介紹到這了,更多相關(guān)Vue3.0指令封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue2中使用tailwindCss的詳細(xì)教程

    Vue2中使用tailwindCss的詳細(xì)教程

    Tailwind CSS是一個(gè)流行的前端CSS框架,它基于原子設(shè)計(jì)原則,提供了一套預(yù)構(gòu)建的CSS樣式類,旨在幫助開發(fā)者快速地創(chuàng)建響應(yīng)式、可定制的用戶界面,本文給大家介紹了Vue2中使用tailwindCss的詳細(xì)教程,需要的朋友可以參考下
    2024-09-09
  • vue.js實(shí)現(xiàn)標(biāo)簽頁切換效果

    vue.js實(shí)現(xiàn)標(biāo)簽頁切換效果

    這篇文章主要介紹了vue.js實(shí)現(xiàn)標(biāo)簽頁切換效果,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • Vue實(shí)現(xiàn)選擇城市功能

    Vue實(shí)現(xiàn)選擇城市功能

    這篇文章主要介紹了Vue實(shí)現(xiàn)選擇城市功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-05-05
  • Vue+Element+Springboot圖片上傳的實(shí)現(xiàn)示例

    Vue+Element+Springboot圖片上傳的實(shí)現(xiàn)示例

    最近在學(xué)習(xí)前段后分離,本文介紹了Vue+Element+Springboot圖片上傳的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-11-11
  • 深度解析Vue3實(shí)現(xiàn)日歷組件的五大主流方案

    深度解析Vue3實(shí)現(xiàn)日歷組件的五大主流方案

    在 Vue3 項(xiàng)目開發(fā)中,日歷組件是日程管理,預(yù)約系統(tǒng),數(shù)據(jù)可視化等場(chǎng)景的核心組件,本文將從易用性,擴(kuò)展性,性能三個(gè)維度,深入分析 5 款主流 Vue3 日歷組件,并提供選型建議,幫助開發(fā)者快速找到適配場(chǎng)景的最佳方案
    2026-04-04
  • 解決VUE-npm ERR! C:\rj\node-v14.4.0-win-x64\nod問題

    解決VUE-npm ERR! C:\rj\node-v14.4.0-win-x64\nod問題

    這篇文章主要介紹了解決VUE-npm ERR! C:\rj\node-v14.4.0-win-x64\nod問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能

    vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能

    這篇文章主要介紹了vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-04-04
  • Vue $router.push打開新窗口的實(shí)現(xiàn)方法

    Vue $router.push打開新窗口的實(shí)現(xiàn)方法

    在Vue中,$router.push方法默認(rèn)不支持在新窗口中打開頁面,但通過結(jié)合window.open方法和$router.resolve方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09
  • vue?父子組件共用mixins的注意點(diǎn)

    vue?父子組件共用mixins的注意點(diǎn)

    這篇文章主要介紹了vue?父子組件共用mixins的注意點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 基于vue通用表單解決方案的思考與分析

    基于vue通用表單解決方案的思考與分析

    這篇文章主要給大家介紹了基于vue通用表單解決方案的思考與分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論

谢通门县| 板桥市| 抚顺县| 双城市| 张家港市| 桐柏县| 丽江市| 凤台县| 柏乡县| 苍南县| 镇安县| 乐山市| 乳山市| 望城县| 若羌县| 汝阳县| 资兴市| 汝州市| 太仆寺旗| 马公市| 淮南市| 信宜市| 海安县| 武邑县| 黔江区| 德钦县| 平顺县| 永顺县| 吉木萨尔县| 临湘市| 仙桃市| 张家口市| 邯郸市| 织金县| 富源县| 响水县| 宁阳县| 中西区| 晋中市| 嵊州市| 柳林县|