【问题标题】:Polymer 2 TypeError on Local DOM element when Event triggered事件触发时本地 DOM 元素上的 Polymer 2 TypeError
【发布时间】:2018-05-09 20:20:56
【问题描述】:

我有一个用于接收用户输入的搜索输入字段和一个响应用户输入的可变状态按钮。注意搜索输入上的on-input 事件。

<dom-module id="app-search">
    <template>
        
        <input type="search" id="searchInput" on-input="_onInput" />

        <!-- NOTE: button is set to 'disabled' when there is no value of search field -->
        <paper-button disabled>Done</paper-button>

    </template>
</dom-module>

在 Polymer ready() 定义中,我得到了 paper-button 元素的句柄(ready() 函数在所有内容之后调用,包括在元素及其属性已初始化之后,因此现在是查询本地 DOM)。

ready() {
    super.ready(); // must call this for Polymer to work

    // get handle to paper-button element
    this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');
}

(顺便说一下,我知道使用this.$ 可以用作Polymer.dom(this.root).querySelector() 的语法快捷方式,但该语法似乎只适用于定位本地DOM 中具有id,例如:this.$.searchInput 将返回带有 id="searchInput" 的元素的句柄。有谁知道无需输入 Polymer.dom(this.root)... 即可定位非 id 常规元素的速记 ?)

我有一个函数可以在搜索字段中检测input 事件。如果搜索字段中有值,请启用该按钮。

_onInput() {
    // if search input has value
    if (Boolean(this.$.searchInput.value)) {
        // remove disabled attr from button
        this._doneBtn.removeAttribute('disabled');
    } else {
        this._disableBtn();
    }
}

_disableBtn() {
    this._doneBtn.setAttribute('disabled', true);
}

到目前为止,这可以在用户开始输入时启用按钮;当没有值时,按钮将被禁用。

不过,按照惯例,用户也可以通过点击搜索输入右侧的小“x”来删除输入值。开发人员可以通过将search 事件附加到输入元素来检测该事件:

ready() {
    super.ready(); // must call this for Polymer to work

    // get handle to paper-button element
    this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');

    // attach 'search' event listener to search input field
    // call the element's '_disableBtn' function
    this.$.searchInput.addEventListener('search', this._disableBtn);
}

问题是,当我通过单击搜索字段有值时出现的“x”触发事件时,this._disableBtn 函数会触发,但函数内部的this._doneBtn 返回未定义Uncaught TypeError: Cannot read property 'setAttribute' of undefined.

假设这可能与不正确的类型定义有关,我尝试在 Polymer 属性 getter 中声明 _doneBtn 属性:

static get properties() {
    return {
        _doneBtn: Object // also tried 'String'
    }
}

我还尝试再次从 _disabledBtn 函数内部查询 DOM 并尝试重新声明该属性,但仍然遇到相同的错误:

_disableBtn() {
    if (!this._doneBtn) {
        this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');
    }
    this._doneBtn.setAttribute('disabled', true);
}

谁能理解这里发生了什么?这似乎与事件监听器有关。尽管在 ready() 调用中切换声明的顺序并没有什么不同,但也许 DOM 在解析之前并未完全呈现?它也可能与this 有关。

有趣的是,当我在_disableBtn 中使用console.log(this) 时,控制台会返回两个不同的this 实例,一个用于宿主元素(&lt;app-search&gt;),另一个用于触发事件的目标元素:two elements point to 'this'。另外值得注意的是this的打印顺序。

我希望比我更聪明的人可以帮助解决这里发生的事情。

【问题讨论】:

    标签: javascript events polymer dom-events polymer-2.x


    【解决方案1】:

    我的直觉是你没有正确使用“this”。 “this” 表达式是违反直觉的,因为我们倾向于自动将它与词法范围或使用“this”的位置相关联。唉,情况并非如此,因为“this”绑定不是在 JIT“编译时”或“运行时”确定的,而是在“调用时”确定的。

    this 表示调用它的上下文。因此,只需将一行代码从一个函数移动到另一个函数,“this”就可以引用其他内容。并且其他东西可能没有附加“setAttribute”函数,因此出现“未定义”错误消息。

    解决这个(没有双关语)现实的一种方法是使用 .bind([调用该函数时我们希望“this”具有的值])配置被调用函数。

    例如,不要写下面的sn-p:

    } else {
        this._disableBtn();
    }
    

    你会写的

    } else {
        this._disableBtn().bind(this);
    }
    

    您会确保您在 _disableBtn() 函数中使用的“this”指向与“else”块中的“this”相同的目标。

    基本上,“this”值取决于调用它的函数的原始调用站点上下文(我不确定这是否清楚......但如果它没有意义,请慢慢重读第一次飞行)。要在被调用函数中硬编码“this”的值,您可以在调用函数时添加 .bind("this" value 您要传递给被调用函数),例如:

    function aFunction() {
       myfunction(parameter).bind("required value of 'this' in myFunction").
    }
    

    希望这会有所帮助。

    杰克

    【讨论】:

    • 我认为你在做某事。我刚刚发布了我的解决方案。感谢您的详细回答。
    • @Peak 谢谢,如果它对您的问题有帮助,请您投赞成票。谢谢。
    【解决方案2】:

    阅读@softjake 的回复后,我能够解决问题。

    首先,让我们回顾一下ready() 函数中添加的addEventListener() 设置:

    ready() {
        super.ready();
    
        // handle to toggle button element
        this._doneBtn = Polymer.dom(this.root).querySelector('paper-button');
    
        // previous method === no worky
        //this.$.searchInput.addEventListener('search', this._disableBtn);
    
        // changed it to:
        this.$.searchInput.addEventListener('search', this._disableBtn.bind(this._doneBtn));
    }
    

    这里的关键是我使用.bind(this._doneBtn) 来确保this_disableBtn 函数的范围内引用this._doneBtn 而不是其他this(如父元素或文档/窗口)。

    最后稍微调整_disableBtn函数:

    _disableBtn() {
        // previous (also no worky)
        //this._doneBtn.setAttribute('disabled', true);
    
        // changed to:
        this.setAttribute('disabled', true);
    }
    

    因为this已经引用了this._doneBtn,我们可以简单地使用this.setAttribute(...)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2018-10-21
      • 2011-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多