详解如何在Vue里建立长按指令


Posted in Javascript onAugust 20, 2018

您是否曾想过按住按钮几秒钟才能在Vue应用程序中执行某个功能?

您是否曾想在应用程序上创建一个按钮,通过按一次(或按住按钮的整个输入)来清除单个输入?

如果你曾有过这些想法,很好,我也是。那么恭喜你看到了这篇文章。

本文将解释如何通过按下(或按住)按钮来执行功能和删除输入。

首先,我将解释如何在VanillaJS中实现这一目标。然后,为它创建一个Vue指令。

那么,让我们开始吧。

原理

为了实现长按,用户需要按住按钮几秒钟。

要在代码中复制它,我们需要在按下鼠标“单击”按钮时监听,启动计时器,不管我们希望用户在执行函数之前按住按钮,并在时间设置之后执行该功能。

非常简单!但是,我们需要知道用户何时按住该按钮。

怎么做

当用户单击按钮时,在单击事件之前会触发另外两个事件: 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在解释它这里方面做得很好。

成功 !!!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
zeroclipboard复制到剪切板的flash
Aug 04 Javascript
密码强度检测效果实现原理与代码
Jan 04 Javascript
JS实现div内部的文字或图片自动循环滚动代码
Apr 19 Javascript
图片Slider 带左右按钮的js示例
Aug 30 Javascript
jquery表单对象属性过滤选择器实例分析
May 18 Javascript
NODE.JS跨域问题的完美解决方案
Oct 20 Javascript
微信小程序获取用户openId的实现方法
May 23 Javascript
jQuery中each循环的跳出和结束实例
Aug 16 jQuery
js实现简易聊天对话框
Aug 17 Javascript
Angular2里获取(input file)上传文件的内容的方法
Sep 05 Javascript
详解vue-cli构建项目反向代理配置
Sep 07 Javascript
微信小程序开发之路由切换页面重定向问题
Sep 18 Javascript
微信小程序scroll-view实现滚动穿透和阻止滚动的方法
Aug 20 #Javascript
Angular6 写一个简单的Select组件示例
Aug 20 #Javascript
Layer弹出层动态获取数据的方法
Aug 20 #Javascript
layui 给数据表格加序号的方法
Aug 20 #Javascript
解决LayUI表单获取不到data的问题
Aug 20 #Javascript
Layui数据表格之获取表格中所有的数据方法
Aug 20 #Javascript
解决layui上传文件提示上传异常,实际文件已经上传成功的问题
Aug 19 #Javascript
You might like
用PHP制作静态网站的模板框架(一)
2006/10/09 PHP
php 中的str_replace 函数总结
2007/04/27 PHP
非常实用的PHP常用函数汇总
2014/12/17 PHP
Linux服务器下PHPMailer发送邮件失败的问题解决
2017/03/04 PHP
JavaScript Event学习第三章 早期的事件处理程序
2010/02/07 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
js实现带圆角的两级导航菜单效果代码
2015/08/24 Javascript
AngularJS入门教程中SQL实例详解
2016/07/27 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
jQuery如何防止Ajax重复提交
2016/10/14 Javascript
javascript 利用arguments实现可变长参数
2016/11/21 Javascript
javascript函数的四种调用模式
2017/01/08 Javascript
解决ztree搜索中多级菜单展示不全问题
2017/07/05 Javascript
微信JSAPI Ticket接口签名详解
2020/06/28 Javascript
ES6新增数据结构WeakSet的用法详解
2017/08/07 Javascript
JS将网址url转化为JSON格式的方法
2018/07/02 Javascript
详解webpack4.x之搭建前端开发环境
2019/03/28 Javascript
JavaScript自动生成 年月范围 选择功能完整示例【基于jQuery插件】
2019/09/03 jQuery
layui关闭层级、简单监听的实例
2019/09/06 Javascript
vue自定义标签和单页面多路由的实现代码
2020/05/03 Javascript
[00:55]2015国际邀请赛中国区预选赛5月23日——28日约战上海
2015/05/25 DOTA
收集的几个Python小技巧分享
2014/11/22 Python
详解Python中的各种函数的使用
2015/05/24 Python
解决Python安装时报缺少DLL问题【两种解决方法】
2019/07/15 Python
django认证系统实现自定义权限管理的方法
2019/08/28 Python
python pillow模块使用方法详解
2019/08/30 Python
详解python中docx库的安装过程
2019/11/08 Python
wxPython色环电阻计算器
2019/11/18 Python
新西兰最大的品牌运动鞋购物网站:Platypus NZ
2017/10/27 全球购物
Ibatis如何使用动态表名
2015/07/12 面试题
Linux如何命名文件--使用文件名时应注意
2014/05/29 面试题
二年级数学教学反思
2014/01/21 职场文书
学生会主席竞聘书
2014/03/31 职场文书
承诺书范文
2014/06/03 职场文书
html2 canvas svg不能识别的解决方案
2021/06/03 HTML / CSS
使用scrapy实现增量式爬取方式
2022/06/21 Python