【问题标题】:How to highlight drop zone under draggable element using angularJS?如何使用angularJS突出显示可拖动元素下的拖放区?
【发布时间】:2015-10-25 13:02:03
【问题描述】:

当拖动的元素位于其上方时,我无法突出显示放置区域(使用 dropZone 指令定义)。

我尝试过使用 CSS:

.highlight {
    background-color: rgba(0, 255, 0, 0.2);
}
.highlight:hover {
    background-color: rgba(0, 255, 0, 0.5);
}

但这不起作用,因为我正在拖动一个元素,所以hover 在可拖动元素上。

代码如下:

var app = angular.module("myApp", []);

app.directive("dragCopy", function($http, $compile, $document) {
  return {
    restrict: 'A',
    link: function($scope, $element) {
      $element.on("mousedown", function($event) {
        $event.preventDefault();

        var newNode = $compile('<div class="dragFile" draggable-file>drag</div>')($scope);

        newNode.children("#title").text($element.parent().text());

        angular.element($document[0].body).append(newNode);
        newNode.css({
          top: $event.pageY - (newNode.prop("offsetHeight") * 0.9) + "px",
          left: $event.pageX - (newNode.prop("offsetWidth") / 2) + "px",
        });

        newNode.triggerHandler("mousedown");
      });
    }
  }
});

app.factory("dragDropService", function() {
  var object = {
    dropZoneList: [],
    highlightList: [],
    register: function(element) {
      object.dropZoneList.push(element);
    },
    highlightDropZones: function() {
      for (var i in object.dropZoneList) {
        var element = object.dropZoneList[i].append('<div class="highlight"></div>');
        var childrens = element.children();

        object.highlightList.push(childrens[childrens.length - 1]);
      }
    },
    resetDropZones: function() {
      for (var i in object.highlightList) {
        object.highlightList[i].remove();
      }
    }
  };

  return object;
});

app.directive("dropZone", function(dragDropService) {
  return {
    restrict: 'A',
    link: function($scope, $element) {
      dragDropService.register($element);
    }
  };
});

app.directive("draggableFile", function($document, dragDropService) {
  return {
    restrict: 'A',
    link: function($scope, $element) {
      var startX = 0,
        startY = 0;
      var x, y;

      $element.on("mousedown", function($event) {
        dragDropService.highlightDropZones();

        startX = $element.prop("offsetWidth") / 2;
        startY = $element.prop("offsetHeight") * 0.9;

        $document.on("mousemove", mousemove);
        $document.on("mouseup", mouseup);
      });

      function mousemove($event) {
        y = $event.pageY - startY;
        x = $event.pageX - startX;
        $element.css({
          top: y + "px",
          left: x + "px"
        });
      }

      function mouseup() {
        $document.off("mousemove", mousemove);
        $document.off("mouseup", mouseup);
        $element.remove();

        console.log(document.elementFromPoint(x, y));

        dragDropService.resetDropZones();
      }
    }
  }
});
.itemDrag {
  cursor: pointer;
  border: 3px solid #81CFE0;
  border-radius: 50%;
  font-size: 40px;
  color: #81CFE0;
  padding: 5px;
  background-color: rgba(255, 255, 255, 0.5);
}
#receiver {
  position: absolute;
  left: 50%;
  right: 0;
  top: 0;
  bottom: 0;
}
.dragFile {
  position: absolute;
  border: 1px solid #81CFE0;
  border-radius: 5px;
  background-color: rgba(129, 207, 224, 0.5);
  cursor: pointer;
}
.highlight {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  color: #00FF00;
  border: 3px dashed #00FF00;
  border-radius: 5px;
  text-align: center;
  font-weight: bold;
  text-shadow: 0px 0px 2px black;
  background-color: rgba(0, 255, 0, 0.2);
}
.highlight:before {
  content: "Add content to terminal";
}

