使用 jQuery 在拖动时滚动页面

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19743228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 00:32:43  来源:igfitidea点击:

Scroll the page on drag with jQuery

javascriptjqueryhtmlcsskineticjs

提问by ben

I have tried using kinetic.js and the code below, however when I try this in IE11 it keeps jumping to the top every time I scroll:

我曾尝试使用 kinetic.js 和下面的代码,但是当我在 IE11 中尝试时,每次滚动时它都会跳到顶部:

$("html").kinetic();

I want to make the page scrollable on tablets and IE10 and 11 so that users can just push the page up to scroll down as you would on mobile devices.

我想让页面在平板电脑和 IE10 和 11 上可滚动,以便用户可以像在移动设备上一样向上推页面向下滚动。

How can I do this in pure-JS or jQuery without it jumping to the top?

如何在纯 JS 或 jQuery 中执行此操作而不跳到顶部?

回答by Rory McCrossan

You can do this quite simply by recording the position of the mouse when clicked, and the current position when being dragged. Try this:

您可以通过记录单击时鼠标的位置和拖动时的当前位置来非常简单地完成此操作。尝试这个:

var clicked = false, clickY;
$(document).on({
    'mousemove': function(e) {
        clicked && updateScrollPos(e);
    },
    'mousedown': function(e) {
        clicked = true;
        clickY = e.pageY;
    },
    'mouseup': function() {
        clicked = false;
        $('html').css('cursor', 'auto');
    }
});

var updateScrollPos = function(e) {
    $('html').css('cursor', 'row-resize');
    $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
}

To prevent text selection while dragging, add the following CSS:

要防止拖动时选择文本,请添加以下 CSS:

body {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

Example fiddle

示例小提琴



Update

更新

Here's an version of the above as a jQuery plugin, extended to allow both vertical and horizontal scrolling via the settings. It also allows you to change the cursorthat's used too.

这是上述 jQuery 插件的一个版本,扩展为允许通过设置进行垂直和水平滚动。它还允许您更改使用的cursor那个。

(function($) {
  $.dragScroll = function(options) {
    var settings = $.extend({
      scrollVertical: true,
      scrollHorizontal: true,
      cursor: null
    }, options);

    var clicked = false,
      clickY, clickX;

    var getCursor = function() {
      if (settings.cursor) return settings.cursor;
      if (settings.scrollVertical && settings.scrollHorizontal) return 'move';
      if (settings.scrollVertical) return 'row-resize';
      if (settings.scrollHorizontal) return 'col-resize';
    }

    var updateScrollPos = function(e, el) {
      $('html').css('cursor', getCursor());
      var $el = $(el);
      settings.scrollVertical && $el.scrollTop($el.scrollTop() + (clickY - e.pageY));
      settings.scrollHorizontal && $el.scrollLeft($el.scrollLeft() + (clickX - e.pageX));
    }

    $(document).on({
      'mousemove': function(e) {
        clicked && updateScrollPos(e, this);
      },
      'mousedown': function(e) {
        clicked = true;
        clickY = e.pageY;
        clickX = e.pageX;
      },
      'mouseup': function() {
        clicked = false;
        $('html').css('cursor', 'auto');
      }
    });
  }
}(jQuery))

$.dragScroll();
/* Note: CSS is not relevant to the solution. 
   This is only needed for this demonstration */

body,
html {
  padding: 0;
  margin: 0;
}

div {
  height: 1000px;
  width: 2000px;
  border-bottom: 3px dashed #EEE;
  /* gradient is only to make the scroll movement more obvious */
  background: rgba(201, 2, 2, 1);
  background: -moz-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
  background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(201, 2, 2, 1)), color-stop(16%, rgba(204, 0, 204, 1)), color-stop(31%, rgba(94, 0, 201, 1)), color-stop(43%, rgba(0, 153, 199, 1)), color-stop(56%, rgba(0, 199, 119, 1)), color-stop(69%, rgba(136, 199, 0, 1)), color-stop(83%, rgba(199, 133, 0, 1)), color-stop(100%, rgba(107, 0, 0, 1)));
  background: -webkit-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
  background: -o-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
  background: -ms-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
  background: linear-gradient(-110deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
  filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#c90202', endColorstr='#6b0000', GradientType=1);
  color: #EEE;
  padding: 20px;
  font-size: 2em;
}

