Javascript webkit 上未调用对象回调
Javascript object callback not being called on webkit
我定义了一个 js "class" 这样的:
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).
上不工作
我错过了什么?
谢谢!
tl;dr 在附加事件处理程序之前将元素附加到 DOM
感谢您提供有趣的案例。几次尝试后,我认为 WebKit 在注册事件处理程序之前需要附加到 DOM 的元素(偶然发现 Todd Motto's example,他在附加事件处理程序之前确实获得了带有 jQuery 的元素! )
这是您的代码 a working fiddle,带有注释。
主要是,我在 render 方法之后添加了一个调用的 bindEventHandlers 方法,使整个对象成为一个带有链接方法的流畅接口(a la jQuery),在 "class" 上添加了一个静态计数器。
简短摘录:
跟踪实例化了多少对象
TelephoneFormGroup.counter = ++TelephoneFormGroup.counter || 0;
this.counter = TelephoneFormGroup.counter;
将回调封装在一个方法中并用 apply
调用它(确保在正确的对象上调用该方法,在另一个项目上有一些问题)
this.removePhone = function(){
removePhoneCallback.apply(this);
};
将 this
绑定到您的 Object.keys
的 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)
由于 removePhoneLink
构造现在分两个阶段构建(构建标记,然后附加事件处理程序),我们使用动态创建的 id
将其耦合
...
// in buildFormGroup()
removePhoneLink.id = "btnRemove"+this.targetId;
...
// called after attaching the form group to the dom
this.bindEventHandlers = function() {
document.getElementById("btnRemove"+this.targetId).onclick = function(e) {
this.removePhone();
}.bind(this);
}
我希望它适用于您的用例。我在 Chrome 和 Safari (Mac OS X Yosemite).
上试过了
edit : 我发现您的代码有趣、简单,但对于我考虑了一段时间的小测试来说足够复杂了。您的所有方法都绑定到实例化对象。使用 JavaScript 和原型模式,您应该向对象的原型添加方法(如 this fiddle for your code)。
我做了一个小的基准测试来比较这两种技术,检查内存使用情况和完成方法的时间 ()。
我会使用 Chrome 开发人员工具(堆大小 运行s,在 运行s 之间刷新,然后渲染时间 运行s,在 运行s 之间刷新)。
查找 the results there (fiddle.md).
如您所见,在实例化 50 个对象之前,它不会产生太大差异。然后,您可以使用原型将渲染速度提高 18%,并且内存使用率提高近 30%(对于 50'000 个对象 运行)。
所以我想对于生产用途,去寻找原型?
我定义了一个 js "class" 这样的:
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).
我错过了什么?
谢谢!
tl;dr 在附加事件处理程序之前将元素附加到 DOM
感谢您提供有趣的案例。几次尝试后,我认为 WebKit 在注册事件处理程序之前需要附加到 DOM 的元素(偶然发现 Todd Motto's example,他在附加事件处理程序之前确实获得了带有 jQuery 的元素! )
这是您的代码 a working fiddle,带有注释。 主要是,我在 render 方法之后添加了一个调用的 bindEventHandlers 方法,使整个对象成为一个带有链接方法的流畅接口(a la jQuery),在 "class" 上添加了一个静态计数器。 简短摘录:
跟踪实例化了多少对象
TelephoneFormGroup.counter = ++TelephoneFormGroup.counter || 0; this.counter = TelephoneFormGroup.counter;
将回调封装在一个方法中并用
apply
调用它(确保在正确的对象上调用该方法,在另一个项目上有一些问题)this.removePhone = function(){ removePhoneCallback.apply(this); };
将
this
绑定到您的Object.keys
的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)
由于
将其耦合removePhoneLink
构造现在分两个阶段构建(构建标记,然后附加事件处理程序),我们使用动态创建的 id... // in buildFormGroup() removePhoneLink.id = "btnRemove"+this.targetId; ... // called after attaching the form group to the dom this.bindEventHandlers = function() { document.getElementById("btnRemove"+this.targetId).onclick = function(e) { this.removePhone(); }.bind(this); }
我希望它适用于您的用例。我在 Chrome 和 Safari (Mac OS X Yosemite).
上试过了edit : 我发现您的代码有趣、简单,但对于我考虑了一段时间的小测试来说足够复杂了。您的所有方法都绑定到实例化对象。使用 JavaScript 和原型模式,您应该向对象的原型添加方法(如 this fiddle for your code)。
我做了一个小的基准测试来比较这两种技术,检查内存使用情况和完成方法的时间 (
我会使用 Chrome 开发人员工具(堆大小 运行s,在 运行s 之间刷新,然后渲染时间 运行s,在 运行s 之间刷新)。
查找 the results there (fiddle.md).
如您所见,在实例化 50 个对象之前,它不会产生太大差异。然后,您可以使用原型将渲染速度提高 18%,并且内存使用率提高近 30%(对于 50'000 个对象 运行)。
所以我想对于生产用途,去寻找原型?