vue-model如何自定義指令,及批量注冊自定義指令

一、在Vue.js中,v-model是一個用于在表單輸入和應用狀態之間創建雙向綁定的指令。要編寫自定義的v-model指令,你需要使用Vue的自定義指令API。以下是編寫自定義v-model指令的步驟:

  1. 定義一個自定義指令對象。
  2. 在指令對象的bind鉤子函數中,設置元素的初始值。
  3. inserted鉤子函數中,添加事件監聽器來更新數據。
  4. componentUpdated鉤子函數中,確保當父組件的數據變化時,更新元素的值。
  5. unbind鉤子函數中,移除事件監聽器。

下面是一個示例代碼,展示了如何創建一個自定義的v-model指令:

Vue.directive('custom-model', {bind: function(el, binding, vnode) {// 初始化元素值el.value = binding.value;// 定義一個處理函數,用于更新數據function handleInput(event) {const newValue = event.target.value;if (newValue !== binding.value) {vnode.context.$emit('input', newValue);}}// 為元素添加事件監聽器el.addEventListener('input', handleInput);// 將處理函數存儲在元素的_handleInput屬性中,以便后續可以移除監聽器el._handleInput = handleInput;},inserted: function(el, binding, vnode) {// 可以在這里執行一些額外的操作,例如聚焦輸入框等},update: function(el, binding, vnode) {// 確保元素的值與綁定的值同步if (binding.value !== el.value) {el.value = binding.value;}},unbind: function(el) {// 移除事件監聽器el.removeEventListener('input', el._handleInput);delete el._handleInput;}
});

在這個示例中,我們創建了一個名為custom-model的自定義指令。這個指令會在綁定的元素上設置一個輸入事件監聽器,當用戶輸入時,它會觸發一個input事件并更新綁定的數據。同時,當綁定的數據發生變化時,指令的update鉤子會確保元素的值也相應地更新。最后,當指令解綁時,我們會移除事件監聽器以清理資源。

二、如何批量注冊v-model自定義指令

在Vue.js中,如果你需要批量注冊多個自定義指令,包括v-model指令,你可以使用一個循環來簡化這個過程。以下是一個示例,展示了如何批量注冊多個自定義指令,包括自定義的v-model指令:

// 定義自定義指令對象
const customDirectives = {'custom-model': {bind: function(el, binding, vnode) {el.value = binding.value;function handleInput(event) {const newValue = event.target.value;if (newValue !== binding.value) {vnode.context.$emit('input', newValue);}}el.addEventListener('input', handleInput);el._handleInput = handleInput;},inserted: function(el, binding, vnode) {// 可以在這里執行一些額外的操作,例如聚焦輸入框等},update: function(el, binding, vnode) {if (binding.value !== el.value) {el.value = binding.value;}},unbind: function(el) {el.removeEventListener('input', el._handleInput);delete el._handleInput;}},// 其他自定義指令可以在這里添加
};// 批量注冊自定義指令
Object.keys(customDirectives).forEach(key => {Vue.directive(key, customDirectives[key]);
});

在這個示例中,我們首先定義了一個包含所有自定義指令的對象customDirectives。然后,我們使用Object.keys()方法獲取這個對象的所有鍵(即指令名稱),并使用forEach循環遍歷這些鍵,調用Vue.directive()方法來注冊每個自定義指令。

這樣,你就可以輕松地批量注冊多個自定義指令,包括自定義的v-model指令。

三、常用自定義指令

1、v-copy

需求:實現一鍵復制文本內容,用于鼠標右鍵黏貼

思路:

  1. 創建自定義指令:在Vue實例中定義一個自定義指令?v-copy
  2. 使用Clipboard API:利用現代瀏覽器提供的?navigator.clipboard.writeText()?方法來實現復制功能。
  3. 處理右鍵事件:監聽元素的右鍵事件,并觸發復制操作。
  4. 回退機制:如果?navigator.clipboard?不可用,可以使用傳統的DOM操作方式作為回退方案。

實現代碼如下:

// main.js or where you define your Vue instance
import Vue from 'vue';Vue.directive('copy', {bind(el, binding) {const textToCopy = binding.value;// Function to handle the copy actionfunction handleCopy() {if (navigator.clipboard && window.isSecureContext) {navigator.clipboard.writeText(textToCopy).then(() => {console.log('復制成功!');}).catch((err) => {console.error('復制失敗:', err);fallbackCopyTextToClipboard(textToCopy);});} else {fallbackCopyTextToClipboard(textToCopy);}}// Fallback method for older browsersfunction fallbackCopyTextToClipboard(text) {const textArea = document.createElement('textarea');textArea.value = text;textArea.style.position = 'fixed'; // Prevent scrolling to bottom of page in MS Edge.document.body.appendChild(textArea);textArea.focus();textArea.select();try {document.execCommand('copy');console.log('復制成功!');} catch (err) {console.error('復制失敗:', err);}document.body.removeChild(textArea);}// Add event listener for right-click context menuel.addEventListener('contextmenu', (event) => {event.preventDefault(); // Prevent default context menuhandleCopy();});}
});// In your Vue component template
<template><div v-copy="'要復制的文本內容'">點擊右鍵復制這段文本</div>
</template>
  1. 自定義指令綁定:在?bind?鉤子中,我們獲取到需要復制的文本內容?binding.value
  2. 處理復制邏輯
    • 如果瀏覽器支持?navigator.clipboard?并且當前頁面是在安全上下文(HTTPS)下運行,則使用?navigator.clipboard.writeText?方法進行復制。
    • 如果不支持或發生錯誤,則調用?fallbackCopyTextToClipboard?函數,該函數使用傳統的方法創建一個隱藏的?<textarea>?元素來執行復制操作。
  3. 右鍵事件監聽:通過監聽?contextmenu?事件,阻止默認的右鍵菜單彈出,并調用?handleCopy?函數執行復制操作。
  4. 回退機制:在?fallbackCopyTextToClipboard?函數中,創建一個隱藏的?<textarea>?元素,將文本內容放入其中,選中并執行復制命令,最后移除該元素。

這樣,你就可以在Vue組件中使用 v-copy 自定義指令,實現一鍵復制文本內容的功能,并在鼠標右鍵時觸發復制操作。

2、拖拽自定義指令

需求:實現一個拖拽指令,可在頁面可視區域任意拖拽元素

export default {inserted(el) {let disX, disY;const oDiv = el;const onMouseDown = (e) => {// 防止默認行為(如選中文本)e.preventDefault();// 計算鼠標相對元素的位置disX = e.clientX - oDiv.offsetLeft;disY = e.clientY - oDiv.offsetTop;// 綁定移動和結束事件document.addEventListener('mousemove', onMouseMove);document.addEventListener('mouseup', onMouseUp);};const onMouseMove = (e) => {// 計算新的位置let left = e.clientX - disX;let top = e.clientY - disY;// 獲取視口尺寸const viewportWidth = window.innerWidth || document.documentElement.clientWidth;const viewportHeight = window.innerHeight || document.documentElement.clientHeight;// 獲取元素尺寸const elWidth = oDiv.offsetWidth;const elHeight = oDiv.offsetHeight;// 限制元素不超出視口left = Math.max(0, Math.min(left, viewportWidth - elWidth));top = Math.max(0, Math.min(top, viewportHeight - elHeight));// 設置元素位置oDiv.style.left = `${left}px`;oDiv.style.top = `${top}px`;};const onMouseUp = () => {// 移除事件監聽器document.removeEventListener('mousemove', onMouseMove);document.removeEventListener('mouseup', onMouseUp);};// 綁定鼠標按下事件oDiv.addEventListener('mousedown', onMouseDown);// 可選:添加觸摸事件支持const onTouchStart = (e) => {if (e.touches.length !== 1) return; // 只處理單點觸控const touch = e.touches[0];disX = touch.clientX - oDiv.offsetLeft;disY = touch.clientY - oDiv.offsetTop;document.addEventListener('touchmove', onTouchMove);document.addEventListener('touchend', onTouchEnd);};const onTouchMove = (e) => {if (e.touches.length !== 1) return;const touch = e.touches[0];let left = touch.clientX - disX;let top = touch.clientY - disY;const viewportWidth = window.innerWidth || document.documentElement.clientWidth;const viewportHeight = window.innerHeight || document.documentElement.clientHeight;const elWidth = oDiv.offsetWidth;const elHeight = oDiv.offsetHeight;left = Math.max(0, Math.min(left, viewportWidth - elWidth));top = Math.max(0, Math.min(top, viewportHeight - elHeight));oDiv.style.left = `${left}px`;oDiv.style.top = `${top}px`;};const onTouchEnd = () => {document.removeEventListener('touchmove', onTouchMove);document.removeEventListener('touchend', onTouchEnd);};oDiv.addEventListener('touchstart', onTouchStart);},unbind(el) {// 移除所有事件監聽器el.removeEventListener('mousedown', this.onMouseDown);el.removeEventListener('touchstart', this.onTouchStart);document.removeEventListener('mousemove', this.onMouseMove);document.removeEventListener('mouseup', this.onMouseUp);document.removeEventListener('touchmove', this.onTouchMove);document.removeEventListener('touchend', this.onTouchEnd);}
};
  1. 事件綁定和解綁:

    • 將?mousedownmousemovemouseuptouchstarttouchmove?和?touchend?事件綁定到目標元素本身,而不是全局?document。這避免了多個可拖拽元素之間的事件沖突,并提高了性能。
    • 在?unbind?鉤子中,確保移除所有添加的事件監聽器,防止內存泄漏。
  2. 邊界檢查:

    • 在?onMouseMove?和?onTouchMove?函數中,計算元素的新位置時,加入了對視口尺寸的檢查,確保元素不會拖出視窗范圍。
  3. 觸摸設備支持:

    • 添加了對觸摸事件的處理,使指令在移動設備上也能正常工作。
  4. 代碼現代化:

    • 使用了 ES6+ 的箭頭函數和模板字符串,使代碼更加簡潔易讀。
    • 使用?addEventListener?和?removeEventListener?代替直接賦值事件處理器,增強了代碼的可維護性和可讀性。
  5. 防止默認行為:

    • 在?onMouseDown?中調用?e.preventDefault(),防止在拖拽過程中出現意外的默認行為(如文本選擇)。
  6. 性能優化:

    • 通過將事件監聽器綁定到具體元素,減少了不必要的事件冒泡和捕獲,提升了性能。
  7. 樣式控制:

    • 通過計算并設置?left?和?top?樣式,而不是直接修改?style?屬性,避免了與其他 CSS 規則的潛在沖突。使用示例
    • <template><div v-drags class="draggable">拖拽我</div>
      </template><script>
      import drags from '@/directive/drag'; // 根據實際路徑調整export default {directives: {drags}
      };
      </script><style scoped>
      .draggable {position: absolute; /* 確保元素是絕對定位 */width: 100px;height: 100px;background-color: lightblue;cursor: grab;
      }
      </style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/70192.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70192.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70192.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

簡單認識一下-Redis

一、什么是Redis Redis&#xff08;Remote Dictionary Server&#xff09;是一個開源的、基于內存的數據結構存儲系統&#xff0c;它既可以用作數據庫、緩存&#xff0c;也可以作為消息中間件使用。以下為你詳細介紹 Redis&#xff1a; 基本特點 高性能&#xff1a;Redis 將數…

LabVIEW的吞雨測控系統

本案例介紹了一種基于LabVIEW開發的吞雨測控系統&#xff0c;該系統通過建模仿真分析不同控制器模式下的階躍信號響應&#xff0c;從而選擇了最適合的控制器。為了有效解決在控制流量過程中出現的振蕩收斂和流量信號大擾動問題&#xff0c;系統采用了改進的積分分離PID算法&…

C++中的順序容器(一)

文章目錄 順序容器概述所有容器類型都支持的操作迭代器容器定義與初始化將一個容器初始化為另一個容器的拷貝標準庫array具有固定大小 賦值和swap關系運算符 順序容器的特有操作向順序容器添加元素訪問元素刪除元素特殊的forward_list操作改變容器的大小容器操作可能是迭代器失…

Javaweb中,使用Servlet編寫簡單的接口

案例&#xff1a;網頁提交用戶名和密碼信息&#xff0c;后端校驗密碼長度需在6-12位之間 后端部分 WebServlet("/valid") public class SimpleServlet extends HttpServlet{public void service(HttpServletRequest req, HttpServletResponse resp) throws IOExcepti…

C語言實現的常見排序算法

排序是計算機科學中非常重要的基礎算法之一。無論是在數據分析、數據庫查詢還是圖形界面中&#xff0c;我們都可能會遇到排序問題。本文將介紹幾種常見的排序算法&#xff0c;并提供其C語言實現代碼。排序算法的效率和應用場景有很大關系&#xff0c;不同的算法有不同的時間復雜…

對于簡單的HTML、CSS、JavaScript前端,我們可以通過幾種方式連接后端

1. 使用Fetch API發送HTTP請求&#xff08;最簡單的方式&#xff09;&#xff1a; //home.html // 示例&#xff1a;提交表單數據到后端 const submitForm async (formData) > {try {const response await fetch(http://your-backend-url/api/submit, {method: POST,head…

[論文閱讀] SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

文章目錄 一、前言二、主要貢獻三、Introduction四、Methodology4.1 Motivation &#xff1a;4.2Framework Overview.** 一、前言 通信作者是香港理工大學 & OPPO研究所的張磊教授&#xff0c;也是圖像超分ISR的一個大牛了。 論文如下 SeeSR: Towards Semantics-Aware Rea…

案例-04.部門管理-刪除

一.功能演示 二.需求說明 三.接口文檔 四.思路 既然是通過id刪除對應的部門&#xff0c;那么必然要獲取到前端請求的要刪除部門的id。id作為請求路徑傳遞過來&#xff0c;那么要從請求路徑中獲取&#xff0c;id是一個路徑參數。因此使用注解PathVariable獲取路徑參數。 請求方…

Blazor-父子組件傳遞任意參數

在我們從父組件傳參數給子組件時&#xff0c;可以通過子組件定義的[Parameter]特性的公開屬性進行傳值&#xff0c;但是當我們需要傳遞多個值的時候&#xff0c;就需要通過[Parameter]特性定義多個屬性&#xff0c;有沒有更簡便的方式&#xff1f; 我們可以使用定義 IDictionar…

DeepSeek 的創新融合:多行業應用實踐探索

引言 在數字化轉型的浪潮中&#xff0c;技術的融合與創新成為推動各行業發展的關鍵力量。藍耘平臺作為行業內備受矚目的創新平臺&#xff0c;以其強大的資源整合能力和靈活的架構&#xff0c;為企業提供了高效的服務支持。而 DeepSeek 憑借先進的人工智能技術&#xff0c;在自然…

STM32創建靜態庫lib

創建靜態庫lib 1. 新建工程1.1 創建工程文件夾1.2 編寫用戶相關代碼1.2.1 stm32f4xx_it.h1.2.2 stm32f4xx_it.c1.2.3 標準庫配置&#xff1a;stm32f4xx_conf.h1.2.4 HAL庫的配置&#xff1a;stm32f4xx_hal_conf.h1.2.5 LL庫配置&#xff1a;stm32f4xx_ll_conf.h 1.3 移植通用文…

elabradio入門第二講——BPSK數字調制與解調(插值、升余弦濾波、速率匹配、符號同步)

數字信號可以通過數字基帶傳輸系統進行傳輸&#xff0c;而基帶傳輸系統僅僅適用于低頻信道下的數字信號傳輸。然而&#xff0c;在實際的通信系統中信道通常具有帶通特性&#xff0c;因而需要將基帶信號搬移到適合信道傳輸的高頻載波上&#xff0c;使得信號與信道相匹配&#xf…

汽車 OTA 升級:提升下載與升級速度,優化用戶體驗

摘要&#xff1a; 隨著汽車智能化的飛速發展&#xff0c;OTA&#xff08;Over - the - Air&#xff09;升級已成為汽車行業的重要技術&#xff0c;它能為車輛持續帶來功能更新與性能優化。然而&#xff0c;下載及升級速度較慢的問題常常影響用戶體驗。本文深入探討在汽車 OTA …

【Spring+MyBatis】留言墻的實現

目錄 1. 添加依賴 2. 配置數據庫 2.1 創建數據庫與數據表 2.2 創建與數據庫對應的實體類 3. 后端代碼 3.1 目錄結構 3.2 MessageController類 3.3 MessageService類 3.4 MessageMapper接口 4. 前端代碼 5. 單元測試 5.1 后端接口測試 5.2 使用前端頁面測試 在Spri…

SQLite Select 語句詳解

SQLite Select 語句詳解 SQLite 是一個輕量級的數據庫管理系統&#xff0c;以其簡潔的設計和高效的性能被廣泛應用于各種場景。在 SQLite 中&#xff0c;SELECT 語句是用于查詢數據庫中的數據的命令。本文將詳細介紹 SQLite 的 SELECT 語句&#xff0c;包括其基本語法、常用功…

深度學習05 ResNet殘差網絡

目錄 傳統卷積神經網絡存在的問題 如何解決 批量歸一化BatchNormalization, BN 殘差連接方式 ?殘差結構 ResNet網絡 ResNet 網絡是在 2015年 由微軟實驗室中的何凱明等幾位大神提出&#xff0c;斬獲當年ImageNet競賽中分類任務第一名&#xff0c;目標檢測第一名。獲得CO…

組件庫地址

react&#xff1a; https://react-vant.3lang.dev/components/dialoghttps://react-vant.3lang.dev/components/dialog vue用v2的 Vant 2 - Mobile UI Components built on Vue

docker 進階命令(基于Ubuntu)

數據卷 Volume: 目錄映射, 目錄掛載 匿名綁定: 匿名綁定的 volume 在容器刪除的時候, 數據卷也會被刪除, 匿名綁定是不能做到持久化的, 地址一般是 /var/lib/docker/volumes/xxxxx/_data 綁定卷時修改宿主機的目錄或文件, 容器內的數據也會同步修改, 反之亦然 # 查看所有 vo…

從入門到精通:Postman 實用指南

Postman 是一款超棒的 API 開發工具&#xff0c;能用來測試、調試和管理 API&#xff0c;大大提升開發效率。下面就給大家詳細講講它的安裝、使用方法&#xff0c;再分享些實用技巧。 一、安裝 Postman 你能在 Postman 官網&#xff08;https://www.postman.com &#xff09;下…

將圖片base64編碼后,數據轉成圖片

將圖片數據進行base64編碼后&#xff0c;可以在瀏覽器上查看圖片&#xff0c;只需在前端加上data:image/png;base64,即可 在線工具&#xff1a; Base64轉圖片 - 加菲工具