简体   繁体   English

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

[英]How can I avoid traversing the same DOM route multiple times?

I have an on function that has two mouse events inside of it mouseenter and mouseleave . 我有一个on函数,它在mouseentermouseleave中有两个鼠标事件。 When these events are triggered they run different functions, one adds a class, the other removes it. 触发这些事件时,它们会运行不同的函数,一个添加一个类,另一个删除它。

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

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

The thing is, I'm doing the following DOM traversal twice: 问题是,我正在进行以下两次DOM遍历:

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

But I don't see how I can save this traversal as a variable in one function and use it as another. 但我不知道如何将这个遍历保存为一个函数中的变量并将其用作另一个函数。 Here is my full JS code: 这是我的完整JS代码:

JavaScript 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 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>

Can anybody suggest a better way of doing this? 任何人都可以建议一个更好的方法吗?

Thanks. 谢谢。

You can change to have a common event handler for both events and set the operation depending upon which event it was: 您可以更改为两个事件都有一个公共事件处理程序,并根据它是哪个事件来设置操作:

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

Here's an explanation of what's going on: 以下是对正在发生的事情的解释:

  • .on("mouseenter mouseleave", function(e) {...}) hooks up multiple events to the same event handler. .on("mouseenter mouseleave", function(e) {...})将多个事件挂钩到同一个事件处理程序。
  • e.type is the name of the event for the current event so when you have multiple events triggering the same event handler, you can see which event it was that triggered. e.type是当前事件的事件名称,因此当您有多个事件触发相同的事件处理程序时,您可以看到触发了哪个事件。
  • var method = e.type === "mouseenter" ? "removeClass" : "addClass" var method = e.type === "mouseenter" ? "removeClass" : "addClass" is like an if/else statement where it assigns either "removeClass" or "addClass" to the method variable based on the value of e.type . var method = e.type === "mouseenter" ? "removeClass" : "addClass"就像一个if / else语句,它根据e.type的值为method变量赋值“ e.type "removeClass""addClass" It's called the ternary operator . 它被称为三元运算符
  • obj[method] is a property reference using a variable for the name of the property instead of a string literal. obj[method]是一个属性引用,它使用变量作为属性的名称而不是字符串文字。 So obj.addClass is the same as obj[method] when method is "addClass" . 因此当method"addClass"时, obj.addClassobj[method]相同。 Adding the () onto the end to make it a function call, then obj.addClass('unseen') is the same as obj[method]('unseen') when method is "addClass" . ()添加到末尾以使其成为函数调用,当method"addClass"时, obj.addClass('unseen')obj[method]('unseen')相同。

So, to break that last line down again: 所以,再次打破最后一行:

// 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');

One possible useful tool for DRY is .hover() because it is a shortcut for mouseenter and mouseleave. DRY的一个可能有用的工具是.hover()因为它是.hover()和mouseleave的快捷方式。 If you know that the relevant paragraphs are always marked as unseen before hover and no other code in the page ever messes with the unseen class (something you don't say anything about in your question), then you can use a shortcut using .hover() 如果你知道在悬停之前相关的段落总是被标记为未看到,并且页面中的其他代码都没有与看不见的类.hover() (你在问题中没有说明什么),那么你可以使用.hover()的快捷方式.hover()

$('.client').hover(function() {
    $(this).siblings('.testimonial').find('p').toggleClass('unseen');
});

The more common way of just moving repeated code into a common function that you can use in both places would look like this: 将重复代码移动到可在两个地方使用的常用函数的更常见方法如下所示:

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

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

You could use following logic if it does really matter to cache the specific siblings children elements and not all .testimonial p : 你可以使用以下逻辑,如果它确实缓存特定的兄弟姐妹子元素,而不是所有.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');
});

If you're looking for a DRY way to do it, you could write a reusable function that finds the sibling you want. 如果你正在寻找一种干嘛的方法,你可以编写一个可重复使用的函数来找到你想要的兄弟姐妹。

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

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

This way, if you need to change how the testimonial paragraph is accessed, you only need to do it in one place. 这样,如果您需要更改推荐段落的访问方式,您只需要在一个地方进行。

You could simply do the following: 您可以简单地执行以下操作:

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

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

I hope that this helps. 我希望这个对你有用。

Try to store selected items 尝试存储所选项目

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

and then operate with stored ones 然后使用存储的操作

$('.clienet').hover(
    function(){ p.removeClass('unseen') }, 
    function(){ p.addClass('unseen') }
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM