【问题标题】:How can I refresh a stored and snapshotted jquery selector variable如何刷新存储和快照的 jquery 选择器变量
【发布时间】:2012-08-05 19:43:13
【问题描述】:

我昨天遇到了一个分配给变量的 jquery-selector 问题,这让我发疯了。

这是一个带有测试用例的 jsfiddle:

  • 将 .elem 分配给我的 obj var
  • 将两个长度记录到控制台。结果 => 4
  • 从 DOM 中移除 #3
  • 将 obj 记录到控制台 => 删除的 #3 仍然存在,长度仍然是 4。 我发现 jquery 查询是快照的?到变量,不能?不会?更新
  • 将 .elem 记录到控制台.. 是的 Result => 3 并且 #3 消失了
  • 现在我将 .elem 更新为 300 的新宽度
  • logging obj & obj.width 给了我 300.. 所以快照已经更新了?有趣的是 4 个 div 中有 3 个有新的宽度,但删除的 #3 没有...

另一个测试:将 li 元素添加到 domtree 并记录 obj 和 .elem。 .elem 确实有新的 li 而 obj 没有,因为它仍然是旧快照

http://jsfiddle.net/CBDUK/1/

有没有办法用新内容更新这个 obj? 我不想创建一个新的 obj,因为在我的应用程序中,该对象中保存了很多信息,我不想破坏...

