2017-04-07 47 views
0

我正在尝试创建一个元素,用户可以将它们的鼠标放在缓慢向下滚动页面的同时拖动元素。这是支持我的Drag-& -Drop编辑器所必需的。DragOver和DragLeave AngularJS

我正在检测用户是否悬停在锚上并正在拖动,如果是这样,我开始$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

为什么你甚至需要定制滚动?如果您将元素拖出视口,则窗口滚动将自动发生。 – Gaurav

+0

对熟悉电脑的人来说,这是一个明智的回应,但恐怕我的用户不会。如果站点有固定的顶栏菜单,这也不适用于滚动备份。 – FvB

+0

好的,这是有道理的,但你应该记住要照顾任何其他可访问性问题,你会介绍(如果有的话)。无论如何,看看我发布的答案。 – Gaurav

回答

1

与您的代码的问题是,您已注册的事件,如 elem.on('dragover', mouseOver)elem.on('dragleave', mouseLeave)elem.on('dragend', mouseLeave)并作为doc mentionsDuring 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(); 
 
     } 
 
     } 
 
    } 
 

 
    });
.container { 
 
    padding: 0; 
 
    margin: 0; 
 
    background: blue; 
 
    height: 800px; 
 
} 
 

 
.container .drag { 
 
    height: 300px; 
 
} 
 

 
.container .drag a { 
 
    color: white; 
 
}
<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>

+0

完美!这有我需要的一切:) – FvB