在webkit上没有调用Javascript对象回调

时间:2016-01-31 14:49:56

标签: javascript google-chrome safari webkit

我已经定义了一个像这样的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)。

我错过了什么?

谢谢!

1 个答案:

答案 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个对象)。 所以我想在生产中使用原型?