knockoutjs和同位素添加新项目导致第一个元素跳转

时间:2014-08-10 10:41:32

标签: javascript jquery knockout.js jquery-isotope knockout-3.0

我正在使用knockoutjs和同位素masonary布局,基于代码 blog link here 的自定义绑定,如下所示:

查看:

<div id="container" class="isotope" data-bind="foreach: bills">
    <div class="item" data-bind="isotope: {container: '#container', itemSelector: '.item'}, style: {height: RandomHeight() + 'px'}">
        <h3 data-bind="text: title"></h3>
        <p>Votes: <span data-bind="text: votes"></span><p>
        <p data-bind="text: desc"></p>
    </div>
</div>

ViewModel和自定义绑定:

ko.bindingHandlers.isotope = function() {
    var self = this;

    self.init = function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log("init...");
        var value = ko.utils.unwrapObservable(valueAccessor());

        var $container = $(value.container);

        $container.isotope({
            itemSelector: value.itemSelector,
            masonry: {
              columnWidth: 100
            }
        });
    };

    self.update = function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var $el = $(element);
        var value = ko.utils.unwrapObservable(valueAccessor());
        console.log("updating..." + value);
        var $container = $(value.container);
        $container.isotope('appended', $el);
    };

    return {
        init: self.init,
        update: self.update
    }
}();

问题是当我添加一个新项目并将其附加到列表时,第一个项目从左向右跳转。顶部的项目应该保持静态定位,只有底部的项目应该随机播放,这个发生的示例屏幕截图(mid-jump_位于帖子的底部。

任何想法,我做错了吗?

小提琴在这里:http://jsfiddle.net/g18c/zoohcveh/4/

brick jump

2 个答案:

答案 0 :(得分:3)

您的同位素结合位于item,如果您仔细阅读日志,同位素会在每次添加新项目时执行另一个初始化。这肯定会带来麻烦。

正确的方法是在顶级容器上使用同位素绑定,只启动一次。 但我们还需要保持(也称为扩展)foreach绑定的行为。

要在添加新项目后触发isotope的动画,您需要使用foreach&#39; afterAdd回调。在这里阅读更多http://knockoutjs.com/documentation/foreach-binding.html

http://jsfiddle.net/zoohcveh/27/

<强> HTML

<div id="container" class="isotope" data-bind="isotope: bills, isotopeOptions: {
                itemSelector: '.item',
                masonry: {
                  columnWidth: 182
                }
            }">
    <div class="item" data-bind="style: {height: RandomHeight() + 'px'}">
        <h3 data-bind="text: title"></h3>
        <p>Votes: <span data-bind="text: votes"></span></p>
        <p data-bind="text: desc"></p>
    </div>
</div>

<强> JS

// use a factory method since most code of 'init' and 'update' are shared.
function initOrUpdate(method) {
    return function(element, valueAccessor, allBindings, viewModel, bindingContext) {

        function isotopeAppend(ele) {
            // runs isotope animation
            console.log('nodeType ' + ele.nodeType);
            // nodeType 3 is Text (the empty space before and after div.item)
            // nodeType 1 is element
            if (ele.nodeType === 1) { // Element type
              console.log("appended isotope");
              $(element).isotope('appended', ele).isotope('layout');
            }
        }

        function attachCallback(valueAccessor) {
            return function() {
                return {
                    data: valueAccessor(),
                    afterAdd: isotopeAppend,
                };
            };
        }

        // extend foreach binding
        ko.bindingHandlers.foreach[method](element,
            attachCallback(valueAccessor), // attach 'afterAdd' callback
            allBindings, viewModel, bindingContext);

        if (method === 'init') {
            console.log('init...');
            var options = allBindings.get('isotopeOptions') || {};
            console.log("options " + JSON.stringify(options));
            $(element).isotope(options);

            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                $(element).isotope("destroy");
            });
        } else {
            console.log("updating...");
        }
    }
}

ko.bindingHandlers.isotope = {
    init: initOrUpdate('init'),
    update: initOrUpdate('update')
};

<强>更新

要成为好公民,请为$(element).isotope("destroy");添加处理回调。

答案 1 :(得分:1)

http://jsfiddle.net/zombiesplat/zoohcveh/17/这是我在下面回答的工作版本。

