我尝试创建一个元素,用户可以将鼠标悬停在拖动元素的同时慢慢向下滚动页面。这对于支持我的Drag-& -Drop编辑器是必要的。
我检测用户是否悬停在锚点上并且正在拖动,如果是,我启动$interval
我开始慢速滚动。如果鼠标离开锚点,或者用户停止拖动,则应取消慢速滚动,但不是。以下是我的代码。
elem.on('dragover', mouseOver);
elem.on('dragleave', mouseLeave);
elem.on('dragend', mouseLeave);
var scroller = null;
function mouseOver(ev) {
ev.preventDefault();
console.log('over');
scroller = $interval(function () {
if (!scrolledToBottom()) {
$(window).scrollTop($(window).scrollTop() + 1);
}
}, 10);
}
function mouseLeave(ev) {
ev.preventDefault();
console.log('left');
$interval.cancel(scroller);
scroller = null;
}
function scrolledToBottom() {
return ($(window).scrollTop() + $(window).height()) ==
$(document).height();
}
即使console.log
发射得很好,滚动条也永远不会停止滚动。我认为这是因为Angular无法在事件内部看到它被触发并且无法将更改应用于滚动条。但是,Angular没有ngDragOver
,我只能想到JQuery的实现。
有什么建议吗?
答案 0 :(得分:1)
您的代码存在的问题是您注册了类似的事件
elem.on('dragover', mouseOver)
,elem.on('dragleave', mouseLeave)
和elem.on('dragend', mouseLeave)
以及During the operations, several event types are fired and some event types might be fired many times (for example the drag and dragover event types).
例如,您的dragover
事件处理程序如下所示:
function mouseOver(ev) {
ev.preventDefault();
console.log('over');
scroller = $interval(function () {
if (!scrolledToBottom()) {
$(window).scrollTop($(window).scrollTop() + 1);
}
}, 10);
}
因此,上述事件处理程序将多次触发$interval
多次注释,并将松散对旧承诺的引用。
使用以下检查修复此问题:
var scroller = null;
function mouseOver(ev) {
ev.preventDefault();
console.log('over');
if (scroller === null) { // <-- This check will prevent multiple $interval registration.
scroller = $interval(function () {
if (!scrolledToBottom()) {
$(window).scrollTop($(window).scrollTop() + 1);
}
}, 10);
}
}
我会删除elem.on('dragleave', mouseLeave)
事件处理程序注册调用作为此事件处理程序,如果在启动元素拖动时也会调用注册。从而取消了自定义scoll
逻辑。
此外,我建议更改您的dragend
事件处理程序,以便在取消$interval
之前进行检查,例如(这仅用于代码清晰度):
function mouseLeave(ev) {
ev.preventDefault();
if (scroller !== null) { // <-- Make a check before cancelling the
$interval.cancel(scroller);
scroller = null;
}
}
这是一个尝试的实例:
angular.module('myApp', [])
.directive('drag', function($interval) {
return {
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
elem.on('dragover', mouseOver);
elem.on('dragend', mouseLeave);
var scroller = null;
function mouseOver(ev) {
ev.preventDefault();
if (scroller === null) {
scroller = $interval(function() {
if (!scrolledToBottom()) {
$(window).scrollTop($(window).scrollTop() + 1);
}
}, 10);
}
}
function mouseLeave(ev) {
ev.preventDefault();
if (scroller !== null) {
$interval.cancel(scroller);
scroller = null;
}
}
function scrolledToBottom() {
return ($(window).scrollTop() + $(window).height()) ==
$(document).height();
}
}
}
});
&#13;
.container {
padding: 0;
margin: 0;
background: blue;
height: 800px;
}
.container .drag {
height: 300px;
}
.container .drag a {
color: white;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js "></script>
<div ng-app="myApp">
<div class="container">
<div class="drag">
<a href="" drag>Drag Me</a>
</div>
</div>
</div>
&#13;