[Перевод] Напишите команду длительного нажатия с помощью Vue

внешний интерфейс JavaScript Vue.js

Оригинальная ссылка:Building a long press directive in Vue

Переводчик:OFED

Напишите команду длительного нажатия с помощью Vue

Alt text

Вы когда-нибудь хотели просто удерживать кнопку в течение нескольких секунд, чтобы активировать функцию в вашем приложении Vue?

Вы когда-нибудь задумывались о создании кнопки, которая очищает одну запись одним нажатием (или постоянным удержанием, чтобы очистить все записи)?

мысль? Отлично, герои видят то же самое.

Эта статья о том, как выполнить функцию и очистить ввод при нажатии (или удерживании) кнопки.

Сначала я объясню, как это сделать на чистом JS. Затем также создается директива Vue.

Пожалуйста, пристегните ремень. Грядет хорошее шоу.

принцип

Чтобы добиться длительного нажатия, пользователю необходимо нажать и удерживать кнопку в течение нескольких секунд.

Чтобы смоделировать этот эффект через код, нам нужно запустить таймер, чтобы отслеживать продолжительность нажатия пользователя, когда мышь «щелкает» кнопку, и, если время превышает ожидаемую нами продолжительность, выполнять соответствующую функцию.

очень простой! Однако нам нужно знать, когда пользователь удерживает кнопку.

Как добиться

Когда пользователь нажимает кнопку, перед событием нажатия запускаются два других события:mousedownа такжеmouseup.

Запускается, когда пользователь нажимает кнопкуmousedownсобытие, вызываемое, когда пользователь отпускает кнопкуmouseupмероприятие.

Что нам нужно сделать, так это:

  1. mousedownКогда событие сработает, запустите таймер.
  2. однаждыmouseupЕсли событие запускается 2 секунды назад, как и ожидалось, очистите таймер и не выполняйте соответствующую функцию. Так же, как обычное событие клика.

До тех пор, пока таймер не будет очищен в течение установленного нами времени, т.е.mouseupСобытие не запускается - тогда вы можете сказать, что пользователь не отпустил кнопку. Следовательно, можно определить, что длительное нажатие может выполнить соответствующую функцию.

упражняться

Давайте углубимся в код, чтобы завершить эту функциональность.

Во-первых, мы должны определить три вещи, а именно:

  1. ОдинПеременнаяИспользуется для хранения таймеров.
  2. ОдинзапускатьФункция производительности, используется для запуска таймера.
  3. ОдинОтменаФункция функции отмены таймера.

Переменная

Эта переменная в основном используется для сохраненияsetTimeoutЦенность, так что когда мышьmouseupМы можем отменить его, когда событие сработает.

let pressTimer = null;

Мы устанавливаем значение переменнойnullЦель состоит в том, чтобы проверить значение этой переменной, чтобы определить, есть ли в настоящее время работающий таймер, перед выполнением операции отмены.

функция запуска

Эта функция включает в себяsetTimeout, который является базовым методом в JavaScript, позволяющим выполнять функцию через определенное время.

Уведомление,clickВо время выполнения события запускаются два других события. Но что нам нужно, чтобы запустить таймерmousedownмероприятие. Если это просто событие щелчка, вам не нужно запускать таймер.

// 创建计时器 ( 1s之后执行函数 )
let start = (e) => {
    // 如果是点击事件,不启动计时器
    if (e.type === 'click' && e.button !== 0) {
        return;
    }
    // 在启动一个定时器之前确保没有正在运行的计时器
    if (pressTimer === null) {
        pressTimer = setTimeout(() => {
            // 执行任务 !!!
        }, 1000)
    }
}

функция отмены

Эта функция, как следует из названия, используется для отмены создания функции запуска.setTimeout.

отменитьsetTimeout, вы можете использовать JavaScriptclearTimeoutметод, который в основном используется для очисткиsetTimeout()Таймер, установленный методом.

В использованииclearTimeoutПеред этим нужно проверитьpressTimerЯвляется ли переменнаяnull. если бы неnull, что означает наличие работающего таймера. Поэтому нам нужно сначала очистить его и поставитьpressTimerпеременная установлена ​​вnull.

let cancel = (e) => {
    // 检查 pressTimer 的值是否为 null
    if (pressTimer !== null) {
        clearTimeout(pressTimer)
        pressTimer = null
    }
}

