2016-11-10 159 views
0

我从使用Grunt作为构建工具切换到Webpack。过渡是相对平稳。至少直到我注意到我遇到以下问题。子视图更改事件未触发

我目前在我的应用程序中有许多Backbone视图,并且在我移动时使用工厂方法实例化和垃圾收集。通过我的子视图change将我的项目转换为Webpack后,事件不再发射(也就是说,它之前正在发射,所以我知道它在某个时刻起作用)。

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; 
    } 
}); 

它也可能是值得注意的是我生成的事件,当用户进入父视图在for循环中的子视图生成以非正常的主干方式通过字符串连接并更改事件数组。这是因为我需要为我的HTML元素指定唯一的ID。

我的第一个想法是,可能由于某些原因,新的webpack实现没有正确连接事件。我试图通过调用this.delegateEvents()来解决这个问题,但没有成功。

我的下一个想法是,可能事件不在视图范围内,或者以某种方式分离,因此我确认input元素在视图中可附加事件。也不是问题。

我认为什么是最令人费解的这个情况是,如果我改变change事件到click事件它工作完全正常,并触发相应的功能:

var inputEventKey = 'click' + ' .input-' + this.options.data.formattedDate; 

UPDATE(其他数据):

子视图模板:

<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驱动我的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

UPDATE(16年11月14日):经过unsuccesfully试图将CONTRO内复制该(plunkr等)我决定开始慢慢地向后工作来诊断问题。到目前为止,我发现这个问题不是来自webpack,而是来自我项目的模块化。我从每个文件的快速脚本标记转到根目录index.js并导入了所有依赖模块,这似乎是事情开始出错的地方。

+0

没有模板和/或webpack配置或[mcve],不可能发现问题。 –

+1

感谢您的快速回复@EmileBergeron!要更改我的文件以反映您的建议并回报。 – wootencl

回答

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(); 

然后在子的看法,我会移动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; 
    } 
}); 
+1

这种方式仍然不幸运。虽然我认为你对清理我的观点的建议有希望让我指出正确的方向。将在今晚/明天晚些时候报告我的调查结果。再次感谢您的帮助! – wootencl

+1

@wootencl很高兴帮助;)另一个问题,它真的与webpack有关吗?如果只采用相关的视图/模板并创建最小的可运行片段,会怎么样? –

+1

好问题。我认为它是webpack,因为当我从Grunt迁移到webpack时,我开始注意到这个问题,尽管可能并非如此。如果我今晚无法弄清楚,我可能会尝试创建一个plunkr(或类似的东西),看看我是否可以重新创建这个问题。 – wootencl