我从使用Grunt作为我的构建工具切换到Webpack。转换相对平滑。至少直到我注意到我遇到的以下问题。
我目前在我的应用程序中有很多Backbone视图,并且在我移动时使用工厂方法实例化和垃圾收集。将我的项目转换为Webpack之后,虽然我的一个子视图change
事件不再触发(也就是说它之前已经触发,所以我知道它在某些时候起作用)。当用户在for循环中输入父视图时生成子视图:
for (var i=0; i<this.dayIds.length; i++) {
this.timeSelectorDayViews[i] = new timeSelectorDay({
el: '#timePickersWrapper',
data: {
time: this.model.get(this.dayIds[i]),
date: moment(this.model.get('weekStartDate')).add(i, 'd')
}
}).render();
}
以下是子视图代码:
'use strict';
import { app } from '../app';
export const timeSelectorDay = Backbone.View.extend({
initialize: function(data) {
this.options = data;
this.options.data.formattedDate = moment(this.options.data.date).format('YYYY-MM-DD');
this.events = _.clone(this.events) || {};
var inputEventKey = 'change' + ' .input-' + this.options.data.formattedDate;
this.events[inputEventKey] = 'inputCheck';
this.totalHours = 0;
},
render: function(){
this.template = _.template(app.createTemplate('templates/timeSelectorDay.tpl', this.options.data));
$(this.options.el).append(this.template({}));
this.delegateEvents();
this.checkTotalTime();
return this;
},
inputCheck: function() {
...
... //Doing some computational logic here
...
app.event_bus.trigger('totalTime');
app.event_bus.trigger('inputChange');
},
checkTotalTime: function(){
var totalTimeDiv = document.getElementById('totalHours-'+this.options.data.formattedDate);
var totalTime = parseFloat(totalTimeDiv.innerHTML);
if (totalTime>0) {
totalTimeDiv.style.backgroundColor = '#69a776';
} else {
totalTimeDiv.style.backgroundColor = '#dd3c3c';
}
this.totalHours = totalTime;
}
});
值得注意的是,我通过字符串连接以及更改事件数组以非正常骨干方式生成事件。这是因为我需要为HTML元素分配唯一ID。
我的第一个想法是,由于某种原因,可能由于新的webpack实现而没有正确附加事件。我尝试通过调用this.delegateEvents()
解决此问题但没有成功。
我的下一个想法是,事件可能不属于视图范围或者以某种方式被分离,因此我确认input
元素是视图中可附加的事件。也不是问题。
我认为对于这种情况最令人费解的是,如果我将change
事件更改为click
事件,它可以完美地运行并触发相应的函数:
var inputEventKey = 'click' + ' .input-' + this.options.data.formattedDate;
更新(附加数据):
子视图模板:
<div id="timeselectors-<%= formattedDate%>" class="row small-collapse medium-uncollapse margin-bottom border">
<div class="small-12 columns"><%= moment(date).format('dddd') %> (<%= moment(date).format('MM/DD/YYYY') %>)</div>
<div class="small-10 columns">
<div class="row small-collapse">
<div class="small-5 medium-2 columns morning">
<input id="morning-login" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Login"/>
</div>
<div class="small-1 medium-1 columns morning dash"> - </div>
<div class="small-5 medium-2 columns morning">
<input id="morning-logout" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Logout"/>
</div>
<div class="small-5 medium-2 medium-offset-1 columns afternoon">
<input id="afternoon-login" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Login"/>
</div>
<div class="small-1 medium-1 columns afternoon dash"> - </div>
<div class="small-5 medium-2 columns afternoon end">
<input id="afternoon-logout" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Logout"/>
</div>
</div>
</div>
<div id="totalHours-<%= formattedDate%>" class="small-2 columns hours">
<%= time %>
</div>
</div>
至于我的webpack配置,我使用gulp作为我的webpack驱动程序,但是这里是我传递给webpack实例的配置:
{
entry: './src/app/client-app/index.js',
output: {
path: path.join(__dirname, 'dist/app/js'),
filename: 'app.bundle.js'
},
plugins: [
new webpack.ProvidePlugin({
'_': 'lodash'
})
],
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loaders: ['babel'] },
]
}
}
webpack条目文件:
// import 'babel-polyfill';
import 'script!jquery';
import 'script!lodash';
// import 'script!what-input';
import Backbone from 'backbone';
import 'backbone-validation';
import 'script!jquery.cookie';
import 'script!moment';
import 'script!fastclick';
import 'script!clndr';
import 'script!timepicker';
import 'script!foundation-sites/js/foundation';
import { app } from './app';
$(document).ready(function () {
app.init();
//Initialize Foundation
$(document).foundation();
});
除了我应该提到的所有内容之外,如果您想要克隆存储库并重现问题,所有代码都可以在github上公开获取:
https://github.com/wootencl/timeSheetApplication/tree/ProjectRewrite
更新(2016年11月14日):在一个受控环境(plunkr等)中不成功地尝试复制之后,我决定开始慢慢地向后工作来诊断问题。到目前为止,我发现问题不是来自webpack,而是来自我项目的模块化。我从每个文件的brash脚本标记到导入所有依赖模块的根index.js
,这似乎是事情开始出错的地方。
答案 0 :(得分:1)
虽然我无法用提供的代码发现问题,但我可以开始指出一些可以改进的事情。
首先,我会直接传递自定义选项,不需要嵌套的data
对象。
this.timeSelectorDayViews[i] = new timeSelectorDay({
el: '#timePickersWrapper',
time: this.model.get(this.dayIds[i]),
date: moment(this.model.get('weekStartDate')).add(i, 'd')
}).render();
然后在子视图中,在Backbone使用提供的events
创建调用setElement
之前,我会将el
更改移动到构造函数中。
export const timeSelectorDay = Backbone.View.extend({
// The template should be compiled once here, then used in the render function.
template: _.template(app.createTemplate('templates/timeSelectorDay.tpl')),
constructor: function(options) {
this.options = _.extend({
/* default options could go here */
}, options); // make a copy and use it.
this.options.formattedDate = moment(this.options.date).format('YYYY-MM-DD');
// change the events hash before delegating the events.
// the constructor is a good place for this.
this.events['change .input-' + this.options.formattedDate] = 'inputCheck';
Backbone.View.prototype.constructor.apply(this, arguments);
},
initialize: function(options) {
this.totalHours = 0;
},
render: function() {
// use the $el directly, avoid global jQuery.
this.$el.html(this.template(this.options));
this.checkTotalTime();
return this;
},
inputCheck: function() {
// Doing some computational logic here
// ...snip...
app.event_bus.trigger('totalTime');
app.event_bus.trigger('inputChange');
},
checkTotalTime: function() {
// use Backbone's jQuery shortcut instead of the Javascript native
// api, it's easier and it is scoped to the view's el.
var totalTimeDiv = this.$('#totalHours-' + this.options.formattedDate),
totalTime = parseFloat(totalTimeDiv.html());
// I would avoid changing the css in favor of toggling a class.
// It would keep the style separated from the logic.
totalTimeDiv.css('background-color', totalTime > 0 ? '#69a776' : '#dd3c3c');
this.totalHours = totalTime;
}
});