如何避免多次遍历同一个DOM路由?

时间:2015-02-03 22:13:23

标签: javascript jquery dom traversal jquery-traversing

我有一个on函数,其中包含两个鼠标事件mouseentermouseleave。当这些事件被触发时,它们会运行不同的函数,一个添加一个类,另一个删除它。

$(this).siblings('.testimonial').find('p').addClass('unseen');

$(this).siblings('.testimonial').find('p').removeClass('unseen');

问题是,我正在进行以下两次DOM遍历:

$(this).siblings('.testimonial').find('p')

但我不知道如何将这个遍历保存为一个函数中的变量并将其用作另一个函数。这是我的完整JS代码:

的JavaScript

(function ($) {

    var testimonial = $('.testimonial');
    var testimonialHeight = testimonial.outerHeight();
    var testimonialWidth = testimonial.outerWidth();

    testimonial.find('p').addClass('unseen');

    testimonial.css({
        height: testimonialHeight,
        width: testimonialWidth
    });

    $('.client').on({
        mouseenter: function() {
            $(this).siblings('.testimonial').find('p').removeClass('unseen');
        },
        mouseleave: function() {
            $(this).siblings('.testimonial').find('p').addClass('unseen');
        }
    });

})(jQuery);

HTML

<ul class="list-unstyled list-inline">
  <li>
    <div class="testimonial"><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.<p></div>
      <img class="client" src="https://s3.amazonaws.com/uifaces/faces/twitter/jsa/128.jpg" alt="" />
  </li>
  <li>
    <div class="testimonial"><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.</p></div>
    <img class="client" src="https://s3.amazonaws.com/uifaces/faces/twitter/gerrenlamson/128.jpg" alt="" />
  </li>
  <li>
    <div class="testimonial"><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p></div>
    <img class="client" src="https://s3.amazonaws.com/uifaces/faces/twitter/jadlimcaco/128.jpg" alt="" />
  </li>
</ul>

有人可以提出更好的方法吗?

感谢。

5 个答案:

答案 0 :(得分:4)

您可以更改为两个事件都有一个公共事件处理程序,并根据事件的具体情况设置操作:

$('.client').on("mouseenter mouseleave", function(e) {
    var method = e.type === "mouseenter" ? "removeClass" : "addClass";
    $(this).siblings('.testimonial').find('p')[method]('unseen');
});

以下是对正在发生的事情的解释:

  • .on("mouseenter mouseleave", function(e) {...})将多个事件挂钩到同一个事件处理程序。
  • e.type是当前事件的事件名称,因此当您有多个事件触发相同的事件处理程序时,您可以看到触发了哪个事件。
  • var method = e.type === "mouseenter" ? "removeClass" : "addClass"类似于if / else语句,它根据"removeClass"的值将"addClass"method分配给e.type变量。它被称为ternary operator
  • obj[method]是一个属性引用,它使用变量作为属性的名称而不是字符串文字。因此,当obj.addClassobj[method]时,method"addClass"相同。将()添加到结尾以使其成为函数调用,obj.addClass('unseen')obj[method]('unseen') method "addClass"// find the right paragraphs $(this).siblings('.testimonial').find('p') // get the property whose name is in the method variable $(this).siblings('.testimonial').find('p')[method] // call that property as a function and pass it 'unseen' $(this).siblings('.testimonial').find('p')[method]('unseen'); 相同。

所以,再次打破最后一行:

.hover()

DRY的一个可能有用的工具是.hover(),因为它是mouseenter和mouseleave的快捷方式。如果您知道相关段落在悬停之前始终标记为未见过,并且页面中没有其他代码与看不见的课程混淆(您在问题中没有说出任何内容),那么您可以使用快捷方式$('.client').hover(function() { $(this).siblings('.testimonial').find('p').toggleClass('unseen'); });

function getSiblingParagraphs(parent) {
    return $(parent).siblings('.testimonial').find('p');
}

$('.client').on({
    mouseenter: function() {
        getSiblingParagraphs(this).removeClass('unseen');
    },
    mouseleave: function() {
        getSiblingParagraphs(this).addClass('unseen');
    }
 });

将重复代码移动到可在两个地方使用的常用函数的更常见方法如下所示:

{{1}}

答案 1 :(得分:1)

如果缓存特定的兄弟姐妹子元素而不是全部.testimonial p,那么您可以使用以下逻辑:

$('.client').each(function () {
    this._testimonialP = $(this).siblings('.testimonial').find('p').addClass('unseen');// But .unseen should be set in HTML markup by default
}).hover(function () {
    this._testimonialP.toggleClass('unseen');
});

答案 2 :(得分:0)

如果您正在寻找一种干嘛的方法,那么您可以编写一个可重复使用的函数来找到您想要的兄弟。

function findTestimonialParagraph($root) {
    return $root.siblings('.testimonial').find('p');
}

$('.client').on({
    mouseenter: function() {
        findTestimonialParagraph($(this)).removeClass('unseen');
    },
    mouseleave: function() {
        findTestimonialParagraph($(this)).addClass('unseen');
    }
});

这样,如果您需要更改推荐段落的访问方式,您只需要在一个地方进行。

答案 3 :(得分:-1)

您可以执行以下操作:

var $client = $('.client');
var $clientTestimonialParagraphs = $client.siblings('.testimonial').find('p');

$client.on({
        mouseenter: function() {
            $clientTestimonialParagraphs.removeClass('unseen');
        },
        mouseleave: function() {
            $clientTestimonialParagraphs.addClass('unseen');
        }
    });

我希望这会有所帮助。

答案 4 :(得分:-1)

尝试存储所选项目

var p = testimonial.find('p').addClass('unseen');

然后使用存储的

进行操作
$('.clienet').hover(
    function(){ p.removeClass('unseen') }, 
    function(){ p.addClass('unseen') }
)