问题
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-init
s 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