Подтвердить что ты не робот

JQuery: выделить элемент под курсором мыши?

Возможный дубликат:
Как сделать этот JavaScript намного быстрее?

Я пытаюсь создать "сборщик элементов" в jQuery, например Firebug. В принципе, я хочу выделить элемент под пользовательской мышью. Вот что я получил до сих пор, но он работает не очень хорошо:

$('*').mouseover(function (event) {
    var $this = $(this);
    $div.offset($this.offset()).width($this.width()).height($this.height());
    return false;
});


var $div = $('<div>')
    .css({ 'background-color': 'rgba(255,0,0,.5)', 'position': 'absolute', 'z-index': '65535' })
    .appendTo('body');

В принципе, я вводил div в DOM, который имеет полупрозрачный фон. Затем я слушаю событие mouseover для каждого элемента, а затем перемещаю div так, чтобы он покрывал этот элемент.

Прямо сейчас, это просто делает всю страницу красной, как только вы наводите указатель мыши на страницу. Как я могу заставить это работать лучше?

Изменить:. По-видимому, проблема в том, что, как только моя мышь касается страницы, тело выбирается, а затем, когда я перемещаю мышь, ни один из моментов не проходит через высокий уровень потому что его верхняя часть всего.


Firebug

Копаясь через исходный код Firebug, я нашел это:

drawBoxModel: function(el)
{
    // avoid error when the element is not attached a document
    if (!el || !el.parentNode)
        return;

    var box = Firebug.browser.getElementBox(el);

    var windowSize = Firebug.browser.getWindowSize();
    var scrollPosition = Firebug.browser.getWindowScrollPosition();

    // element may be occluded by the chrome, when in frame mode
    var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0;

    // if element box is not inside the viewport, don't draw the box model
    if (box.top > scrollPosition.top + windowSize.height - offsetHeight ||
        box.left > scrollPosition.left + windowSize.width ||
        scrollPosition.top > box.top + box.height ||
        scrollPosition.left > box.left + box.width )
        return;

    var top = box.top;
    var left = box.left;
    var height = box.height;
    var width = box.width;

    var margin = Firebug.browser.getMeasurementBox(el, "margin");
    var padding = Firebug.browser.getMeasurementBox(el, "padding");
    var border = Firebug.browser.getMeasurementBox(el, "border");

    boxModelStyle.top = top - margin.top + "px";
    boxModelStyle.left = left - margin.left + "px";
    boxModelStyle.height = height + margin.top + margin.bottom + "px";
    boxModelStyle.width = width + margin.left + margin.right + "px";

    boxBorderStyle.top = margin.top + "px";
    boxBorderStyle.left = margin.left + "px";
    boxBorderStyle.height = height + "px";
    boxBorderStyle.width = width + "px";

    boxPaddingStyle.top = margin.top + border.top + "px";
    boxPaddingStyle.left = margin.left + border.left + "px";
    boxPaddingStyle.height = height - border.top - border.bottom + "px";
    boxPaddingStyle.width = width - border.left - border.right + "px";

    boxContentStyle.top = margin.top + border.top + padding.top + "px";
    boxContentStyle.left = margin.left + border.left + padding.left + "px";
    boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px";
    boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px";

    if (!boxModelVisible) this.showBoxModel();
},

hideBoxModel: function()
{
    if (!boxModelVisible) return;

    offlineFragment.appendChild(boxModel);
    boxModelVisible = false;
},

showBoxModel: function()
{
    if (boxModelVisible) return;

    if (outlineVisible) this.hideOutline();

    Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel);
    boxModelVisible = true;
}

Похоже, что они используют стандартный div + css для рисования..... просто нужно выяснить, как они обрабатывают события сейчас... (этот файл длиной 28K)

Там также этот фрагмент, который, я думаю, извлекает соответствующий объект... хотя я не могу понять, как это сделать. Они ищут класс "objectLink-element"... и я не знаю, что такое "repObject".

onMouseMove: function(event)
{
    var target = event.srcElement || event.target;

    var object = getAncestorByClass(target, "objectLink-element");
    object = object ? object.repObject : null;

    if(object && instanceOf(object, "Element") && object.nodeType == 1)
    {
        if(object != lastHighlightedObject)
        {
            Firebug.Inspector.drawBoxModel(object);
            object = lastHighlightedObject;
        }
    }
    else
        Firebug.Inspector.hideBoxModel();

},

Я думаю, что, возможно, когда событие mousemove или mouseover срабатывает для маркера node, я могу как-то передать его вместо этого? Может быть, для node это покрытие...?