body {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>First...</div>

<div>Second...</div>

回答by Mark Anthony Uy

I just like to add. Using Rory's code I made horizontal scrolling.

我只是喜欢补充。我使用 Rory 的代码进行了水平滚动。

var clicked = false, base = 0;

$('#someDiv').on({
    mousemove: function(e) {
        clicked && function(xAxis) {
            var _this = $(this);
            if(base > xAxis) {
                base = xAxis;
                _this.css('margin-left', '-=1px');
            }
            if(base < xAxis) {
                base = xAxis;
                _this.css('margin-left', '+=1px');
            }
        }.call($(this), e.pageX);
    },
    mousedown: function(e) {
        clicked = true;
        base = e.pageX;
    },
    mouseup: function(e) {
        clicked = false;
        base = 0;
    }
});

回答by PariSh KhAn

This code will work on horizontal and vertical mouse drag scroll. It's pretty simple.

此代码适用于水平和垂直鼠标拖动滚动。这很简单。

var curYPos = 0,
    curXPos = 0,
    curDown = false;

window.addEventListener('mousemove', function(e){ 
  if(curDown === true){
    window.scrollTo(document.body.scrollLeft + (curXPos - e.pageX), document.body.scrollTop + (curYPos - e.pageY));
  }
});

window.addEventListener('mousedown', function(e){ curDown = true; curYPos = e.pageY; curXPos = e.pageX; });
window.addEventListener('mouseup', function(e){ curDown = false; }); 

回答by cn123h

Base on Rory McCrossan's idea, implemented with AngularJS2.

基于 Rory McCrossan 的想法,用 AngularJS2 实现。

import {Directive, ElementRef, OnDestroy, Input} from "@angular/core";

declare var jQuery: any;

@Directive({
    selector: '[appDragScroll]'
})
export class DragScrollDirective implements OnDestroy {

    @Input() scrollVertical: boolean = true;
    @Input() scrollHorizontal: boolean = true;

    private dragging = false;
    private originalMousePositionX: number;
    private originalMousePositionY: number;
    private originalScrollLeft: number;
    private originalScrollTop: number;

    constructor(private nodeRef: ElementRef) {
        let self = this;

        jQuery(document).on({
            "mousemove": function (e) {
                self.dragging && self.updateScrollPos(e);
            },
            "mousedown": function (e) {
                self.originalMousePositionX = e.pageX;
                self.originalMousePositionY = e.pageY;
                self.originalScrollLeft = jQuery(self.nodeRef.nativeElement).scrollLeft();
                self.originalScrollTop = jQuery(self.nodeRef.nativeElement).scrollTop();
                self.dragging = true;
            },
            "mouseup": function (e) {
                jQuery('html').css('cursor', 'auto');
                self.dragging = false;
            }
        });

    }

    ngOnDestroy(): void {
        jQuery(document).off("mousemove");
        jQuery(document).off("mousedown");
        jQuery(document).off("mouseup");
    }

    private updateScrollPos(e) {
        jQuery('html').css('cursor', this.getCursor());

        let $el = jQuery(this.nodeRef.nativeElement);
        if (this.scrollHorizontal) {
            $el.scrollLeft(this.originalScrollLeft + (this.originalMousePositionX - e.pageX));
        }
        if (this.scrollVertical) {
            $el.scrollTop(this.originalScrollTop + (this.originalMousePositionY - e.pageY));
        }
    }

    private getCursor() {
        if (this.scrollVertical && this.scrollHorizontal) return 'move';
        if (this.scrollVertical) return 'row-resize';
        if (this.scrollHorizontal) return 'col-resize';
    }

}

回答by ProgAndPlay

Based on the first answer, this is the code for horizontal scroll on mouse drag:

基于第一个答案,这是鼠标拖动水平滚动的代码:

var clicked = false, clickX;
$(document).on({
    'mousemove': function(e) {
        clicked && updateScrollPos(e);
    },
    'mousedown': function(e) {
        e.preventDefault();        
        clicked = true;
        clickX = e.pageX;
    },
    'mouseup': function() {
        clicked = false;
        $('html').css('cursor', 'auto');
    }
});

var updateScrollPos = function(e) {
    $('html').css('cursor', 'grabbing');
    $(window).scrollLeft($(window).scrollLeft() + (clickX - e.pageX));
}

回答by tycrek

I modified Rory's code quite a bit, and I got per-element side scrolling to work. I needed that for a project that had multiple scrollable tiles in a single view for a webapp. Add the .dragclass to any element, possibly do a bit of styling, and it should be good to go.

我对 Rory 的代码进行了相当多的修改,并且让每个元素的横向滚动都可以工作。对于在一个 web 应用程序的单个视图中具有多个可滚动图块的项目,我需要它。将.drag类添加到任何元素,可能会做一些样式,它应该很好。

// jQuery sidescroll code. Can easily be modified for vertical scrolling as well.
// This code was hacked together so clean it up if you use it in prod.
// Written by Josh Moore
// Thanks to Rory McCrossan for a good starting point

// How far away the mouse should move on a drag before interrupting click
// events (your own code must also interrupt regular click events with a
// method that calls getAllowClick())
const THRESHOLD = 32;
var clicked = false;
var allowClick = true;

// mouseX: most recent mouse position. updates when mouse moves.
//     el: jQuery element that will be scrolled.
//    thX: "threshold X", where the mouse was at the beginning of the drag
var mouseX, startY, el, thX;

// Add the .drag class to any element that should be scrollable.
// You may need to also add these CSS rules:
//   overflow: hidden; /* can be replaced with overflow-x or overflow-y */
//   whitespace: none;
function drag() {
    $('.drag').on({
        'mousemove': e => {
            if (el != null && clicked) {
                el.scrollLeft(el.scrollLeft() + (mouseX - e.pageX));
                mouseX = e.pageX;
                allowClick = Math.abs(thX - mouseX) > THRESHOLD ? false : true;
            }
        },
        'mousedown': e => {
            clicked = true;
            // This lets the user click child elements of the scrollable.
            // Without it, you must click the .drag element directly to be able to scroll.
            el = $(e.target).closest('.drag');
            mouseX = e.pageX;
            thX = e.pageX;
        },
        'mouseup': e => {
            clicked = false;
            el = null;
            allowClick = true;
        }
    });
}

function getAllowClick() {
    return allowClick;
}

Again, I had no use for vertical scrolling but it would be pretty simple to add (replace X's with Y's, scrollTop()instead of scrollLeft(), etc). Hope this helps someone in the future!

同样,我没有使用垂直滚动,但添加起来非常简单(用 Y 替换 X,scrollTop()而不是scrollLeft()等)。希望这对未来的人有所帮助!