JS写不一样的悬停几秒后执行函数

大家好,我是 vortesnail。

前言:

最近这几个星期,一直都在维护自己的基于 React 的开源播放器组件,以为功能基本都差不多了,却忽视了播放器一个很重要的功能:鼠标悬停在视频播放界面时,在一定时间后鼠标会消失,视频下方的控制栏也会隐藏,呈现视频的最大可视化。但是鼠标稍微一动,一切恢复如初。用一张简单的 gif 图来说明的话,是下面这样子的: 有点犯难,它不是简单地移到元素(如视频)上,2秒后让它执行鼠标消失和控制栏消失的操作,因为一旦鼠标一动一点,都要恢复原样,不过好在结合 防抖的思想以及自己的一些思考,实现了这个功能,并将其封装为一个工具函数,可供大家使用,当然,其中也有不足,也请各位能给予意见,我会结合给的意见更新这篇博客。

开始:

如果你现在需要使用这个功能,你希望用起来尽量简单,并且能达到你的使用要求,思来想去,给你暴露 4 个参数最为妥当:

  • element:你所希望操作的元素(比如上面 gif 中 “我是视频”这个 div 元素)
  • secondsLaterDoFn:你设定的时间之后,想做什么操作(比如上面 gif 中“鼠标消失,控制栏消失”)
  • seconds:你希望的时间,单位:ms(比如上面 gif 中我设定的时间为 2000ms)
  • reNormalFn:回归原样的操作(比如上面 gif 中控制栏和鼠标都回来)

那么,我们现在写一个函数,把这四个参数传进去,并对传入的 element 写两个监听事件,以及我们的清除定时器函数:

function HoverSD(element, secondsLaterDoFn, seconds, reNormalFn) {
  var timeout;
  var ele = element, secondsLDF = secondsLaterDoFn, secs = seconds, reNFn = reNormalFn;

  var clearTimer = function() {
    timeout && clearTimeout(timeout);
  }

  this.secondsHoverEX = function() {
    ele.addEventListener('mousemove', rebuildTimer);
    ele.addEventListener('mouseleave', clearTimer);
  }
}

window.HoverSD = HoverSD;

你也发现了, rebuildTimerclearTimer是个啥玩意儿?别急。 我们整理一下思路:在鼠标移到这个元素上面之后,我们要有一个定时器,在设定的时间过后,执行操作,但是,我们在设定的时间之内,又移动了鼠标,这时候需要把之前设定的定时器清除,重新开一个定时器,重新计时,这里的思想和 防抖一模一样,于是我们初步的 rebuildTimer如下:

var rebuildTimer = function() {
  var context = this;
  var args = arguments;
  clearTimer();
  timeout = setTimeout(() => {
    secondsLDF.apply(context, args);
  }, secs);
}

意思就是,当我们 mousemove 的时候,就会执行 rebuildTimer函数,在这个函数内部,清除定时器,即每次移动之后,重新计时,执行 secondsLDF

可是我们传入的参数 reNormalFn(即 reNFn)并没有用到啊,它是用来恢复原状态的操作,我们直接插入在清除定时器之前就可以了。

var rebuildTimer = function() {
  var context = this;
  var args = arguments;

  reNFn.apply(context, args);

  clearTimer();
  timeout = setTimeout(() => {
    secondsLDF.apply(context, args);
  }, secs);
}

那我们在特定的时候想要移出这个元素的监听事件怎么办呢?比如在 React 中我们在 componentDidMount中用了,需要在 componentWillUnmount中去除监听事件,防止内存占用,那我们就需要再写一个移除事件的函数:

this.removeElemEventListener = function() {
  ele.removeEventListener('mousemove', rebuildTimer);
  ele.removeEventListener('mouseleave', clearTimer);
}

注意, removeEventListener的参数,必须与监听时候的执行函数完全相同,且 不能有参数,不能有参数,不能有参数!!!,我一开始就是写的有参数形式,怎么搞都搞不对。。。

现在把它封装成一个工具函数,放到 npm 上,直接安装使用,为了兼顾在不配置 webpack 情况下以及低版本浏览器情况下,我们可以这样来做:

// all code
function HoverSD(element, secondsLaterDoFn, seconds, reNormalFn) {
  var timeout;
  var ele = element, secondsLDF = secondsLaterDoFn, secs = seconds, reNFn = reNormalFn;

  var rebuildTimer = function() {
    var context = this;
    var args = arguments;
    reNFn.apply(context, args);
    clearTimer();
    timeout = setTimeout(() => {
      secondsLDF.apply(context, args);
    }, secs);
  }

  var clearTimer = function() {
    timeout && clearTimeout(timeout);
  }

  this.secondsHoverEX = function() {
    ele.addEventListener('mousemove', rebuildTimer);
    ele.addEventListener('mouseleave', clearTimer);
  }

  this.removeElemEventListener = function() {
    ele.removeEventListener('mousemove', rebuildTimer);
    ele.removeEventListener('mouseleave', clearTimer);
  }
}