Если я помещаю невидимый элемент над каждым элементом с более высоким z-индексом, чем мой маркер, но дайте моему маркеру более высокий индекс z, чем фактические элементы... теоретически, он должен работать. Невидимые элементы будут отключать событие мыши, но эффект выделения будет по-прежнему выглядеть как верхняя часть фактических элементов.

Это означает, что я только удвоил элементы DOM, и позиционирование должно быть правильным. Если, может быть, я только "подниму" элементы, которые в настоящее время покрывает маркер? Но это все равно может быть каждый элемент > . < Кто-то мне поможет!

4b9b3361

Ответ 1

Все эти ответы слишком сложны... Простое решение:

JavaScript:

prevElement = null;
document.addEventListener('mousemove',
    function(e){
        var elem = e.target || e.srcElement;
        if (prevElement!= null) {prevElement.classList.remove("mouseOn");}
        elem.classList.add("mouseOn");
        prevElement = elem;
    },true);

Css:

.mouseOn{
  background-color: #bcd5eb !important;
  outline: 2px solid #5166bb !important;
}

Ответ 2

Чтобы изменить ответ Дэвида так, чтобы он правильно возвращал цвета фона...

$('body *').live('mouseover mouseout', function(event) {
    if (event.type == 'mouseover') {
        $(this).data('bgcolor', $(this).css('background-color'));
        $(this).css('background-color','rgba(255,0,0,.5)');
    } else {
        $(this).css('background-color', $(this).data('bgcolor'));
    }
    return false;
});

Ответ 3

Можно ли предложить альтернативный подход?

Как просто назначить background-color всем дочерним элементам страницы, а затем, на hover(), отрегулировать background-color этого элемента, чтобы увеличить его контраст?

$('html').children().css('background-color','rgba(0,0,0,0.2)');
$('body').children().hover(
    function(){
        $(this).css('background-color','#fff');
    },
    function(){
        $(this).css('background-color','rgba(0,0,0,0.2)');
    });

JS Fiddle demo.

Ответ 4

Причина, по которой вся страница становится красной, как только вы наводите указатель мыши на то, что ваш код соответствует событию mouseover для элемента body. Вы можете остановить это, только выбрав детей body.

$('body *').bind( //...

Вы столкнетесь с проблемами производительности на странице с большим количеством элементов, хотя, поскольку bind будет присоединять слушатель для каждого отдельного элемента. Попробуйте взглянуть на делегирование события jQuery api (.delegate(), http://api.jquery.com/delegate/), который позволяет прослушивать события, распространяющиеся до корневого элемента и работает также для событий мыши.

Ответ 5

► Этот немного менее суетлив, но он не может обнаружить переход от родительского элемента к одному его детей без предварительного перемещения мыши от указанного родителя.

var $div = $('<div id="highlighter">').css({
    'background-color': 'rgba(255,0,0,.5)',
    'position': 'absolute',
    'z-index': '65535'
}).hide().prependTo('body');

var $highlit;

$('*').live('mousemove', function(event) {
    if (this.nodeName === 'HTML' || this.nodeName === 'BODY')
    {
        $div.hide();
        return false;
    }
    var $this = this.id === 'highligher' ? $highlit : $(this),

        x = event.pageX,
        y = event.pageY,

        width = $this.width(),
        height = $this.height(),
        offset = $this.offset(),

        minX = offset.left,
        minY = offset.top,
        maxX = minX + width,
        maxY = minY + height;

    if (this.id === 'highlighter')
    {
        if (minX <= x && x <= maxX
            && minY <= y && y <= maxY)
        {
            // nada
        }
        else
        {
            $div.hide();
        }
    }
    else
    {
        $highlit = $this;
        $div.offset(offset).width($this.width()).height($this.height()).show();
    }
    return false;
});

Надеюсь, это поможет получить мяч. Вероятно, вы могли бы настроить то, что я написал, чтобы использовать document.elementFromPoint(x, y), чтобы проверить, переместилась ли мышка в дочерний элемент элемента в настоящее время подсвечен. Я недостаточно проснулся, чтобы понять это сейчас.

В качестве альтернативы, если вычеркивание так же хорошо, как выделение вам, вы можете попробовать подход, который я упомянул в своем комментарии к вашему первоначальному вопросу. Нарисуйте 4 divs вокруг текущего зависающего элемента * - это один div для каждого края контура. Больше элементов чертежа между вами и вашим фактическим содержанием!


* Готов поспорить, что document.elementFromPoint(x, y) сделает этот элемент под мышью намного проще здесь.