专栏首页小皮咖Vue 编写一个长按指令插件

Vue 编写一个长按指令插件

1. 如何编写 Vue 插件

在以往的 Vue 项目开发过程中,我们使用插件的方法是Vue.use(plugin)。如:

import filters from "./filter/filters";
Vue.use(filters);

plugin 为 Object 对象,需内置一个install()方法方可使用。该方法第一个参数为Vue对象,其余参数由使用者传入决定。

plugin.install = function(Vue, options) {}
复制代码

2. 编写 Vue 长按指令

  1. 根据官方文档:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化
  bind: function (el, binding, vnode, oldVnode) {
  },
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  },
  // 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
  update: function (el, binding, vnode, oldVnode) {
  },
  // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  componentUpdated: function (el, binding, vnode, oldVnode) {
  },
  // 只调用一次,指令与元素解绑时调用。
  unbind: function (el, binding, vnode, oldVnode) {
  },
})
复制代码

此次长按指令我们只用到了bind()函数

  1. 分析长按功能实现

监听 mousedown 和 mouseout (移动端为 touchstart 和 touchend),间隔时间大于某个时间则视为长按事件触发。

因此需设置一个变量存放定时器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);

功能优化,当指令传入的值不为函数时提醒用户——

// 确保提供的表达式是函数        
if (typeof binding.value !== 'function') {            
  // 获取组件名称            
  const compName = vNode.context.name;            
  // 将警告传递给控制台            
  let warn = `[longpress:] provided expression '${binding.expression}' is not afunction, but has to be `;
  if (compName) { warn += `Found in component '${compName}' `}
  console.warn(warn);
}  
复制代码

3. 使长按时间可定制化

// longpress.js
export default {
  install(Vue, options = {
    time: 2000
  }) {
    // ...
  }
}

且定时器中的时间改为options.time,然后Vue.use(plugin, {time: 5000})即可。

4. 完整代码

export default {
  install(Vue, options = {
    time: 2000
  }) {
    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 afunction, 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();
            }, options.time)
          }
        }
        // 取消计时器
        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);
      }
    })
  }
}
复制代码

main.js

// main.js
import LongPress from 'longpress.js'
Vue.use(LongPress, {time: 2500})

component.vue

// template
<div v-longpress="test"></div>
// methods
methods: {
  test(event) {
    console.log(111)
  }
}
复制代码

希望本文对你有帮助!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 团队技术文档构建利器vuepress上手实践

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    csxiaoyao
  • 15.vue中的路由vue-router

    npm install vue-router --save / cnpm install vue-router --save

    玩蛇的胖纸
  • 14.非父子组件之间传值

    玩蛇的胖纸
  • uni-app: 如何高效开发?

    本文主要是讲解Uni-App开发技巧,如何快速的撸码?如何调试Uni-App?通过本文,让小伙伴们开发出优秀的Uni-App。

    Javanx
  • vue.js学习(01)

    之前尝试用electron做一些项目的时候,因为完全没有前端开发经验,做起来还是有点找不到头绪,思路非常乱,想到什么功能便搜什么,这样导致没有全局观,不找到整体...

    efonfighting
  • asp.net

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    sofu456
  • 爬虫篇 | 200 行代码实现一个滑动验证码

    做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动、点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还是很清晰的,本文章大致说明下这些验证码的...

    叫我龙总
  • vue学习篇-以优雅的姿势创建vue项目

    小白一枚,今年(2019)准备学习一下前端的技术,因为发现自己对后端(python)相对比较熟悉但是还是写不出一个优雅的系统,可见前端的重要性,于是静下心学习。...

    泽阳
  • 七个开源的 Spring Boot 前后端分离项目,一定要收藏!

    原文链接:https://blog.csdn.net/u012702547/article/details/10097...

    ccf19881030
  • React VS Vue:2020年应该选哪个?[每日前端夜话0xD3]

    Javascript 框架以及 HTML 和 CSS 已成为每个现代软件项目前端开发的重要组成部分。2020 年将会是为你的 Web 项目选择正确的 javas...

    疯狂的技术宅

扫码关注云+社区

领取腾讯云代金券