2015-04-17 2 views
1

Я хочу анимировать элемент из наблюдаемого массива.Анимационный элемент в наблюдаемом массиве

Я не добавляю и не удаляю элементы из наблюдаемого массива.

Учитывая следующий jsfiddle, я хотел бы вызвать функцию animateFirstElement и выделить планеты «Меркурий»

Я могу легко получить деталь. Но я не знаю, как получить это соответствующий HTML элемент:

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

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

+1

Доступ к элементам HTML и управление ими напрямую - это то, что Knockout пытается помешать вам делать.Ваши взгляды должны зависеть от ваших моделей взглядов, а не наоборот. Подумайте об использовании настраиваемой привязки, которая привязывается к свойству в вашей модели представления, чтобы вызвать анимацию. – CrimsonChris

+1

Вот аналогичный вопрос с отличным ответом. http://stackoverflow.com/questions/16296774/access-html-element-from-ko-computed http://stackoverflow.com/questions/10126812/knockout-js-get-dom-object-associated-with-data – CrimsonChris

ответ

1

я второй, что сказал @CrimsonChris в комментарии, хотя это довольно просто в любом случае. Нокаут по умолчанию передает параметры 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 и анимировать добавления/удаления с 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/

0

Вы можете сделать это: Изменить строки:

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

Ключ не работать против нокаута. Ваш viewmodel никогда не должен знать HTML-элементы, которые используются для рендеринга.

Если вы хотите повлиять на видимость ваших товаров, представьте недвижимость visible на вашем viewmodel и сделайте так, чтобы вы оценили изменения в этом отеле. При необходимости создайте настраиваемые привязки, которые обрабатывают сама анимацию - я создал привязки fadeVisible и slideVisible.

Следующая модель использует вид 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>

Анимационные первую планету настолько тривиальное теперь, что я не удосужился его реализации.

+0

Можете ли вы объяснить, как оживить первую планету, когда я нажимаю кнопку? Это был оригинальный вопрос :) Thks –

+0

Посмотрите на последнее предложение в моем ответе. Тогда поймите мой ответ. Тогда это придет к вам. – Tomalak

+0

Извините, но я действительно не понял. Может быть, мне не хватает того, что вы здесь делаете: $ (element) [visible? "fadeIn": "fadeOut"](); –

Смежные вопросы