CSS/JS: Наведите курсор на элемент, чтобы выделить другой элемент

Я создаю сетку, которая может иметь n rows и разделен на два представления: leftChild и rightChild. LeftChild имеет то же количество строк, что и rightChild, но leftChild остается на своем месте. Единственное отличие с rightChild в том, что его можно прокручивать по горизонтали. Когда я наводю курсор мыши на элемент leftChild или rightChild, я хочу добавить какой-либо эффект зависания... это легко, но я хочу добавить эффект зависания по всей строке. Поэтому, если я наведу курсор на 3-й ряд в leftChild, я хочу выделить 3-й ряд в rightChild.

Теперь, в идеале, я хотел бы иметь полное CSS-решение, похожее на это, но это невозможно, потому что мои строки не следуют непосредственно друг за другом. Я пытался придумать другой способ решения этой проблемы, но это не представляется возможным с прямым CSS.

Введите JavaScript. Я думаю, что следующий шаг - объединить JavaScript с CSS. Я могу добавить эффект наведения на строку, а затем использовать JavaScript, чтобы добавить класс наведения к соответствующей строке в другом дочернем элементе. Это довольно просто с jQuery, но я ищу нативный подход JavaScript.

Основной подход, о котором я думаю, - это добавить mouseenter а также mouseleave на каждом элементе класса строки. Мне не очень нравится этот подход, потому что тогда я устанавливаю 2 слушателя событий на каждый элемент строки... что кажется немного неэффективным. В любом случае, когда вы вводите, вы берете номер строки того, что вы зависли, а затем добавляете класс наведения ко всем этим элементам номера строки. Когда вы уходите, вы просто находите все элементы при наведении курсора и удаляете соответственно. Соответствующий код выглядит следующим образом:

HTML

<body onload="loaded()">
    <div id="parent">
        <div id="leftChild">
            <div>left child</div>
            <div class="row row1">some content</div>
            <div class="row row2">other content</div>
            <div class="row row3">more content</div>
        </div>
        <div id="rightChild">
            <div>right child</div>
            <div class="row row1">
                <span class="col1">column 1 content</span>
                <span class="col2">column 2 content</span>
                <span class="col3">column 3 content</span>
                <span class="col4">column 4 content</span>
                <span class="col5">column 5 content some really long content to trigger scrolling just for the purpose of this example</span>
            </div>
            <div class="row row2">
                <span class="col1">column 1 content</span>
                <span class="col2">column 2 content</span>
                <span class="col3">column 3 content</span>
                <span class="col4">column 4 content</span>
                <span class="col5">column 5 content some really long content to trigger scrolling just for the purpose of this example</span>
            </div>
            <div class="row row3">
                <span class="col1">column 1 content</span>
                <span class="col2">column 2 content</span>
                <span class="col3">column 3 content</span>
                <span class="col4">column 4 content</span>
                <span class="col5">column 5 content some really long content to trigger scrolling just for the purpose of this example</span>
            </div>
        </div>
    </div>
</body>

JS

function loaded() {
    /*var parent = document.getElementById('parent');
    parent.onmouseenter = function(event) {
        console.log(event.target);
    };
    parent.onmouseleave = function(event) {
        console.log(event.target);
    };*/

    var rows = document.getElementsByClassName('row');
    for (var i = 0; i < rows.length; i++) {
        rows[i].onmouseenter = function(event) {
            var splits = event.target.className.split(" ");
            var elems = document.getElementsByClassName(splits[splits.length - 1]);
            for (var j = 0; j < elems.length; j++) {
                elems[j].className += " hover";
            }
        };

        rows[i].onmouseleave = function(event) {
            var hovers = document.getElementsByClassName('hover');
            var len = hovers.length;
            for (var j = 0; j < len; j++) {
                hovers[0].className = hovers[0].className.replace(/\shover(\s|$)/, '');
            }
        };
    }
}

CSS

.row:hover, .hover {
    background-color: lightblue;
}

.row {
    height: 50px;
    padding: 5px;
    white-space: nowrap;
}

.row > span {
    display: inline-block;
    border: 5px solid black;
}

#leftChild, #rightChild {
    float: left;
}

#rightChild {
    width: 300px;
    overflow: auto;
}

#rightChild .row {
    display: inline-block;
}

jsFiddle: здесь

Так что я хотел бы знать несколько вещей.

  1. Это возможно только с прямым CSS?
  2. Если нет, как я могу сделать свой подход более эффективным?
  3. Является ли более эффективным иметь один обработчик событий или несколько обработчиков событий?

Я знаю, что здесь много спрашиваю, но я ненавижу задавать несколько вопросов, особенно если мне придется повторяться. Буду признателен за любую помощь. Спасибо!

2 ответа

Решение

Основанный на этом jsPerf, прямой JavaScript-подход, который у меня есть, является самым быстрым, гибридный подход занимает второе место - и я имею в виду очень близко к нативному подходу JS - и (почти полностью) подход jQuery приходит в тупик последний - и это действительно медленно по сравнению с двумя другими.

Все это можно увидеть на этом jsFiddle.

JS

// Native JS approach... fastest (according to my jsPerf http://jsperf.com/removeclass-vs-native-js-remove-class/2)
function loaded() { 
    var rows = document.getElementsByClassName('row');
    for (var i = 0; i < rows.length; i++) {
        rows[i].onmouseenter = function(event) {
            var row = this.className.match(/row-[\d]+/);
            var elems = document.getElementsByClassName(row[0]);
            for (var j = 0; j < elems.length; j++) {
                elems[j].className += " hover";
            }
        };

        rows[i].onmouseleave = function(event) {
            var hovers = document.getElementsByClassName('hover');
            var len = hovers.length;
            for (var j = 0; j < len; j++) {
                hovers[0].className = hovers[0].className.replace(/\shover(\s|$)/, '');
            }
        };
    }
}

// jQuery approach (slowest)
/*$(document).ready(function() {
    $('.row').on('mouseenter', function(event) {
        var row = this.className.match(/row-[\d]+/);
        $('.' + row).addClass('hover');
    });

    $('.row').on('mouseleave', function(event) {
        $('.hover').removeClass('hover');
    });
});*/

// Hybrid approach (basically as fast as native JS approach)
/*$(document).ready(function() {
    var rows = document.getElementsByClassName('row');
  for (var i = 0; i < rows.length; i++) {
    rows[i].onmouseenter = function(event) {
      var row = this.className.match(/row-[\d]+/);
      $('.' + row[0]).addClass('hover');
    };

        rows[i].onmouseleave = function(event) {
            $('.hover').removeClass('hover');
        };
    }
});*/
  1. через css с такой структурой: нет, не раньше, чем можно использовать css уровень 4.
  2. использование this и проверить на className добавить к нему пока новое правило
  3. зависание мыши и уход мыши?

я получаю это: через JQuery, но для теста я удалил класс .row и сохранил пронумерованный

$("[class*='row']").hover(
  function () {
      $('head').append('<style class="'+this.className+'" rel="stylesheet" > .'+this.className+' {background-color:lightblue;} </style>'); 
$(this).mouseleave(function() {  $('style.'+this.className).remove();});
});

http://codepen.io/gcyrillus/pen/bhglr

Другие вопросы по тегам