我已经定义了一个像这样的js“类”:
var TelephoneFormGroup = function(targetId, removePhoneCallback) {
this.phone = '';
this.phone_type_options = [];
this.counter = 0;
this.targetId = targetId;
this.form_group = {};
this.removePhone = removePhoneCallback;
this.buildFormGroup = function() {
var outerDiv = document.createElement('div');
outerDiv.className = 'form-group';
var label = document.createElement('label');
label.className = 'label-control col-sm-3';
var innerDiv = document.createElement('div');
innerDiv.className = 'col-sm-8';
var inputId = document.createElement('input');
inputId.type = 'hidden';
inputId.name = 'data[Telephone][' + this.counter + '][id]';
var inputPhoneTypeId = document.createElement('select');
inputPhoneTypeId.name = 'data[Telephone][' + this.counter + '][phone_type_id]';
inputPhoneTypeId.className = 'form-control col-sm-3';
var removePhoneIcon = document.createElement('i');
removePhoneIcon.className = "glyphicon glyphicon-remove";
var removePhoneLink = document.createElement('a');
removePhoneLink.appendChild(removePhoneIcon);
removePhoneLink.title = "Remover Telefone";
removePhoneLink.href = "#";
removePhoneLink.dataset.toggle = "tooltip";
removePhoneLink.onclick = this.removePhone;
label.appendChild(removePhoneLink);
label.innerHTML += 'Telefone ' + this.counter;
var that = this;
Object.keys(this.phone_type_options).forEach( function(key) {
inputPhoneTypeId.options[inputPhoneTypeId.options.length] = new Option(that.phone_type_options[key], key);
});
var inputPhone = document.createElement('input');
inputPhone.type = 'text';
inputPhone.name = 'data[Telephone][' + this.counter + '][phone]';
inputPhone.className = 'form-control phone col-sm-9';
outerDiv.appendChild(label);
outerDiv.appendChild(innerDiv);
innerDiv.appendChild(inputId);
innerDiv.appendChild(inputPhoneTypeId);
innerDiv.appendChild(inputPhone);
this.form_group = outerDiv;
},
this.render = function() {
if (this.targetId == null || this.targetId == '') throw 'Empty target id';
if (typeof(this.targetId) === 'string') {
document.getElementById(this.targetId).appendChild(this.form_group);
} else if (typeof(this.targetId === 'object')) {
this.targetId.appendChild(this.form_group);
};
}
};
我的问题是removePhoneLink.onclick = this.removePhone;
没有在webkit浏览器上触发。在Firefox(mac)上正常工作,但它不适用于safari / chrome(mac),safari / chrome(ipad)。
我错过了什么?
谢谢!
答案 0 :(得分:1)
tl; dr 在附加事件处理程序
之前将元素附加到DOM感谢有趣的案例。经过几次尝试后,我认为WebKit在注册事件处理程序之前需要附加到DOM的元素(偶然发现Todd Motto's example,他在附加事件处理程序之前确实使用jQuery获取元素!)
这是代码的a working fiddle,注释。 主要是,我添加了一个在render方法之后调用的bindEventHandlers方法,使用chained方法(la jQuery)将整个对象变成一个流畅的接口,在“class”上添加了一个静态计数器。 简短摘录:
跟踪实例化的对象数
TelephoneFormGroup.counter = ++TelephoneFormGroup.counter || 0;
this.counter = TelephoneFormGroup.counter;
将回调封装在一个方法中并用apply
调用它(确保在正确的对象上调用该方法,在另一个项目中遇到这个问题)
this.removePhone = function(){
removePhoneCallback.apply(this);
};
将this
绑定到Object.keys
的{{1}} {已移除的forEach
技巧
var that=this;
因为Object.keys(this.phone_type_options).forEach( function(key) {
inputPhoneTypeId.options[inputPhoneTypeId.options.length] = new Option(this.phone_type_options[key], key);
}.bind(this));
// Here, we tell forEach we want 'this' to be bound to the object, not the current item being iterated over (i.e. that=this trick)
构造现在构建在两个阶段(构建标记,然后附加事件处理程序),我们使用动态创建的id耦合它
removePhoneLink
我希望它适用于您的用例。我在Chrome和Safari(Mac OS X Yosemite)上尝试过它。
编辑:我发现你的代码很有趣,简单,但却足够复杂,我想了一段时间的小测试。您的所有方法都绑定到实例化的对象。使用JavaScript和原型模式,您应该将方法添加到对象的原型中(如this fiddle for your code中所示)
我做了一个小基准来比较两种技术,检查内存使用情况和完成方法的时间(machine spec)
我会使用Chrome Developer工具(堆大小运行,运行之间刷新,然后渲染时间运行,运行之间刷新)。
查找the results there (fiddle.md)。
正如您所看到的,在实例化50个对象之前,它不会产生太大差异。然后使用原型渲染速度提高18%,内存使用率提高到近30%(运行50'000个对象)。
所以我想在生产中使用原型?