#javascript #events #backbone.js #view #amd
#javascript #Мероприятия #backbone.js #Вид #amd
Вопрос:
Я разрабатываю небольшой проект в попытке научиться backbone.js и я использую AMD (рекомендовано в руководстве). У меня есть дочернее представление для «Элемента управления спортсменом», в основном представление, которое я планирую повторно использовать на других страницах / представлениях. Событие щелчка в дочернем представлении (AthleteView) не срабатывает.
AthleteView отображается в div в TimerView, а TimerView отображается в div с идентификатором «страница» на индексной странице. Я включил все, что приведено ниже, поскольку подозреваю, что проблема может быть в том, как я все настраиваю.
Основной Вид:
define([
'jquery',
'underscore',
'backbone',
'views/SettingsView',
'views/AthleteControlView',
'text!templates/timerTemplate.html',
'timer'
], function($, _, Backbone, SettingsView, AthleteView, timerTemplate){
var TimerView = Backbone.View.extend({
el: $("#page"),
render: function(){
this.$el.html(timerTemplate);
var settingsView = new SettingsView();
settingsView.render();
var athleteView = new AthleteView();
athleteView.render();
console.log('rendered Timer');
}
});
return TimerView;
});
Дочерний вид:
define([
'jquery',
'underscore',
'backbone',
'text!templates/AthleteControlTemplate.html',
'jqueryui'
], function($, _, Backbone, keypadTemplate){
var AthleteView = Backbone.View.extend({
el: $("#AthleteControl"),
events: {
'click': 'clickHandler'
},
render: function(){
$("#AthleteControl").html(keypadTemplate);
console.log('rendered AthleteControl');
},
clickHandler: function()
{
alert('click');
console.log('click');
}
});
return AthleteView;
});
ROUTER.JS
define([
'jquery',
'underscore',
'backbone',
'views/TimerView'
], function($, _, Backbone, TimerView) {
var AppRouter = Backbone.Router.extend({
routes: {
'*actions': 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:defaultAction', function (actions) {
var timerView = new TimerView();
timerView.render();
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
Index.html
<html>
<head>
<script data-main="js/main" src="js/libs/require/require.js"></script>
</head>
<body>
<div id="page">
Loading....
</div>
<div id="footer"></div>
</div>
</body>
</html>
ШАБЛОН ТАЙМЕРА:
<div class = "Controls">
<button id="Start">Start</button>
<button id="Stop">Stop</button>
<button id="Reset">Reset</button>
</div>
<div id="AthleteControl"></div>
Комментарии:
1. Существуют ли
#AthleteControl
и#page
при загрузке ваших представлений? Использованиеel: $(...)
почти всегда плохая идея, IMO. Я думаю,el: 'some selector string'
что это тоже плохая идея, позволяя каждому представлению создавать свое собственноеel
и позволяя вызывающему пользователю размещать его на странице, обходя всевозможные проблемы.2. Я включил дополнительные файлы, чтобы продемонстрировать, как все загружается в данный момент (извиняюсь, если это излишне). Я думаю, что оба существуют при загрузке представлений, но моего понимания того, как это работает на самом деле, все еще не хватает. Не могли бы вы проиллюстрировать, что вы имеете в виду, позволяя каждому представлению создавать свой собственный el и т.д.? Спасибо
Ответ №1:
Таким образом, id="AthleteControl"
элемент поступает изнутри timerTemplate.html
. Это означает, что $('#AthleteControl")
ничего не найдет при выполнении этого кода:
var AthleteView = Backbone.View.extend({
el: $("#AthleteControl"),
Это означает, что AthleteView
в конечном итоге будет вести себя так, как если бы вы сказали:
var AthleteView = Backbone.View.extend({
el: undefined,
Если вы не укажете представление el
явно, представление создаст пустое <div>
значение el
. Такие вещи, как:
el: $("some-selector")
почти всегда ошибка из-за проблем с синхронизацией. Вместо этого просто используйте строку селектора и позвольте Backbone преобразовать ее в узел DOM, когда это необходимо:
el: "some-selector"
Быстрое исправление должно заключаться в отмене jQuery el
s:
el: '#page'
el: '#AthleteControl'
Что касается «позволить представлениям создавать свои собственные el
s», вы позволяете представлениям создавать свои собственные узлы DOM для использования в качестве своих el
вместо того, чтобы пытаться привязать представления к el
s, которые уже есть на странице. Этот подход:
- Делает ваши представления более автономными.
- Помогает уменьшить конфликты привязки событий, поскольку ваше приложение становится больше и включает в себя больше просмотров.
- Помогает уменьшить утечки памяти, поскольку каждое представление имеет один узел DOM (и наоборот) во время работы приложения.
- Удаление представления — это простой
view.remove()
вызов, а не ручная очистка привязок событий и HTML. Если у вас есть подвиды, то вы бы переопределилиremove
в своем представлении вызовremove
подвидов перед подключением кremove
реализации по умолчанию.
Этот подход (без AMD/require.js материал для ясности) будет больше похоже на следующее.
HTML:
<script id="timerTemplate" type="text/x-underscore">
<div class="Controls">
<button id="Start">Start</button>
<button id="Stop">Stop</button>
<button id="Reset">Reset</button>
</div>
</script>
<div id="page">
</div>
JavaScript:
var AthleteView = Backbone.View.extend({
id: 'AthleteControl',
render: function() {
this.$el.html('Athlete control stuff goes here.');
return this; // This is standard practice, you'll see why below.
}
});
var TimerView = Backbone.View.extend({
render: function () {
var tmpl = _.template($('#timerTemplate').html());
this.$el.html(tmpl());
var athleteView = new AthleteView();
this.$el.append(athleteView.render().el);
return this;
}
});
var timer_view = new TimerView;
$('#page').html(timer_view.render().el);
Обратите внимание на return this
в render
методах и обратите внимание, как this.$el.html
и this.$el.append
используются для построения и объединения представлений.
Демонстрация:http://jsfiddle.net/ambiguous/r4tsA/1 /
Комментарии:
1. Спасибо за этот исчерпывающий ответ, высоко ценится. Это исправило проблему, и я начинаю лучше понимать. Я бы поддержал ваш ответ, но пока у меня нет необходимой репутации, но я сделаю это, как только сделаю. Приветствия
Ответ №2:
Чтобы привязать событие к действию, вам нужно указать, какой элемент прослушивает какое событие, например
.., var AthleteView = Backbone.View.extend({
..
events: {
'click button.btn': 'doSomething'
},
..
doSomething: function(e) {
// code goes here
},
..
Комментарии:
1. Я боюсь, что это не сработает. Я добавил простую кнопку и сделал именно это, но без радости.
2. Неверно.
'click': 'doSomething'
вevents
привязывает событие щелчка кel
самому представлению, в документации даже говорится об этом: «Исключениеselector
приводит к привязке события к корневому элементу представления (this.el
)».