однаждыmouseupКогда событие сработает, эта функция будет вызвана.

установить триггер

Все, что осталось, — это добавить прослушиватели событий к кнопкам, которые вы хотите использовать при длительном нажатии.

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

Приведенный выше код составлен следующим образом:

// 定义变量
let pressTimer = null;

// 创建计时器( 1秒后执行函数 )
let start = (e) => {

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

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

            // 执行任务 !!!

        }, 1000)
    }
}

// 停止计时器
let cancel = (e) => {

    // 检查是否有正在运行的计时器
    if ( pressTimer !== null ) {
        clearTimeout(pressTimer);
        pressTimer = null;
    }
}

// 选择 id 为 longPressButton 的元素
let el = document.getElementById('longPressButton');

// 添加事件监听器
el.addEventListener("mousedown", start);

// 长按事件取消,取消计时器
el.addEventListener("click", cancel);
el.addEventListener("mouseout", cancel);

Обертывание с помощью директив Vue

При создании директив Vue вы можете создавать глобальные или локальные директивы.В этой статье мы используем глобальные директивы.

Во-первых, мы должны объявить имя пользовательской директивы.

Vue.directive('longpress', {

})

Это регистрируетv-longpressглобальная пользовательская директива.

Далее добавляем бинд с параметрамифункция ловушки, что позволяет нам ссылаться на элемент, к которому привязана директива, получать значение, переданное директиве, и идентифицировать компонент, используемый директивой.

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

    }
})

Далее мы добавляем код для функции длительного нажатия в функцию привязки.

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

        // 定义变量
        let pressTimer = null;

        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {

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

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

                    // 执行任务 !!!

                }, 1000)
            }
        }

        // 取消计时器
        let cancel = (e) => {

            // 检查是否有正在运行的计时器
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }

        // 添加事件监听器
        el.addEventListener("mousedown", start);

        // 取消计时器
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
    }
})

Далее нам нужно добавить функцию для запуска переданного вlongpressметод обучения.

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

        // 定义变量
        let pressTimer = null;

        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {

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

            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // 执行函数
                    handler();
                }, 1000)
            }
        }

        // 停止计时器
        let cancel = (e) => {

            // 检查是否有正在运行的计时器
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }

        // 运行函数
        const handler = (e) => {
            // 执行传递给指令的方法
            binding.value(e)
        }

        // 添加事件监听器
        el.addEventListener("mousedown", start);

        // 取消计时器
        el.addEventListener("click", cancel);
        el.addEventListener("mouseout", cancel);
    }
})

Теперь эту директиву можно использовать в приложениях Vue, если только пользователь не передаст директиве значение, не являющееся функцией. Поэтому нам необходимо давать обратную связь пользователям посредством предупреждений.

Для обратной связи с пользователями мы добавили в функцию привязки следующее:

// 确保提供的表达式是函数
if (typeof binding.value !== 'function') {
    // 获取组件名称
    const compName = vNode.context.name;
    // 将警告传递给控制台
    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) {

        // 确保提供的表达式是函数
        if (typeof binding.value !== 'function') {
            // 获取组件名称
            const compName = vNode.context.name;
            // 将警告传递给控制台
            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);
        }

        // 定义变量
        let pressTimer = null;

        // 定义函数处理程序
        // 创建计时器( 1秒后执行函数 )
        let start = (e) => {

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

            if (pressTimer === null) {
                pressTimer = setTimeout(() => {
                    // 执行函数
                    handler();
                }, 1000)
            }
        }

        // 取消计时器
        let cancel = (e) => {

            // 检查计时器是否有值
            if ( pressTimer !== null ) {
                clearTimeout(pressTimer);
                pressTimer = null;
            }
        }

        // 运行函数
        const handler = (e) => {
            // 执行传递给指令的方法
            binding.value(e)
        }

        // 添加事件监听器
        el.addEventListener("mousedown", start);
        el.addEventListener("touchstart", start);

        // 取消计时器
        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: {
        // 增加1
        incrementPlusOne() {
            this.value++
        },
        // 增加10
        incrementPlusTen() {
            this.value += 10
        }
    }
}
</script>
. . .

Если вы хотите узнать больше опользовательская директива, пригодный для использованияфункция ловушки, который можно передать этой функции ловушкипараметр,сокращенная функцияинформация см.@vuejsОфициальная документация, автор сделал хорошее объяснение.

Заканчивай, ура!

. . .