如何在Vue裏創建長按指令

clipboard.png

您是否曾想過按住按鈕幾秒鐘才能在Vue應用程序中執行某個功能?javascript

您是否曾想在應用程序上建立一個按鈕,經過按一次(或按住按鈕的整個輸入)來清除單個輸入?html

若是你曾有過這些想法,很好,我也是。那麼恭喜你看到了這篇文章。前端

本文將解釋如何經過按下(或按住)按鈕來執行功能和刪除輸入。vue

首先,我將解釋如何在VanillaJS中實現這一目標。而後,爲它建立一個Vue指令。java

那麼,讓咱們開始吧。git

原理

爲了實現長按,用戶須要按住按鈕幾秒鐘。github

要在代碼中複製它,咱們須要在按下鼠標「單擊」按鈕時監聽,啓動計時器,無論咱們但願用戶在執行函數以前按住按鈕,並在時間設置以後執行該功能。express

很是簡單!可是,咱們須要知道用戶什麼時候按住該按鈕。瀏覽器

怎麼作

當用戶單擊按鈕時,在單擊事件以前會觸發另外兩個事件: mousedown 和 mouseup 。網絡

當用戶按下鼠標按鈕時會調用 mousedown 事件,而當用戶釋放該按鈕時會調用mouseup事件。

咱們須要作的就是:

發生mousedown事件後啓動計時器。

清除該計時器,而且在2secs標記以前觸發mouseup事件後不執行該函數。即完整點擊事件。

只要計時器在到達那個時間以前沒有被清除,咱們就會發現mouseup事件沒有被觸發 - 咱們能夠說用戶沒有釋放按鈕。所以,它被認爲是長按,而後咱們能夠繼續執行所述功能。

實際操做

讓咱們深刻研究代碼並完成這項工做。

首先,咱們必須定義3件事,即:

variable 用於存儲計時器。

start 函數啓動計時器。

cancel 函數取消定時器

變量

這個變量基本上保存了setTimeout的值,因此咱們能夠在發生mouseup事件時取消它。

let pressTimer = null;

咱們將變量設置爲null,這樣咱們就能夠檢查變量,以便知道當前是否有一個活動定時器,而後才能取消它。

啓動功能

該函數由setTimeout組成,它基本上是Javascript中的一種方法,它容許咱們在函數中聲明的特定持續時間以後執行函數。

請記住,在建立click事件的過程當中,會觸發兩個事件。但咱們須要啓動計時器的是mousedown事件。所以,若是是單擊事件,咱們不須要啓動計時器。

// Create timeout ( run function after 1s )
let start = (e) => {
    
    // Make sure the event trigger isn't a click event
    if (e.type === 'click' && e.button !== 0) {
        return;
    }
    // Make sure we don't currently have a setTimeout running
    // before starting another
    if (pressTimer === null) {
        pressTimer = setTimeout(() => {
            // Execute soemthing !!!
        }, 1000)
    }
}

取消功能

這個函數基本上就是名字所說的,取消了調用start函數時建立的setTimeout。

要取消setTimeout,咱們將在javascript中使用 clearTimeout 方法,該方法基本上清除了使用setTimeout()設置的計時器方法。

在使用clearTimeout以前,咱們首先須要檢查 pressTimer 變量是否設置爲null。若是它未設置爲null,則表示存在活動計時器。因此,咱們須要清除計時器,你猜對了,將 pressTimer 變量設置爲 null

let cancel = (e) => {
    // Check if timer has a value or not
    if (pressTimer !== null) {
        clearTimeout(pressTimer)
        pressTimer = null
    }
}

一旦 mouseup 事件被觸發,就會調用此函數。

設置觸發器

剩下的就是將事件監聽器添加到要添加長按效果的按鈕上。

addEventListener("mousedown", start);
addEventListener("click", cancel);

總而言之,咱們有:

// Define variable
let pressTimer = null;

// Create timeout ( run function after 1s )
let start = (e) => {

    if (e.type === 'click' && e.button !== 0) {
        return;
    }

    if (pressTimer === null) {
        pressTimer = setTimeout(() => {

            // Execute something !!!

        }, 1000);
    }
}

// Cancel Timeout
let cancel = (e) => {

    // Check if timer has a value or not
    if (pressTimer !== null) {
        clearTimeout(pressTimer);
        pressTimer = null;
    }
}

// select element with id longPressButton
let el = document.getElementById('longPressButton');

// Add Event listeners
el.addEventListener("mousedown", start);

// Cancel timeouts if this events happen
el.addEventListener("click", cancel);
el.addEventListener("mouseout", cancel);

將它所有包裝在Vue指令中

在建立Vue指令時,Vue容許咱們在組件的全局或本地定義指令,但在本文中咱們將使用全局路由。

讓咱們構建完成此任務的指令。

首先,咱們必須聲明自定義指令的名稱。

