Add classes to adjacent elements dynamically on mouseenter

女生的网名这么多〃 提交于 2019-12-08 03:39:41

问题


I'm creating a grid of elements and have a hover effect in place, using CSS transitions, for each element. I'd like to add secondary effects on adjacent x- and y-axis elements as well, creating a cloud effect. I imagine I'll be referencing those elements using jQuery's next() and prev() methods, or by $index and $parent.$index.

The grid area will be large enough to prevent row-wrapping (using negative margins and hidden overflow).

Here's a simplified example of my repeat:

<div class="activity-thumb-row" ng-repeat="i in getNumArray(20) track by $index">
    <div class="activity-thumb"
       ng-class="{'adjacent': adjacent}"
       ng-repeat="j in getNumArray(30) track by $index"
       ng-mouseenter="highlightActivities()">
    </div>
</div>

And a function in the controller (which I realize may not be the best approach):

$scope.highlightActivities = function() {
    $(this).next().adjacent = true;
    $(this).prev().adjacent = true;
}

How can I target elements adjacent to the hovered element using ng-class (or something else) inside ng-repeat?

Here's a fiddle for fiddling.

For reference, here are some related discussions:

  • Change class on mouseover in directive
  • Angular js ng repeat with conditional ng class not applying css class
  • ng-mouseover and leave to toggle item using mouse in angularjs

回答1:


Here's a directive that calculates all of the indices of adjacent cells and adds the adjacent class using jQuery only ... not ng-class.

Assumes that rows will wrap , would need adjusting for individual row elements

.directive('activityThumb', function() {
  return {
    restrict: 'C',
    link: function(scope, elem) {
      elem.bind('mouseenter', function(e) {

        var elW = elem.width(),
            $parent =elem.parent(),
            parentW = $parent.width(),
            $items = $parent.children(),
            numItems =$items.length
            itemsPerRow = Math.floor(parentW / elW),
            idx = elem.index(),
            rowIndex = idx % itemsPerRow;
        /* object of various indices , easy to inspect*/
        var adjacentIdx = {
          top:     idx > itemsPerRow ? idx - itemsPerRow : false,
          right:   rowIndex != itemsPerRow ? idx + 1 : false,
          left:    rowIndex > 0 ? idx - 1 : false,
          bottom:  (numItems - idx) > itemsPerRow ? idx + itemsPerRow : false
        }
        console.dir(adjacentIdx);
        $items.removeClass('adjacent')
        $.each(adjacentIdx, function(position, index){
          if(index !== false){
            $items.eq(index).addClass('adjacent');
          }
        });

      });
    }
  }

});

It wouldn't take much tweaking to remove jQuery dependency either.

Also would need additional directive on parent to remove extra classes when mouse leaves the main parent from one of the edges

DEMO




回答2:


First, it's not a good idea to deal with DOM elements in the controller.

Also, this problem seems to be mostly styling related, and not functionality related. I would thus try to keep the logic in the View and not in the controller.

There are 2 ways to deal with View-specific logic: 1) using custom directives or 2) View-defined scope variables

The second approach can work here and seems like the cheapest approach, but also a bit ugly. It ng-inits the rowHighlight array in the scope and sets which element is highlighted:

<div ng-repeat="i in getNumArray(20) track by $index" ng-init="rowHighlight = []">
    <div class="activity-thumb"
       ng-repeat="j in getNumArray(30) track by $index"
       ng-class="{'adjacent': rowHighlight[$index-1] || rowHighlight[$index+1]}"
       ng-mouseenter="rowHighlight[$index] = true" 
       ng-mouseleave="rowHighlight[$index] = false">
    </div>
</div>

updated fiddle



来源:https://stackoverflow.com/questions/28096039/add-classes-to-adjacent-elements-dynamically-on-mouseenter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!