observableArray 中的动画元素

Animate element in observableArray

我想为可观察数组中的元素设置动画。

我没有在 observableArray 中添加或删除项目。

考虑到以下jsfiddle,我想调用animateFirstElement函数并突出显示星球'Mercury'

我可以轻松拿到物品。但我不知道如何得到它对应的 HTML 元素:

this.animateFirstElement = function() {
    alert(this.planets()[0].name);
}; 

http://jsfiddle.net/8k8V5/2644/

你可以这样做: 换行:

<div data-bind='attr: { "class": name + "_" + type }, text: name'> </div>
this.animateFirstElement = function() {
    $("." + this.planets()[0].name + "_" + this.planets()[0].type).toggle();
};

我支持@CrimsonChris 在评论中所说的,尽管这两种方式都相当简单。默认情况下,Knockout 将参数 data, event 传递给视图上的任何绑定。因此,例如,如果您想在用户单击时突出显示一个行星,您可以这样做:

<div data-bind="attr: { 'class': 'planet ' + type }, 
                text: name, 
                click: highlightElement"> </div>

highlightElement中:

function highlightElement(data, e) {
  var target = e.target || e.srcElement;
  myHighlightFunction(target);
}

如果你想从父上下文触发操作,你可以将一个好的 ol' id 属性粘贴到容器,例如 planet-list,并使用 [=35= 动画添加/删除] 在 Knockout 之外,例如:

this.removeFirstElement = function() {
    var target = document.getElementById('planet-list'),
        planet = target.children[0];
    $(planet).slideUp(400,function() { self.planets.shift(); });
};

您也可以在 敲除内执行此操作,例如通过构建 controls descendant bindings 的自定义绑定,或者您可以使用 planetsToShow.subscribe 相应地设置动画数组变小/变大了。请注意,在视图中,您可以完美地将 $element 传递给函数,或 $index(如我下面的测试中所示)

我对你的 fiddle 做了一些修改,请查看:http://jsfiddle.net/8k8V5/2652/

关键是不要对抗击倒。您的视图模型永远不需要知道用于呈现它的 HTML 元素。

如果您想影响项目的可见性,请在您的视图模型中引入 visible 属性 并使您的视图响应此 属性 中的更改。如有必要,创建自定义绑定来处理动画本身 - 我在下面创建了 fadeVisibleslideVisible 绑定。

以下使用单独的 Planet 视图模型和订阅 typeToShow 属性。

function Planet(data) {
    var self = this;
    self.name = data.name;
    self.type = data.type;
    self.visible = ko.observable(true);
}
Planet.create = function (data) {
    return new Planet(data);
};

function Planets(data) {
    var self = this;
    
    self.planets = ko.observableArray(ko.utils.arrayMap(data.planets, Planet.create)); 
    self.typeToShow = ko.observable("all");
    self.displayAdvancedOptions = ko.observable(true);
 
    self.addPlanet = function(name, type) {
        self.planets.push(new Planet({
            name: name || "New planet",
            type: type || "rock"
        }));
    };
    
    self.typeToShow.subscribe(function (type) {
        ko.utils.arrayForEach(self.planets(), function(planet) {
            planet.visible(type === "all" || ko.unwrap(planet.type) === type);
        });
    });
}

ko.bindingHandlers.fadeVisible = {
    init: function(element, valueAccessor) {
        var value = valueAccessor(),
            visible = ko.unwrap(value);
        $(element).toggle(visible);
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor(),
            visible = ko.unwrap(value);
        $(element)[visible ? "fadeIn" : "fadeOut"]();
    }
};

ko.bindingHandlers.slideVisible = {
    init: function(element, valueAccessor) {
        var value = valueAccessor(),
            visible = ko.unwrap(value);
        $(element).toggle(visible);
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor(),
            visible = ko.unwrap(value);
        $(element)[visible ? "slideDown" : "slideUp"]();
    }
};

ko.applyBindings(new Planets({
    planets: [
        { name: "Mercury", type: "rock"},
        { name: "Venus", type: "rock"},
        { name: "Earth", type: "rock"},
        { name: "Mars", type: "rock"},
        { name: "Jupiter", type: "gasgiant"},
        { name: "Saturn", type: "gasgiant"},
        { name: "Uranus", type: "gasgiant"},
        { name: "Neptune", type: "gasgiant"},
        { name: "Pluto", type: "rock"}
    ]
}));
body { font-family: arial; font-size: 14px; }
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; }

.planet { background-color: #AAEECC; padding: 0.25em; border: 1px solid silver; margin-bottom: 0.5em; font-size: 0.75em; }
.planet.rock { background-color: #EECCAA; }
.liveExample input { margin: 0 0.3em 0 1em; }

li { list-style-type: disc; margin-left: 20px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div class='liveExample'> 
    <h2>Planets</h2>
 
    <p data-bind='fadeVisible: displayAdvancedOptions'>
        Show:
        <label><input type='radio' name="type" value='all' data-bind='checked: typeToShow' />All</label>
        <label><input type='radio' name="type" value='rock' data-bind='checked: typeToShow' />Rocky planets</label>
        <label><input type='radio' name="type" value='gasgiant' data-bind='checked: typeToShow' />Gas giants</label>
    </p>
     
    <div data-bind='foreach: planets'>
        <div data-bind='attr: { "class": "planet " + type }, text: name, slideVisible: visible'></div>
    </div>
</div>

现在制作第一个星球的动画太琐碎了,我懒得去实现它了。