Vue.directive('longpress', {
  
}

這基本上註冊了一個名爲 v-longpress的全局自定義指令.

接下來,咱們使用一些參數添加bind hook函數 ,這容許咱們引用元素指令綁定,獲取傳遞給指令的值並標識使用該指令的組件。

Vue.directive('longpress', {
  bind: function (el, binding, vNode) {
    
  }
}

接下來,咱們在bind函數中添加咱們的長按javascript代碼。

Vue.directive('longpress', {
    bind: function (el, binding, vNode) {

        // Define variable
        let pressTimer = null

        // Define funtion handlers
        // Create timeout ( run function after 1s )
        let start = (e) => {

            if (e.type === 'click' && e.button !== 0) {
                return;
            }

            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // Execute something !!!
                }, 1000)
            }
        }

        // Cancel Timeout
        let cancel = (e) => {
            // Check if timer has a value or not
            if (pressTimer !== null) {
                clearTimeout(pressTimer)
                pressTimer = null
            }
        }

        // Add Event listeners
        el.addEventListener("mousedown", start);
        // Cancel timeouts if this events happen
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
    }
})

接下來,咱們須要添加一個函數來運行將傳遞給 longpress 指令的方法。

// Long Press vue directive
Vue.directive('longpress', {
    bind: function (el, binding, vNode) {

        // Define variable
        let pressTimer = null

        // Define funtion handlers
        // Create timeout ( run function after 1s )
        let start = (e) => {

            if (e.type === 'click' && e.button !== 0) {
                return;
            }

            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // Execute function
                    handler()
                }, 1000)
            }
        }

        // Cancel Timeout
        let cancel = (e) => {
            // Check if timer has a value or not
            if (pressTimer !== null) {
                clearTimeout(pressTimer)
                pressTimer = null
            }
        }
        // Run Function
        const handler = (e) => {
            // Execute method that is passed to the directive
            binding.value(e)
        }

        // Add Event listeners
        el.addEventListener("mousedown", start);

        // Cancel timeouts if this events happen
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
        
    }
})

如今咱們能夠在咱們的Vue應用程序中使用該指令,該指令將正常工做,直到用戶添加的值不是指令值中的函數。因此咱們必須經過在發生這種狀況時警告用戶來防止這種狀況。

要警告用戶,咱們將如下內容添加到bind函數:

// Make sure expression provided is a function
if (typeof binding.value !== 'function') {
  // Fetch name of component
  const compName = vNode.context.name
  // pass warning to console
  let warn = `[longpress:] provided expression '${binding.expression}' is not a function, but has to be`
  if (compName) { warn += `Found in component '${compName}' ` }
  console.warn(warn)
}

最後,這個指令也適用於觸控設備。因此咱們爲 touchstart , touchend & touchcancel 添加事件監聽器。

把全部東西放在一塊兒:

Vue.directive('longpress', {
    bind: function (el, binding, vNode) {
        // Make sure expression provided is a function
        if (typeof binding.value !== 'function') {
            // Fetch name of component
            const compName = vNode.context.name
            // pass warning to console
            let warn = `[longpress:] provided expression '${binding.expression}' is not a function, but has to be`
            if (compName) { warn += `Found in component '${compName}' ` }

            console.warn(warn)
        }

        // Define variable
        let pressTimer = null

        // Define funtion handlers
        // Create timeout ( run function after 1s )
        let start = (e) => {

            if (e.type === 'click' && e.button !== 0) {
                return;
            }

            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // Run function
                    handler()
                }, 1000)
            }
        }

        // Cancel Timeout
        let cancel = (e) => {
            // Check if timer has a value or not
            if (pressTimer !== null) {
                clearTimeout(pressTimer)
                pressTimer = null
            }
        }
        // Run Function
        const handler = (e) => {
            binding.value(e)
        }

        // Add Event listeners
        el.addEventListener("mousedown", start);
        el.addEventListener("touchstart", start);
        // Cancel timeouts if this events happen
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
        el.addEventListener("touchend", cancel);
        el.addEventListener("touchcancel", cancel);
    }
})

如今引用咱們的Vue組件:

<template>
    <div>
        <button v-longpress="incrementPlusTen" @click="incrementPlusOne">{{value}}</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            value: 10
        }
    },
    methods: {
        // Increment value plus one
        incrementPlusOne() {
            this.value++
        },
        // increment value plus 10
        incrementPlusTen() {
            this.value += 10
        }
    }
}
</script>

若是您但願瞭解有關自定義指令的更多信息,可使用的鉤子函數,能夠傳遞給此鉤子函數的參數,函數縮寫。偉大的傢伙@vuejs在解釋它這裏方面作得很好。

成功 !!!

插件:LogRocket,一個用於網絡應用的DVR(錄像機)

clipboard.png

LogRocket是一個前端日誌記錄工具,可以讓您像在本身的瀏覽器中同樣重放問題。LogRocket不是猜想錯誤發生的緣由,也不是要求用戶提供屏幕截圖和日誌轉儲,而是讓您重播會話以快速瞭解出現了什麼問題。它適用於任何應用程序,不管框架如何,而且具備從Redux,Vuex和@ngrx / store記錄其餘上下文的插件。
除了記錄Redux操做和狀態以外,LogRocket還記錄控制檯日誌,JavaScript錯誤,堆棧跟蹤,帶有標題+正文的網絡請求/響應,瀏覽器元數據和自定義日誌。它還使用DOM來記錄頁面上的HTML和CSS,從新建立即便是最複雜的單頁應用程序的像素完美視頻。

在這裏試一試吧。

附:代碼示範來源

相關文章
相關標籤/搜索