问题似乎是同位素v2和基因敲除的某种兼容性问题。我的修复来自查找此示例http://zubinraj.com/demo/isotope-knockout/isotope-knockout-binding.htm并将您的代码转换为使用knockout v1.5

HTML

<div>
    <button data-bind="click: addNew">Add New</button>
</div>

<div id="container" class="isotope" data-bind="foreach: bills">
    <div class="item" data-bind="isotope: {container: '#container', itemSelector: '.item'}, style: {height: RandomHeight() + 'px'}">
        <h3 data-bind="text: title"></h3>
        <p>Votes: <span data-bind="text: votes"></span><p>
        <p data-bind="text: desc"></p>
    </div>
</div>

CSS

/* ---- .item ---- */

.item {
  float: left;
  width: 380px;
  background: #0D8;
  border: 2px solid #333;
  border-color: hsla(0, 0%, 0%, 0.7);
}


/* Begin Required Isotope Styles - see http://isotope.metafizzy.co for more info */
 .isotope-item {
    z-index: 2;
}
.isotope-hidden.isotope-item {
    pointer-events: none;
    z-index: 1;
}
/**** Isotope CSS3 transitions ****/
 .isotope, .isotope .isotope-item {
    -webkit-transition-duration: 0.8s;
    -moz-transition-duration: 0.8s;
    -ms-transition-duration: 0.8s;
    -o-transition-duration: 0.8s;
    transition-duration: 0.8s;
}
.isotope {
    -webkit-transition-property: height, width;
    -moz-transition-property: height, width;
    -ms-transition-property: height, width;
    -o-transition-property: height, width;
    transition-property: height, width;
}
.isotope .isotope-item {
    -webkit-transition-property: -webkit-transform, opacity;
    -moz-transition-property: -moz-transform, opacity;
    -ms-transition-property: -ms-transform, opacity;
    -o-transition-property: -o-transform, opacity;
    transition-property: transform, opacity;
}
/**** disabling Isotope CSS3 transitions ****/
 .isotope.no-transition, .isotope.no-transition .isotope-item, .isotope .isotope-item.no-transition {
    -webkit-transition-duration: 0s;
    -moz-transition-duration: 0s;
    -ms-transition-duration: 0s;
    -o-transition-duration: 0s;
    transition-duration: 0s;
}

Dom Ready上的Javascript

var $container = $("#container");
var data = [
    {
        title: "Test 1",
        desc: "Some description text goes here",
        votes: 1000,
        category: "catA",
    },
    {
        title: "Test 2",
        desc: "Some description text goes here",
        votes: 2000,
        category: "catB",
    },
    {
        title: "Test 3",
        desc: "Some description text goes here",
        votes: 100,
        category: "catC",
    }
];

function Bill(title, desc, votes, category)
{
    var self = this;
    self.title = ko.observable(title);
    self.desc = ko.observable(desc);
    self.votes = ko.observable(votes);
    self.category = ko.observable(category);
    self.RandomHeight = ko.observable(Math.floor(Math.random() * 200) + 400);
    console.log("Added new bill");
};

function ViewModel() {
    var self = this;

    self.bills = ko.observableArray();

    self.count = 1;

    self.search = function() {
        self.bills.removeAll();
        for(var i=0; i<data.length; i++)
        {
            var bill = new Bill(
                data[i].title,
                data[i].desc,
                data[i].votes,
                data[i].category
            );
            self.bills.push(bill);
        }
    };

    self.addNew = function() {
        for(var i=0; i<data.length; i++)
        {
            var bill = new Bill(
                self.count,
                data[i].desc,
                data[i].votes,
                data[i].category
            );
            self.bills.push(bill);
            self.count++;
        }
    };
};

ko.bindingHandlers.isotope = {
    init : function(element, valueAccessor, allBindings, viewModel, bindingContext) {

    },  
    update : function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var $el = $(element);
        var value = ko.utils.unwrapObservable(valueAccessor());
        console.log("updating..." + value);
        var $container = $(value.container);
        $container.isotope({
            itemSelector: value.itemSelector,
            masonry: {
              columnWidth: 100
            }
        });
        $container.isotope('appended', $el);
    }

};

ko.applyBindings(new ViewModel());