.highlight:hover {
  background-color: rgba(0, 255, 0, 0.5);
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  <div class="itemDrag fa fa-hand-pointer-o" drag-copy></div>
  <div id="receiver" drop-zone></div>
</div>

只能使用 CSS 吗?

【问题讨论】:

    标签: javascript css angularjs drag-and-drop


    【解决方案1】:

    我找到了解决问题的方法。感谢您的回答,我找到了另一种方法。

    我正在收听dropZone 指令上的mousemove 事件。这样,如果鼠标在放置区域内移动,它将触发并添加样式。

    这是工作代码:

    var app = angular.module("myApp", []);
    
    app.directive("dragCopy", function($http, $compile, $document) {
      return {
        restrict: 'A',
        link: function($scope, $element) {
          $element.on("mousedown", function($event) {
            $event.preventDefault();
    
            var newNode = $compile('<div class="dragFile" draggable-file>drag</div>')($scope);
    
            newNode.children("#title").text($element.parent().text());
    
            angular.element($document[0].body).append(newNode);
            newNode.css({
              top: $event.pageY - (newNode.prop("offsetHeight") * 0.5) + "px",
              left: $event.pageX - (newNode.prop("offsetWidth") / 2) + "px",
            });
    
            newNode.triggerHandler("mousedown");
          });
        }
      }
    });
    
    app.factory("dragDropService", function() {
      var object = {
        dropZoneList: [],
        callbackList: [],
        highlightList: [],
        register: function(element, callback) {
          object.dropZoneList.push(element);
          object.callbackList.push(callback);
        },
        highlightDropZones: function() {
          for (var i in object.dropZoneList) {
            object.dropZoneList[i].append('<div class="highlight"></div>');
    
            var childrens = object.dropZoneList[i].children();
    
            object.highlightList.push(childrens[childrens.length - 1]);
            object.callbackList[i]();
          }
        },
        resetDropZones: function() {
          for (var i in object.highlightList) {
            object.callbackList[i]();
            object.highlightList[i].remove();
          }
          object.highlightList = [];
        }
      };
    
      return object;
    });
    
    app.directive("dropZone", function($document, dragDropService) {
      return {
        restrict: 'A',
        link: function($scope, $element) {
          var highlighted = false;
    
          function toggleHover() {
            if (highlighted) {
              $document.off("mousemove", mousemove);
              highlighted = false;
            } else {
              $document.on("mousemove", mousemove);
              highlighted = true;
            }
          }
    
          function mousemove($event) {
            x = $event.pageX;
            y = $event.pageY;
    
            elementBounding = $element[0].getBoundingClientRect();
    
            console.log("in");
    
            if (x > elementBounding.left && x < elementBounding.right && y > elementBounding.top && y < elementBounding.bottom) {
              angular.element($element.children()[$element.children().length - 1]).addClass("droppable");
            } else {
              angular.element($element.children()[$element.children().length - 1]).removeClass("droppable");
            }
          }
    
          dragDropService.register($element, toggleHover);
        }
      };
    });
    
    app.directive("draggableFile", function($document, dragDropService) {
      return {
        restrict: 'A',
        link: function($scope, $element) {
          var startX = 0,
            startY = 0;
          var x, y;
    
          $element.on("mousedown", function($event) {
            dragDropService.highlightDropZones();
    
            startX = $element.prop("offsetWidth") / 2;
            startY = $element.prop("offsetHeight") * 0.5;
    
            $document.on("mousemove", mousemove);
            $document.on("mouseup", mouseup);
          });
    
          function mousemove($event) {
            x = $event.pageX - startX;
            y = $event.pageY - startY;
    
            $element.css({
              left: x + "px",
              top: y + "px"
            });
          }
    
          function mouseup() {
            $document.off("mousemove", mousemove);
            $document.off("mouseup", mouseup);
            $element.remove();
    
            console.log(document.elementFromPoint(x, y));
    
            dragDropService.resetDropZones();
          }
        }
      };
    });
    .itemDrag {
      cursor: pointer;
      border: 3px solid #81CFE0;
      border-radius: 50%;
      font-size: 40px;
      color: #81CFE0;
      padding: 5px;
      background-color: rgba(255, 255, 255, 0.5);
    }
    #receiver1 {
      position: absolute;
      left: 50%;
      right: 0;
      top: 0;
      bottom: 50%;
    }
    #receiver2 {
      position: absolute;
      left: 50%;
      right: 0;
      top: 50%;
      bottom: 0;
    }
    .dragFile {
      position: absolute;
      border: 1px solid #81CFE0;
      border-radius: 5px;
      background-color: rgba(129, 207, 224, 0.5);
      cursor: pointer;
    }
    .highlight {
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      color: #00FF00;
      border: 3px dashed #00FF00;
      border-radius: 5px;
      text-align: center;
      font-weight: bold;
      text-shadow: 0px 0px 2px black;
      background-color: rgba(0, 255, 0, 0.2);
    }
    .highlight:before {
      content: "Add content to terminal";
    }
    .highlight.droppable {
      background-color: rgba(0, 255, 0, 0.5);
    }
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div ng-app="myApp">
      <div class="itemDrag fa fa-hand-pointer-o" drag-copy></div>
      <div id="receiver1" drop-zone></div>
      <div id="receiver2" drop-zone></div>
    </div>

    【讨论】:

      【解决方案2】:

      您可以使用 document.elementFromPoint 来识别光标所在的元素。现在您只需验证它是否具有“highlight”类。

      btw - 如果你使用 translate 来移动元素图像,document.elementFromPoint 会有更好的结果,因为拖动的元素不会干扰。

      function mousemove($event) {
          y = $event.pageY - startY;
          x = $event.pageX - startX;
      
          var dropElement = document.elementFromPoint(x, y);
      
          console.log(dropElement.classList.contains('highlight'));
      
          $element.css({
              top : y + "px",
              left : x + "px"
          });
      }
      

      【讨论】:

      • 不太方便,我希望有一个完整的 CSS 解决方案。
      • 这是我所拥有的最好的。据我所知,当您的鼠标按下时,您无法将鼠标悬停在元素上,如果您将可拖动元素指针事件设置为无,它仍然不会激活悬停在其他元素上。
      【解决方案3】:

      只能使用 CSS 吗?

      事实上,由浏览器决定元素是否悬停。所以如果他说不,那么我不确定如果:hover:active 不会首先被触发,CSS 是否足够。

      无论如何,这是使用 Angular 内置行为的另一种 JS 解决方案:


      ngMouseenter + ngMouseleave

      将此添加到您的 CSS 中:

      .hovered {
        background-color: rgba(0, 255, 0, 0.5);
        cursor: pointer;
        z-index: 999;
      }
      

      然后在 dropZone 指令中使用 mouseentermouseleave 行为,如下所示:

      app.directive("dropZone", function(dragDropService) {
        return {
          restrict: 'A',
          link: function($scope, $element) {
            dragDropService.register($element);
      
            $element.bind("mouseenter", function(e){
               // if mouse's button is not clicked then we are not dragging
               if(e.buttons == 1 || e.buttons == 3){
                  $element.addClass('hovered');
               }
            });
      
            $element.bind("mouseleave", function(){
                $element.removeClass('hovered');
            });
      
          }
        };
      });
      

      这段代码展示了它是如何工作的:

      var app = angular.module("myApp", []);
      
      app.directive("dragCopy", function($http, $compile, $document) {
        return {
          restrict: 'A',
          link: function($scope, $element) {
            $element.on("mousedown", function($event) {
              $event.preventDefault();
      
              var newNode = $compile('<div class="dragFile" draggable-file>drag</div>')($scope);
      
              newNode.children("#title").text($element.parent().text());
      
              angular.element($document[0].body).append(newNode);
              newNode.css({
                top: $event.pageY - (newNode.prop("offsetHeight") * 0.9) + "px",
                left: $event.pageX - (newNode.prop("offsetWidth") / 2) + "px",
              });
      
              newNode.triggerHandler("mousedown");
            });
          }
        }
      });
      
      app.factory("dragDropService", function() {
        var object = {
          dropZoneList: [],
          highlightList: [],
          register: function(element) {
            object.dropZoneList.push(element);
          },
          highlightDropZones: function() {
            for (var i in object.dropZoneList) {
              var element = object.dropZoneList[i].append('<div class="highlight"></div>');
              var childrens = element.children();
      
              object.highlightList.push(childrens[childrens.length - 1]);
            }
          },
          resetDropZones: function() {
            for (var i in object.highlightList) {
              object.highlightList[i].remove();
            }
          }
        };
      
        return object;
      });
      
      app.directive("dropZone", function(dragDropService) {
        return {
          restrict: 'A',
          link: function($scope, $element) {
            dragDropService.register($element);
      
            $element.bind("mouseenter", function(e){
               if(e.buttons == 1 || e.buttons == 3){
                  $element.addClass('hovered');
               }
            });
      
            $element.bind("mouseleave", function(){
                $element.removeClass('hovered');
            });
          }
        };
      });
      
      app.directive("draggableFile", function($document, dragDropService) {
        return {
          restrict: 'A',
          link: function($scope, $element) {
            var startX = 0,
              startY = 0;
            var x, y;
      
            $element.on("mousedown", function($event) {
              dragDropService.highlightDropZones();
      
              startX = $element.prop("offsetWidth") / 2;
              startY = $element.prop("offsetHeight") * 0.9;
      
              $document.on("mousemove", mousemove);
              $document.on("mouseup", mouseup);
            });
      
            function mousemove($event) {
              y = $event.pageY - startY;
              x = $event.pageX - startX;
              $element.css({
                top: y + "px",
                left: x + "px"
              });
            }
      
            function mouseup() {
              $document.off("mousemove", mousemove);
              $document.off("mouseup", mouseup);
              $element.remove();
      
              console.log(document.elementFromPoint(x, y));
      
              dragDropService.resetDropZones();
            }
          }
        }
      });
      .itemDrag {
        cursor: pointer;
        border: 3px solid #81CFE0;
        border-radius: 50%;
        font-size: 40px;
        color: #81CFE0;
        padding: 5px;
        background-color: rgba(255, 255, 255, 0.5);
      }
      #receiver {
        position: absolute;
        left: 50%;
        right: 0;
        top: 0;
        bottom: 0;
      }
      .dragFile {
        position: absolute;
        border: 1px solid #81CFE0;
        border-radius: 5px;
        background-color: rgba(129, 207, 224, 0.5);
        cursor: pointer;
      }
      .highlight {
        position: absolute;
        top: 0;
        right: 0;
        left: 0;
        bottom: 0;
        color: #00FF00;
        border: 3px dashed #00FF00;
        border-radius: 5px;
        text-align: center;
        font-weight: bold;
        text-shadow: 0px 0px 2px black;
        background-color: rgba(0, 255, 0, 0.2);
      }
      .highlight:before {
        content: "Add content to terminal";
      }
      
      .hovered {
        background-color: rgba(0, 255, 0, 0.5);
        cursor: pointer;
        z-index: 999;
      }
      <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
      
      <div ng-app="myApp">
        <div class="itemDrag fa fa-hand-pointer-o" drag-copy></div>
        <div id="receiver" drop-zone></div>
      </div>

      【讨论】:

      • 虽然这个想法看起来不错,但效果不太好!颜色在拖动元素上方发生变化,而不是在拖放区域下方。鼠标停留在可拖动元素上也不会触发,向下拖动时必须向外移动。
      • 在可拖动区域内移动鼠标时,我必须添加 z-index: 999; 以修复 ngMouseenter 事件的奇怪异常行为。既然您提到了它,我认为它可能会更好地使用 ngMouseover 代替,或者使用不同的 CSS 方法。稍后我会尝试优化它。但我不明白第二部分,doesn't trigger if the mouse stays on the draggable element, it has to go outside when dragging down. 是什么意思?您的意思是当您将元素拖放到其中而不必将鼠标移出时,dragZone 应该再次变为空白吗?
      • Do you mean that dragZone should became blank again when you Drop the element inside and not having to move the mouse out of it ? - 这部分是。但我不是在谈论它。 mouseenter 事件仅在鼠标移动到on$element 时触发。因此,当鼠标位于可拖动元素上时,它不会显示 hovered 类。当我enter$element 时,我必须快速移动鼠标,以便它可以脱离可拖动元素并显示hovered 类。 (我使用 Firefox 来处理这种行为)
      • 嗯,我明白了。你是对的,不仅是 Chrome 中的 Firefox。除非您向下移动,否则当您缓慢进入内部时不会触发。我会弄清楚如何修复它并稍后进行更新。
      • 我尝试过的所有解决方案都没有像我预期的那样工作,即使是纯 JavaScript onmouseenter 在拖动时的行为几乎相同,我认为基于 XY 坐标的解决方案在这种情况下会工作得更好,因为即使我知道如何让它工作我需要修改更多的东西,比如 object.dropZoneList[i].append('&lt;div class="highlight"&gt;&lt;/div&gt;'); 这会破坏 mouseenter 事件,否则我需要使用元素 z-index attr 或重建指令可能像 this one,所以在最后我发现@OriDrori 的想法更好。
      猜你喜欢
      • 1970-01-01
      • 2012-04-10
      • 2018-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      相关资源
      最近更新 更多