2011-01-15 41 views
18

thể trùng lặp:
How to make this JavaScript much faster?jQuery: Đánh dấu phần tử bên dưới con trỏ chuột?

Tôi đang cố gắng để tạo ra một "bảng chọn yếu tố" trong jQuery, như Firebug có. Về cơ bản, tôi muốn làm nổi bật phần tử bên dưới chuột của người dùng. Đây là những gì tôi đã có cho đến nay, nhưng nó không hoạt động rất tốt:

$('*').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'); 

Về cơ bản, tôi đang tiêm div vào DOM có nền bán trong suốt. Sau đó, tôi lắng nghe sự kiện di chuột trên mọi phần tử, sau đó di chuyển div để nó bao gồm phần tử đó.

Ngay bây giờ, điều này chỉ làm cho toàn bộ trang chuyển sang màu đỏ ngay sau khi bạn di chuyển chuột qua trang. Làm thế nào tôi có thể làm điều này để làm việc đẹp hơn?

Chỉnh sửa: Chắc chắn vấn đề là ngay khi chuột chạm vào trang, nội dung được chọn và sau đó khi tôi di chuyển chuột, không có khoảnh khắc nào được truyền qua highligher vì phần trên của nó mọi điều.


Firebug

Đào thông qua mã nguồn Firebug, tôi thấy điều này:

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; 
} 

Hình như họ đang sử dụng một div chuẩn + css để vẽ nó ..... chỉ có để tìm hiểu cách họ xử lý các sự kiện ngay bây giờ ... (tệp này có độ dài 28K)

Còn đoạn mã này, tôi đoán tìm đối tượng thích hợp .... mặc dù tôi không thể tìm ra cách . Họ đang tìm kiếm một lớp "objectLink-element" ... và tôi không biết cái này "repObject" là gì.

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(); 

}, 

Tôi đang nghĩ rằng có lẽ khi MouseMove hoặc mouseover cháy sự kiện cho nút highlighter tôi bằng cách nào đó có thể vượt qua nó cùng để thay thế? Có lẽ để nút nó bao gồm ...?


Nếu tôi đặt một yếu tố vô hình trên mọi phần tử với một z-index cao hơn highlighter của tôi, nhưng cho highlighter tôi một z-index cao hơn các yếu tố thực tế ... về mặt lý thuyết, nó cũng làm việc. Các phần tử vô hình sẽ di chuyển sự kiện chuột, nhưng hiệu ứng nổi bật sẽ vẫn trông giống như các phần tử thực tế của nó.

Điều này có nghĩa là tôi vừa tăng gấp đôi các phần tử DOM và vị trí phải chính xác. Trừ khi có lẽ tôi chỉ "nâng" các yếu tố mà trình đánh dấu hiện đang bao gồm ?? Nhưng đó vẫn có thể là mọi yếu tố>. < Ai đó giúp tôi!

+3

Có một khó khăn bắt-22 khi cố gắng để làm những thứ như thế này. Về cơ bản, ngay sau khi bạn vẽ một cái gì đó dưới con chuột, là kết quả của con chuột di chuột qua một phần tử, con chuột thực sự rời khỏi phần tử gốc và hiện đang lơ lửng trên phần tử _new_. –

+0

@Matt: Làm cách nào để chúng ta có được điều này? Firebug không thao tác DOM để hiển thị các hộp đó hay nó có công cụ hiển thị của riêng nó? – mpen

+1

Firebug nêu bật các yếu tố trong trang web khi bạn di chuột qua chúng trong Firebug - ** riêng **. Hay là suy nghĩ mệt mỏi? Khi bạn sử dụng "bấm để kiểm tra" nó chỉ phác thảo các yếu tố, có thể là điểm then chốt của vấn đề - Firebug có thể vẽ 4 phần tử riêng biệt, một cho mỗi cạnh của hộp, trong trường hợp đó, catch-22 tôi đã đề cập isn không có vấn đề gì cả. –

