我有这些被称为beats的div,我想在点击它们时注册。但是,我似乎无法通过单击它们或在控制台中的特定div上调用JQuery click事件来让它们注册一个单击。无论哪种方式,都没有注册。
measureView.js创建了这个beatView,它在父测量中创建了一个节拍。
beatView.js:
//filename: views/beats/beatView.js
/* This is the view for a single beat, which is contained in a measure view. */
define([ 'jquery', 'underscore', 'backbone', 'backbone/models/beat', 'text!backbone/templates/measures/audioMeasures.html', 'text!backbone/templates/beats/linearBarBeats.html', 'text!backbone/templates/beats/linearBarSVGBeats.html', 'text!backbone/templates/beats/circularPieBeats.html', 'app/dispatch', 'app/log'
], function($, _, Backbone, BeatModel, audioMeasuresTemplate, linearBarBeatsTemplate, linearBarSVGBeatsTemplate, circularPieBeatsTemplate, dispatch, log){
return Backbone.View.extend({
//registering backbone's click event to our toggle() function.
events : {
'click' : 'toggle'
},
//The constructor takes options because these views are created by measuresView objects.
initialize: function(options){
if (options) {
console.log('options :');
console.warn(options);
this.model = options.model;
// this.parentEl should be measure.cid
this.measureBeatHolder = options.parentElHolder;
} else {
console.log('never really getting here');
this.model = new BeatModel;
}
this.render();
},
//We use css classes to control the color of the beat. A beat is essentially an empty div.
render: function(toggle){
var state = this.getSelectionBooleanCSS();
if (toggle) {
$('#beat'+toggle).removeClass(state);
$('#beat'+toggle).addClass(this.switchSelectionBooleanValue());
} else {
var compiledTemplate = _.template(this.representations[this.currentBeatRepresentation], {beat: this.model, beatAngle: this.beatAngle, state: state});
$(this.measureBeatHolder).append( compiledTemplate );
return this;
}
},
getSelectionBooleanCSS: function(){
if (this.model.get("selected")) {
return "ON";
} else {
return "OFF";
}
},
switchSelectionBooleanValue: function(){
if (this.model.get('selected') == true) {
this.model.set('selected', "false");
} else {
this.model.set('selected', "true");
}
return this.model.get('selected');
},
/*
This is called when a beat is clicked.
It does a number of things:
1. toggles the model's selected field.
2. re-renders the beat.
3. prints a console message.
4. tells log to send a log of the click event.
5. triggers a beatClicked event.
*/
toggle: function(){
console.log('getting to toggle function');
var selectedBool = this.model.get("selected");
this.model.set("selected", !selectedBool);
var newBool = this.model.get("selected");
this.render(this.model.cid);
dispatch.trigger('beatClicked.event');
}
});
});
用于参考:
beatModel:
//filename: models/beat.js
/*
This is the beat model.
It only knows about whether or not it
is selected.
*/
define([
'underscore',
'backbone'
], function(_, Backbone) {
var beatModel = Backbone.Model.extend({
defaults: {
selected: false,
state: 'OFF'
},
initialize: function(){
},
getStyleClass: function() {
if (this.selected) {
return 'ON';
}
else {
return 'OFF';
}
}
});
return beatModel;
});
measureModel:
//filename: models/measure.js
/*
This is the measure model.
A component has a collection of these models.
these models have a collection of beats.
*/
define([
'underscore',
'backbone',
'backbone/collections/beats'
], function(_, Backbone, beatsCollection) {
var measureModel = Backbone.Model.extend({
defaults: {
label: '0/4',
beats: beatsCollection,
numberOfBeats: 0,
divisions: 8
},
initialize: function(){
}
});
return measureModel;
});
measureView.js:
// Filename: views/measures/measuresView.js
/*
This is the MeasuresView.
This is contained in a ComponentsView.
*/
define([
'jquery',
'underscore',
'backbone',
'backbone/collections/measures',
'backbone/collections/beats',
'backbone/models/measure',
'backbone/views/beats/beatView',
'text!backbone/templates/measures/audioMeasures.html',
'text!backbone/templates/measures/linearBarMeasures.html',
'text!backbone/templates/measures/linearBarSVGMeasures.html',
'text!backbone/templates/measures/circularPieMeasures.html',
'app/dispatch',
'app/state',
'app/log'
], function($, _, Backbone, MeasureModel, BeatsCollection, MeasuresCollection, beatView, audioMeasuresTemplate, linearBarMeasuresTemplate, linearBarSVGMeasuresTemplate, circularPieMeasuresTemplate, dispatch, state, log){
return Backbone.View.extend({
// el: $('.component'),
// The different representations
representations: {
"audio": audioMeasuresTemplate,
"linear-bar": linearBarMeasuresTemplate,
"linear-bar-svg": linearBarSVGMeasuresTemplate,
"circular-pie": circularPieMeasuresTemplate
},
currentMeasureRepresentation: 'linear-bar',
//registering click events to add and remove measures.
events : {
'click .addMeasure' : 'add',
'click .delete' : 'remove'
},
initialize: function(options){
//if we're being created by a componentView, we are
//passed in options. Otherwise we create a single
//measure and add it to our collection.
if (options) {
this.measuresCollection = options.collection;
this.parent = options.parent;
this.el = options.el;
}
// else {
// this.measure = new BeatsCollection;
// for (var i = 0; i < 4; i++) {
// this.measure.add();
// }
// this.measuresCollection = new MeasuresCollection;
// this.measuresCollection.add({beats: this.measure});
// }
if (options["template-key"]) {
this.currentBeatRepresentation = options["template-key"];
}
//registering a callback for signatureChange events.
dispatch.on('signatureChange.event', this.reconfigure, this);
//Dispatch listeners
dispatch.on('measureRepresentation.event', this.changeMeasureRepresentation, this);
this.render();
//Determines the intial beat width based on the global signature. Has to be below this.render()
this.calcBeatWidth(this.parent.get('signature'));
},
changeMeasureRepresentation: function(representation) {
this.currentMeasureRepresentation = representation;
this.render();
},
render: function(){
$(this.el).html('<div class="addMeasure">+</div>');
var measureCount = 1;
//we create a BeatsView for each measure.
_.each(this.measuresCollection.models, function(measure) {
// when representation button changes, the current representation template will get updated
var compiledTemplate = _.template( this.representations[this.currentMeasureRepresentation], {measure: measure, beatHolder:"beatHolder"+measure.cid, measureCount:measureCount, measureAngle: 360.0 } );
$(this.el).find('.addMeasure').before( compiledTemplate );
console.log('measure beats: ');
console.warn(measure.get('beats').models);
_.each(measure.get('beats').models, function(beat) {
// console.warn("#beat"+beat.cid.toString());
new beatView({model:beat, parentElHolder:'#beatHolder'+measure.cid, parentCID:measure.cid, singleBeat:"#beat"+beat.cid});
}, this);
measureCount ++;
}, this);
return this;
},
/*
This is called when the user clicks on the plus to add a new measure.
It creates a new measure and adds it to the component.
It generates a string representing the id of the measure and the ids of
its beats and logs the creation.
Lastly, it triggers a stopRequest, because we can't continue playing until
all the durations get recalculated to reflect this new measure.
*/
add: function(){
console.log('add measure');
var newMeasure = new BeatsCollection;
for (var i = 0; i < this.parent.get('signature'); i++) {
newMeasure.add();
}
this.measuresCollection.add({beats: newMeasure});
//Logging
name = 'measure' + _.last(this.measuresCollection.models).cid + '.';
_.each(newMeasure.models, function(beats) {
name = name + 'beat'+ beats.cid + '.';
}, this);
log.sendLog([[3, "Added a measure: "+name]]);
//Render
this.render();
//Dispatch
dispatch.trigger('stopRequest.event', 'off');
},
/*
This is called when the user clicks on the minus to remove a measure.
*/
remove: function(ev){
if ($('#measure'+this.measuresCollection.models[0].cid).parent()) {
//removing the last measure isn't allowed.
if(this.measuresCollection.models.length == 1) {
console.log('Can\'t remove the last measure!');
return;
}
console.log('remove measure');
//we remove the measure and get its model.
var model = this.measuresCollection.get($(ev.target).parents('.measure').attr('id').replace('measure',''));
this.measuresCollection.remove(model);
//send a log event showing the removal.
log.sendLog([[3, "Removed a measure: measure"+model.cid]]);
//re-render the view.
this.render();
//trigger a stop request to stop playback.
dispatch.trigger('stopRequest.event', 'off');
dispatch.trigger('signatureChange.event', this.parent.get('signature'));
}
},
// This is triggered by signatureChange events.
reconfigure: function(signature) {
console.log('MeasureView.reconfigure(signature) : signature=' +signature);
/* if the containing component is selected, this
triggers a request event to stop the sound.
Then this destroys the beat collection and creates
a new collection with the number of beats specified
by the signature parameter.
*/
if ($(this.parent).hasClass('selected')) {
dispatch.trigger('stopRequest.event', 'off');
this.measure.reset();
for (var i = 0; i < signature; i++) {
this.measure.add();
}
//re-render the view.
this.render();
//recalculate the widths for each beat.
this.calcBeatWidth(signature);
dispatch.trigger('signatureChange.event', this.parent.get('signature'));
}
},
//This determines the width of each beat based on the
//number of beats per measure or 'signature'.
calcBeatWidth: function(signature) {
if ($(this.el).hasClass('selected')) {
var px = 100/$('.measure').css('width').replace(/[^-\d\.]/g, '');
var beatWidth = (100 - ((signature*1+1)*px))/signature;
$(this.el).children('.beat').css({
'width' : beatWidth+'%'
});
}
}
});
});
答案 0 :(得分:3)
Backbone获取您的events
对象,并将所有这些事件类型和选择器委托给视图el
。您希望事件注册的任何HTML都需要插入到视图的el
中,并且el
需要插入页面。
通常我会设置我的观点:
var myView = Backbone.View.extend({
id: 'myView',
events: {
'click li' : 'myEventCallback'
},
initialize: function() {
$('body').append(this.el); //el on the page now
this.render(); //fills up el with useful markup
},
render: function() {
//fills el with useful markup from a template
this.el.html( JST['myTemplate' ]() );
},
myEventCallback: function() {
//code for handling click events on the li's inside the el of this view
}
});
答案 1 :(得分:0)
感谢@AlexMcp和@PaulHoenecke的贡献。
我最终通过渲染
中的JQuery代理函数将上下文传递给自己 // add click handler to this beat
$("#beat"+this.model.cid).click($.proxy(this.toggle, this));
完成beatView.js文件:
//filename: views/beats/beatView.js
/*
This is the view for a single beat, which
is contained in a measure view.
*/
define([
'jquery',
'underscore',
'backbone',
'backbone/models/beat',
'text!backbone/templates/measures/audioMeasures.html',
'text!backbone/templates/beats/linearBarBeats.html',
'text!backbone/templates/beats/linearBarSVGBeats.html',
'text!backbone/templates/beats/circularPieBeats.html',
'app/dispatch',
'app/log'
], function($, _, Backbone, BeatModel, audioMeasuresTemplate, linearBarBeatsTemplate, linearBarSVGBeatsTemplate, circularPieBeatsTemplate, dispatch, log){
return Backbone.View.extend({
/* TODO still issues with this
el: '.beat',
registering backbone's click event to our toggle() function.
events : {
'click' : 'toggle'
},
*/
// The different representations
representations: {
"audio": audioMeasuresTemplate,
"linear-bar": linearBarBeatsTemplate,
"linear-bar-svg": linearBarSVGBeatsTemplate,
"circular-pie": circularPieBeatsTemplate
},
currentBeatRepresentation: 'linear-bar',
beatAngle: 90,
//The constructor takes options because these views are created
//by measuresView objects.
initialize: function(options){
if (options) {
// TODO: need to take in an option about currentBeatRep
// TODO: maybe need to respond to a representation changed event (change this.currentBeatRepresentation and rerender)
console.log('options :');
console.warn(options);
this.model = options.model;
// this is the html element into which this class should render its template
this.measureBeatHolder = options.parentElHolder;
this.el = options.singleBeat;
this.parent = options.parent;
} else {
console.error('should not be in here!');
this.model = new BeatModel;
}
this.render();
},
//We use css classes to control the color of the beat.
//A beat is essentially an empty div.
render: function(toggle){
// the current state of the beat (is it ON or OFF?)
var state = this.getSelectionBooleanCSS();
// if render is being called from the toggle function, we may want to do something different
if (toggle) {
$('#beat'+toggle).toggleClass("ON");
$('#beat'+toggle).toggleClass("OFF");
} else {
// this is reached during the initial rendering of the page
// compile the template for this beat (respect the current representation)
var compiledTemplate = _.template(this.representations[this.currentBeatRepresentation], {beat: this.model, beatAngle: this.beatAngle, state: state});
// append the compiled template to the measureBeatHolder
$(this.measureBeatHolder).append( compiledTemplate );
// add click handler to this beat
$("#beat"+this.model.cid).click($.proxy(this.toggle, this));
// $(this.parentEl).append(compiledTemplate);
return this;
}
},
getSelectionBooleanCSS: function(){
if (this.model.get("selected")) {
return "ON";
} else {
return "OFF";
}
},
/*
This is called when a beat is clicked.
It does a number of things:
1. toggles the model's selected field.
2. re-renders the beat.
3. prints a console message.
4. tells log to send a log of the click event.
5. triggers a beatClicked event.
*/
toggle: function(){
//switch the selected boolean value on the model
this.model.set('selected', !this.model.get('selected'));
//re-render it, passing the clicked beat to render()
this.render(this.model.cid);
// log.sendLog([[1, "beat" + this.model.cid + " toggled: "+!bool]]);
dispatch.trigger('beatClicked.event');
}
});
});
答案 2 :(得分:0)
实际上......您需要做的就是在视图的初始化函数中定义事件。