observableArray中的Animate元素

时间:2015-04-17 01:26:35

标签: javascript knockout.js

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

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

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

我可以很容易地得到这个项目。但我不知道如何获得相应的HTML元素:

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

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

3 个答案:

答案 0 :(得分:1)

我会在评论中说出@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);
}

如果你想从父上下文触发动作,你可以坚持下去。容器的id属性,例如planet-list,以及在Knockout之外使用jQuery添加/删除动画,例如:

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(如下面的测试中所示)

我对你的小提琴进行了一些修改,请查看:http://jsfiddle.net/8k8V5/2652/

答案 1 :(得分:1)

关键是不要对抗淘汰赛。您的viewmodel永远不需要知道用于呈现它的HTML元素。

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

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

&#13;
&#13;
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"}
    ]
}));
&#13;
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; }
&#13;
<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>
&#13;
&#13;
&#13;

现在,第一颗行星的动画是如此微不足道,以至于我没有费心去实现它。

答案 2 :(得分:0)

你可以这样做: 换行:

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