Trả lời

1

Lý do toàn bộ trang chuyển sang màu đỏ ngay khi bạn di chuột qua là mã của bạn khớp với sự kiện mouseover cho phần tử body. Bạn có thể ngừng điều đó xảy ra bằng cách chỉ chọn trẻ em là body.

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

Bạn sẽ gặp vấn đề về hiệu suất trên một trang có nhiều yếu tố, mặc dù từ ràng buộc sẽ đính kèm người nghe cho mỗi phần tử được so khớp duy nhất. Hãy thử xem xét sự kiện ủy nhiệm sự kiện của jQuery api (.delegate(), http://api.jquery.com/delegate/), cho phép bạn nghe các sự kiện truyền tới một phần tử gốc và cũng làm việc cho các sự kiện chuột.

+0

Điều đó không thực sự khắc phục được vấn đề (sử dụng 'body *'), điều đó chỉ di chuyển vấn đề đến một phần tử sâu hơn một chút. Xem bình luận của Matt. Không quá lo lắng về hiệu suất, tôi sẽ lấy bất cứ thứ gì có hiệu quả. – mpen

+0

Ngoài ra, lý do tôi không sử dụng live() hoặc delegate() là vì sau đó các yếu tố trong tương lai sẽ được bao gồm ... cụ thể là, tôi không muốn nó bắt đầu tự chọn (đó là lý do tại sao tôi nối nó sau khi tôi bị ràng buộc sự kiện). – mpen

+0

Bạn đã thử kiểm tra đối tượng sự kiện được chuyển đến hàm gọi lại của bạn cho currentTarget chưa? Nếu currentTarget là div đánh dấu của bạn, thì bạn không thể làm gì cả. – andrewle

1

► This hơi khó chịu, nhưng không thể phát hiện di chuyển từ phần tử gốc sang một trong các phần tử con mà không cần di chuyển chuột hoàn toàn tắt.

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; 
}); 

Hy vọng rằng sẽ giúp bạn có được quả bóng lăn. Bạn có thể chỉnh sửa những gì tôi đã viết để sử dụng document.elementFromPoint(x, y) để kiểm tra xem con chuột đã di chuyển vào phần tử con của phần tử hiện được tô sáng hay chưa. Tôi không tỉnh táo đủ để tìm ra điều này ngay bây giờ.

Cách khác, nếu phác thảo là tốt như làm nổi bật cho bạn, bạn có thể thử cách tiếp cận mà tôi đã đề cập trong nhận xét của tôi cho câu hỏi ban đầu của bạn. Vẽ 4 div xung quanh phần tử hiện đang lơ lửng * - đó là một div cho mỗi cạnh của hộp phác thảo. Không còn yếu tố vẽ nào giữa bạn và nội dung thực của bạn nữa!


* Tôi muốn đặt cược rằng document.elementFromPoint(x, y) sẽ làm cho nhận được các phần tử dưới chuột dễ dàng hơn nhiều đây.

+0

Đến đó ... vẫn cần một số công việc. Tôi sẽ xem những gì tôi có thể làm. – mpen

2

Tôi có thể đề xuất phương pháp thay thế không?

Làm thế nào về chỉ đơn giản là gán một background-color cho tất cả các phần tử con của trang, và sau đó, trên hover(), điều chỉnh background-color của rằng yếu tố để tăng độ tương phản của nó?

$('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.

+0

Có thể. Tôi có thể phải đi với cách tiếp cận này nếu tôi không thể tìm thấy một giải pháp, nhưng điều này là * thực sự * bugging tôi bởi vì tôi biết có phải là một cách để làm điều đó. – mpen

3

Sửa đổi câu trả lời của David để nó đúng cách trở lại trạng các bạt màu nền ...

$('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; 
}); 
25

Tất cả những câu trả lời là quá phức tạp ... Giải pháp đơn giản:

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; 
} 
Các vấn đề liên quan