【问题讨论】:

    标签: javascript jquery variables dom jquery-selectors


    【解决方案1】:

    是的,这是一张快照。此外,从页面 DOM 树中删除一个元素并不会神奇地消除对该元素的所有引用。

    你可以这样刷新它:

    var a = $(".elem");
    
    a = $(a.selector);
    

    迷你插件:

    $.fn.refresh = function() {
        return $(this.selector);
    };
    
    var a = $(".elem");
    
    a = a.refresh();
    

    不过,这个简单的解决方案不适用于复杂的遍历。您将不得不为 .selector 属性创建一个解析器来刷新它们的快照。

    格式如下:

    $("body").find("div").next(".sibling").prevAll().siblings().selector
    //"body div.next(.sibling).prevAll().siblings()"
    

    就地迷你插件:

    $.fn.refresh = function() {
        var elems = $(this.selector);
        this.splice(0, this.length);
        this.push.apply( this, elems );
        return this;
    };
    
    var a = $(".elem");
    a.refresh() //No assignment necessary
    

    【讨论】:

    • 感谢您的帮助和解释!它与 .selector 调用配合得很好。这是一个jquery内部方法?找不到该调用的任何文档。无论如何..我稍微更改了我的代码,并为该计数创建了一个新的设置器,并使用 setCount ($...length) 调用它,它的效果也很好。
    • @Ralk .selector 属性在技术上是内部的。
    • @Esailija - 在这里不起作用:jsfiddle.net/nJeqf( .selector 属性在 jQuery 1.7 中已弃用)。 api.jquery.com/selector
    • @TravisJ 它不适用于 1.7 之前的那种东西,正如答案中提到的那样。简单的选择器案例仍然像 1.9.1 中所宣传的那样工作:jsfiddle.net/nJeqf/1
    • .selector 被标记为已弃用,将在 3.0 版中删除。
    【解决方案2】:

    我也喜欢@Esailija 解决方案,但似乎 this.selector 有一些过滤器错误。 所以我根据自己的需要进行了修改,也许对某人有用

    这是针对 jQuery 1.7.2 的,没有在更高版本的过滤快照上测试刷新

    $.fn.refresh = function() { // refresh seletor
        var m = this.selector.match(/\.filter\([.\S+\d?(\,\s2)]*\)/); // catch filter string
        var elems = null;
        if (m != null) { // if no filter, then do the evarage workflow
            var filter = m[0].match(/\([.\S+\d?(\,\s2)]*\)/)[0].replace(/[\(\)']+/g,'');
            this.selector = this.selector.replace(m[0],''); // remove filter from selector
            elems = $(this.selector).filter(filter); // enable filter for it
        } else {
            elems = $(this.selector);
        }
        this.splice(0, this.length);
        this.push.apply( this, elems );
        return this;
    };
    

    代码不是那么漂亮,但它适用于我的过滤选择器。

    【讨论】:

    • 为此使用正则表达式不是很灵活,在我看来也不是一个好主意。
    【解决方案3】:

    干净且通用的解决方案可在 jQuery 3.4.1 中正常工作:

    我的解决办法是:

    1. 在 jQuery 对象初始化时拦截选择器,同时使用继承透明地维护所有其他 jQuery 功能
    2. 使用我们在初始化期间添加的新“selector”属性构建刷新插件

    定义:

    $ = (function (originalJQuery) 
    {
        return (function () 
        {
            var newJQuery = originalJQuery.apply(this, arguments);
            newJQuery.selector = arguments.length > 0 ? arguments[0] : null;
            return newJQuery;
        });
    })($);
    
    $.fn = $.prototype = jQuery.fn;
    
    $.fn.refresh = function () 
    {
        if (this.selector != null && (typeof this.selector === 'string' || this.selector instanceof String))
        {
            var elems = $(this.selector);
            this.splice(0, this.length);
            this.push.apply(this, elems);
        }
        return this;
    };
    

    用法:

    var myAnchors = $('p > a');
    //Manipulate your DOM and make changes to be captured by the refresh plugin....
    myAnchors.refresh();
    //Now, myAnchors variable will hold a fresh snapshot 
    

    注意: 作为优化,对象选择器不需要刷新,因为它们本质上是通过引用传递的,所以在刷新插件中,我们只在选择器是字符串选择器而不是对象选择器时才刷新,以便澄清,考虑以下代码:

    // Define a plain object
    var foo = { foo: "bar", hello: "world" };
     
    // Pass it to the jQuery function
    var $foo = $( foo );
     
    // Test accessing property values
    var test1 = $foo.prop( "foo" ); // bar
    
    // Change the original object
    foo.foo = "koko";
    
    // Test updated property value
    var test2 = $foo.prop( "foo" ); // koko
    

    【讨论】:

      【解决方案4】:

      不推荐使用Jquery .selector,最好在分配时将带有选择器值的字符串记住到某个变量

      function someModule($selector, selectorText) {
         var $moduleSelector = $selector;
         var moduleSelectorText = selectorText;
      
         var onSelectorRefresh = function() {
            $moduleSelector = $(moduleSelectorText);
         }
      }
      

      https://api.jquery.com/selector/

      【讨论】:

        【解决方案5】:

        如果你使用remove(),它只会删除DOM的一部分,而不是所有子元素或相关元素,相反,如果你在元素上使用empty(),问题就消失了。

        例如:

         $('#parent .child).find('#foo').empty();
        

        也许它对某人有用!

        【讨论】:

          【解决方案6】:

          您还可以在函数中返回 JQuery 选择器,并将此函数保存到变量中。您的代码看起来会有些不同,但它可以工作。每次执行该函数时,您的 jquery 选择器都会再次搜索 DOM。

          在这个例子中,我使用了一个不带括号的箭头函数,它将返回箭头旁边的任何内容。在这种情况下,它将返回 JQuery 集合。

          const $mySelector = () => $('.selector');
          console.log($mySelector().last().text());
          $('.parent').append('<li class="selector">4</li>')
          
          console.log($mySelector().last().text()); //RETURNS 4 not 3
          <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
          <ul class="parent">
              <li class="selector">1</li>
              <li class="selector">2</li>
              <li class="selector">3</li>
          </ul>

          【讨论】:

            猜你喜欢
            • 2020-07-07
            • 2015-07-19
            • 2014-07-26
            • 2013-09-06
            • 1970-01-01
            • 1970-01-01
            • 2013-08-08
            • 1970-01-01
            相关资源
            最近更新 更多