You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于jQuery长按插件实现关联时长的自定义动画

解决jQuery长按插件随时长变化的自定义动画问题

我明白你的痛点——原来的长按插件只在长按完成后触发回调,所以你尝试的类添加或者CSS steps动画根本没法在长按过程中实时生效。问题的核心是:我们需要在长按的持续过程中,实时追踪已按下的时长,并把这个时长转化为动画进度,而不是等结束才一次性处理。

原插件的局限性

不管是原版还是你的更新版,核心逻辑都是用setTimeout在指定时长后触发长按完成的回调。这种方式只能在“结束”节点执行操作,无法捕捉长按过程中的每一刻状态,自然没法驱动随时间变化的动画。

修改思路:添加实时进度追踪

我们可以在用户按下(mousedown/touchstart)时启动一个重复定时器(比如每10ms执行一次),每次计算当前已长按的时间占总时长的比例,再用这个比例来控制动画参数(比如背景色、宽度、透明度等)。当长按取消或完成时,再清除这个定时器。

修改后的完整插件代码

基于你的更新版插件,我添加了实时进度追踪的逻辑:

(function($) {
    $.fn.longpress = function(longCallback, duration) {
        // 设置默认参数
        let defaults = {
            click: function(el, e) {},
            start: function(el, e) {
                el.css("color", "#000");
            },
            // 新增:实时更新动画的回调,参数是当前长按进度(0到1之间)
            progress: function(el, e, ratio) {
                // 默认实现:背景色从#fff过渡到#000
                const r = Math.floor(255 * (1 - ratio));
                const g = Math.floor(255 * (1 - ratio));
                const b = Math.floor(255 * (1 - ratio));
                el.css("backgroundColor", `rgb(${r}, ${g}, ${b})`);
            },
            complete: function(el, e) {
                el.css("color", "#FFF");
                // 长按完成后固定背景色为#000
                el.css("backgroundColor", "#000");
            },
            cancel: function(el, e) {
                el.css("color", "#F00");
                // 取消后恢复背景色为#fff
                el.css("backgroundColor", "#fff");
            },
            duration: 1000
        };

        // 合并用户配置
        let options = $.extend({}, defaults);
        // 如果传入了duration,覆盖默认值
        if (typeof duration === "number") {
            options.duration = duration;
        }

        return this.each(function() {
            var $this = $(this);
            var mouse_down_time;
            var timeout;
            var progressInterval; // 新增:实时进度的定时器

            $this.data("clicked", "false");

            // 按下时的回调
            function mousedown_callback(e) {
                options.start($this, e);
                $this.data("clicked", "true");
                mouse_down_time = new Date().getTime();
                var context = $(this);

                // 启动实时进度定时器:每10ms更新一次
                progressInterval = setInterval(function() {
                    const press_time = new Date().getTime() - mouse_down_time;
                    // 计算进度比例,最大为1(避免超过总时长后继续变化)
                    const progressRatio = Math.min(press_time / options.duration, 1);
                    // 调用进度回调,传递当前比例
                    options.progress($this, e, progressRatio);
                }, 10);

                // 原有的长按完成定时器
                timeout = setTimeout(function() {
                    if (typeof longCallback === "function") {
                        longCallback.call(context, e);
                        options.complete($this, e);
                        $this.data("clicked", "false");
                        // 完成后清除进度定时器
                        clearInterval(progressInterval);
                    } else {
                        $.error('Callback required for long press. You provided: ' + typeof longCallback);
                    }
                }, options.duration);
            }

            // 松开时的回调
            function mouseup_callback(e) {
                var press_time = new Date().getTime() - mouse_down_time;
                if (press_time < options.duration) {
                    clearTimeout(timeout);
                    // 取消进度定时器
                    clearInterval(progressInterval);
                    $this.data("clicked", "false");
                    options.click($this, e);
                    // 短按后恢复初始状态
                    options.cancel($this, e);
                } else {
                    // 如果长按时间刚好达标,确保清除进度定时器
                    clearInterval(progressInterval);
                }
            }

            // 移动时取消长按的回调
            function move_callback(e) {
                let isClicked = $this.data("clicked");
                if (isClicked == "false") return;
                options.cancel($this, e);
                clearTimeout(timeout);
                // 取消进度定时器
                clearInterval(progressInterval);
                $this.data("clicked", "false");
            }

            // 绑定事件
            $this.on('mousedown', mousedown_callback);
            $this.on('mouseup', mouseup_callback);
            $this.on('mousemove', move_callback);
            $this.on('touchstart', mousedown_callback);
            $this.on('touchend', mouseup_callback);
            $this.on('touchmove', move_callback);
        });
    };
}(jQuery));

使用示例

你可以直接调用这个插件,甚至自定义progress回调来实现不同的动画效果:

// 示例1:默认背景色过渡(#fff到#000)
$("#myElement").longpress(function() {
    // 长按完成后的逻辑
    alert("长按完成!");
}, 2000); // 长按时长设为2秒

// 示例2:自定义进度动画(比如宽度从100%到50%)
$("#anotherElement").longpress(function() {
    alert("长按完成!");
}, {
    duration: 1500,
    progress: function(el, e, ratio) {
        // 宽度从100%过渡到50%
        const width = 100 - (50 * ratio);
        el.css("width", `${width}%`);
    },
    complete: function(el) {
        el.css("width", "50%");
    },
    cancel: function(el) {
        el.css("width", "100%");
    }
});

额外优化建议

  • 如果想要更流畅的动画,可以把setInterval换成requestAnimationFrame,它会根据浏览器的刷新频率来执行,性能更好。
  • 可以通过CSS变量(--progress)来控制动画,这样能把样式逻辑和JS分离,比如在progress回调里设置el.css("--progress", ratio),然后在CSS里写background: linear-gradient(#000, #fff) calc(var(--progress)*100%) 0/100% 100% no-repeat;。

内容的提问来源于stack exchange,提问作者markb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:40:59