jQuery 以正确的顺序插入元素 vs detach().sort()?

发布于 2024-10-24 21:46:26 字数 2485 浏览 4 评论 0原文

假设我有以下 html 结构:

<ul>
  <li>1</li>
  <li>2</li>
  <li>4</li>
</ul>

是否可以(以及如何)以正确的顺序插入新元素

  • 3
  • 而不分离元素和手段?原因是,我相信如果您 .detach() 和 .append() 元素,您将导致页面回流(我认为如果元素移动,无论如何都会发生)。但由于某种原因,与追加/分离/排序/追加相比,将其插入正确的位置似乎更干净。

    我已经在 jQuery 中看到了 nth-child 选择器,并且我也在使用 underscore.js 框架(它提供了 _.sortedIndex ,它告诉我元素的正确位置),但我可以似乎没有找到将其放入其中的正确方法。

    一些背景: 我正在使用backbone.js,并且我有一个项目集合。然后我假设我需要集合的视图(或集合中每个项目的视图?)。当我向集合中添加元素时,我设置了比较器,因此集合已正确排序,但页面上的视图未排序。

    对于那些通过谷歌到达这里的人,这是我最终在backbone.js中想到的:

    Item = Backbone.Model.extend({});
    
    ItemList = Backbone.Collection.extend({
        model: Item,
    
        comparator: function(item) {
            return item.get('id');
        }
    });
    
    ItemView = Backbone.View.extend({
        tagName: 'li',
        className: 'item',
    
        initialize: function() {
            _.bindAll(this, 'render');
            this.model.bind('change', this.render);
            this.model.view = this;
        },
    
        render: function() {
            $(this.el).text(this.model.get('name'));
            return this;
        }
    });
    
    App = Backbone.View.extend({
        el: $('#mylist'),
    
        initialize: function() {
            _.bindAll(this, 'add_one', 'add_all', 'render');
    
            this.items = new ItemList();
            this.items.bind('add', this.add_one);
            this.items.bind('refresh', this.add_all);
            this.items.bind('all', this.render);
    
            this.items.add(new Item({id: 2, name: 'two'}));
            this.items.add(new Item({id: 5, name: 'five'}));
            this.items.add(new Item({id: 1, name: 'one'}));
            this.items.add(new Item({id: 4, name: 'four'}));
            this.items.add(new Item({id: 3, name: 'three'}));        
            this.items.add(new Item({id: 6, name: 'six'}));
            this.items.add(new Item({id: 5.5, name: 'five.five'}));
        },
    
        add_one: function(item) {
            var view = new ItemView({model: item});
            var visible = this.$(view.tagName+'.'+view.className);
            var newel = view.render().el;
            var idx = this.items.indexOf(item);
            if (visible.length == idx) {
                $(this.el).append(newel);
            }
            else {
                visible.eq(idx).before(newel);
            }
        },
    
        add_all: function() {
            this.items.each(this.add_one);
        }
    });
    
    app = new App();
    

    在这里运行它: http:// /jsfiddle.net/dlamotte/L4j3b/

    Let's say I have the following html structure:

    <ul>
      <li>1</li>
      <li>2</li>
      <li>4</li>
    </ul>
    

    Is it possible (and how) to insert a new element <li>3</li> in the correct order without detaching the elements and resorting? Reason being, I believe if you .detach() and .append() the elements, you will cause a page reflow (which I suppose would happen anyways if the elements move around). But for some reason, it seems much cleaner to insert it in the right spot vs append/detach/sort/append.

    I've seen the nth-child selector in jQuery and I'm working with the underscore.js framework too (which provides _.sortedIndex which tells me the correct position of the element), but I can't seem to figure out the right way to put it in there.

    Some background:
    I'm working with backbone.js and I have a collection of items. Then I assume I need a View of the collection (or view per item in the collection?). When I add an element to the collection, I have the comparator set so the collection is sorted properly, but the View on the page is not sorted.

    For those getting here via google, here's what I eventually came up with in backbone.js:

    Item = Backbone.Model.extend({});
    
    ItemList = Backbone.Collection.extend({
        model: Item,
    
        comparator: function(item) {
            return item.get('id');
        }
    });
    
    ItemView = Backbone.View.extend({
        tagName: 'li',
        className: 'item',
    
        initialize: function() {
            _.bindAll(this, 'render');
            this.model.bind('change', this.render);
            this.model.view = this;
        },
    
        render: function() {
            $(this.el).text(this.model.get('name'));
            return this;
        }
    });
    
    App = Backbone.View.extend({
        el: $('#mylist'),
    
        initialize: function() {
            _.bindAll(this, 'add_one', 'add_all', 'render');
    
            this.items = new ItemList();
            this.items.bind('add', this.add_one);
            this.items.bind('refresh', this.add_all);
            this.items.bind('all', this.render);
    
            this.items.add(new Item({id: 2, name: 'two'}));
            this.items.add(new Item({id: 5, name: 'five'}));
            this.items.add(new Item({id: 1, name: 'one'}));
            this.items.add(new Item({id: 4, name: 'four'}));
            this.items.add(new Item({id: 3, name: 'three'}));        
            this.items.add(new Item({id: 6, name: 'six'}));
            this.items.add(new Item({id: 5.5, name: 'five.five'}));
        },
    
        add_one: function(item) {
            var view = new ItemView({model: item});
            var visible = this.$(view.tagName+'.'+view.className);
            var newel = view.render().el;
            var idx = this.items.indexOf(item);
            if (visible.length == idx) {
                $(this.el).append(newel);
            }
            else {
                visible.eq(idx).before(newel);
            }
        },
    
        add_all: function() {
            this.items.each(this.add_one);
        }
    });
    
    app = new App();
    

    Run it here: http://jsfiddle.net/dlamotte/L4j3b/

    如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

    扫码二维码加入Web技术交流群

    发布评论

    需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

    评论(2

    ◇流星雨 2024-10-31 21:46:26

    你可以使用 jQuery

    $('li').eq(1).after('<li>3</li>');
    

    fiddle 页面: http://jsfiddle.net/Hrjks/

    更好的是:

    var myindex = 3;
    var insertPoint = myindex -2;
    $('li').eq(insertPoint).after('<li>' + myindex +'</li>');
    

    fiddle :http://jsfiddle.net/Hrjks/1/

    you can use a jQuery

    $('li').eq(1).after('<li>3</li>');
    

    fiddle page: http://jsfiddle.net/Hrjks/

    Better yet:

    var myindex = 3;
    var insertPoint = myindex -2;
    $('li').eq(insertPoint).after('<li>' + myindex +'</li>');
    

    fiddle for this:http://jsfiddle.net/Hrjks/1/

    梦太阳 2024-10-31 21:46:26

    我最近遇到了同样的问题,我用以下函数修复了。

    function sortInsert(parent, element, fnc) {
        var stack = parent.children().filter(function() {
            return fnc($(this), element) > 0;
        });       
        if (stack.length == 0) {
            parent.append(element);
        } else {
            stack.first().before(element);
        }
    }
    
    sortInsert($('ul'), $('<li>1</li>'), function(e, a) { 
        return parseInt(e.html()) - parseInt(a.html()); 
    } );​
    

    它基本上是获取父级的所有子级,然后执行过滤器。如果您只需要比较它的值,您可以通过避免回调来简单地做到这一点,但在我的情况下,这是需要的,因为我按几个标准进行排序。

    如果您想按降序排序,只需将 append 替换为 prepend,将 before 替换为 lastlast 的第一个 应该可以工作。

    欢迎在我的游乐场玩:http://jsfiddle.net/crodas/FMEkb/5/

    I had the same problem recently and I fixed with the following function.

    function sortInsert(parent, element, fnc) {
        var stack = parent.children().filter(function() {
            return fnc($(this), element) > 0;
        });       
        if (stack.length == 0) {
            parent.append(element);
        } else {
            stack.first().before(element);
        }
    }
    
    sortInsert($('ul'), $('<li>1</li>'), function(e, a) { 
        return parseInt(e.html()) - parseInt(a.html()); 
    } );​
    

    It is basically getting all the child of parent, then doing a filter. If you only need to compare its values you can do it simple by avoiding the callback but in my case it was needed as I was sorting by several criteria.

    If you want to sort with a descending order just replace append by prepend, before by last and first for last and it should be working.

    Feel free to play in my playground: http://jsfiddle.net/crodas/FMEkb/5/

    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文