window.HoverSD = HoverSD;

将主要的核心函数 secondsHoverEXremoveElemEventListener通过 this.暴露出来,再将这个函数暴露到 window 全局,安装之后可以直接通过

let hoversd = new window.HoverSD(elem, fn1, 2000, fn2);
hoversd.secondsHoverEX();
// ...
// other code here
// ...
hoversd.removeElemEventListener();

即可完成使用。

本篇文章收录于我的 个人blog,后续会致力于推出越来越多文章以及开源工具,如有帮助,赏个 star,谢谢各位老爷了!

后记:

非常感谢大家能看到最后,如果有朋友想要提出意见,欢迎来 github/issue给我提建议,也可在下方评论直接提出,我个人觉得这个工具函数适用的场景还是蛮多的,如果能帮助到你,欢迎来此项目下赏个 star。我会在项目主页关于此工具的使用做更详细的介绍,欢迎访问: github项目地址:https://github.com/vortesnail/hover-seconds-do

当然,厚着脸皮也希望大家能支持下我的基于 React 的开源播放器组件:https://github.com/vortesnail/qier-player下次再见,拜拜啦~

原文链接:segmentfault.com

上一篇:从 custom Hooks 到 shared Hooks :hox 原理分析
下一篇:用vue手写一个公式组件

相关推荐

  • 🙋Hanjst汉吉斯特改进+enSafeExpression安全表达式等

    Hanjst汉吉斯特模版语言及模版引擎,近期持续改进升级。 这次改进主要是增加了对安全输出表达式兼容,由于涉及到对软件开发过程中的效率和软件运行效率的平衡和取舍,所以多写了几句,以描述这个权衡利弊对...

    8 天前
  • 🙋Hanjst汉吉斯特升级:+showImageAsync及性能改进等

    自2019年元旦🙋Hanjst汉吉斯特 模板语言及其编译引擎发布,已经过去一年多了。 这期间随着 🙋Hanjst汉吉斯特 的推广应用,我们也陆续发布了如下一些更新内容: 🛠️Hanjst/汉吉...

    1 个月前
  • 😉我用 Nuxt.js 仿了个掘金

    前言 首先肯定是要夸夸掘金啦,最开始从 CSDN 到 博客园 再到 掘金,个人感觉掘金的技术氛围非常的nice,真是个宝藏社区👏。技术文章大多以前端为主,对前端开发者非常友好,质量也是歪瑞古的。

    18 天前
  • 😀一个原生js弹幕库

    danmujs 😀一个原生js弹幕库,基于 CSS3 Animation 地址、核心代码 本项目基于 rcbullets,项目约70%的代码基于rcbullets,首先要感谢这个项目的作者,如...

    4 个月前
  • 🕵️‍♀️由原型到JS中的“模拟类”

    讲述了有关 JavaScript 中原型相关知识,又引出了 JavaScript 中的“类“究竟是什么?,以及一系列相关问题。 一、前置知识 1、JavaScript 的面向对象(OOP) ​ 面向...

    2 个月前
  • 🔥《吊打面试官》系列 Node.js 必知必会必问!

    (/public/upload/f204a3b224d986128f1b4d9b8d06cd17) 前言 codeing 应当是一生的事业,而不仅仅是 30 岁的青春🍚 本文已收录 Git...

    2 个月前
  • 💖CSS + JS 送学妹满屏幕小爱心

    故事开始 午饭时间,暗恋已久的学妹拉着我的衣袖:“学长学长,你能不能让这些爱心变成五颜六色的吗~”。 我在旁边笑开了花~~~ image.png(/public/upload/04aaa24e...

    1 个月前
  • (vuejs学习)2、使用ElementUI(*)

    1.element安装 开发环境是win10,一到node官网下载node的.msi包(https://npm.taobao.org/mirrors/node/v10.16.0/nodev10.16....

    10 个月前
  • (vuejs学习)1、Vue初上手(*)

    参考《官方(https://cli.vuejs.org/zh/guide/installation.html)》官方: Node 版本要求: Vue CLI 需要 Node.js 8.9 或更高...

    10 个月前
  • 鼠标悬停和MouseEnter事件之间的区别是什么?

    (https://stackoverflow.comundefined)提出了一个问题:What is the difference between the mouseover and mouseen...

    2 年前

官方社区

扫码加入 JavaScript 社区