我决定尝试通过编写自定义元素来创建本机 Web 组件。
export default class DropDown extends HTMLElement {
...
当我把一切都准备好后,一切似乎都运转良好。但后来我决定添加一些回调挂钩,以便应用程序可以响应组件上的事件。
添加它们的逻辑位置是在构造函数中,对吧?
/**
*
* @param {Object} callbacks
* @param {Function} callbacks.itemSelected
* @param {Function} callbacks.dropDownClicked
*/
constructor(callbacks = {}) {
super();
if (callbacks) this.#callbacks = callbacks;
}
#handleItemSelected(selection) {
console.log('handleItemSelected()');
if (this.#callbacks.itemSelected) this.#callbacks.itemSelected(this, selection);
if (this.#displaySelection) this.#valuePara.textContent = selection;
}
然后在我的应用程序代码中:
function demoHandler(thisVal, selection) {
console.log('demoHandler ' + thisVal + ' ' + selection);
}
new DropDown({ itemSelected: demoHandler });
但是回调没有被执行。我发现
this.#callbacks
是空的。所以我记录了各种方法/函数调用。这是它们的执行顺序:
constructor()
attributeChangedCallback()
connectedCallback()
constructor()
<user click>
handleItemSelected()
哇。
constructor()
由自定义元素框架调用。当我的应用程序代码稍后再次调用它时,这是毫无意义的,因为我的应用程序构造的对象不是框架正在使用的对象。此外,应用程序无法从框架的实例化中获取对象引用。如果没有该对象引用,我不知道如何传入要执行的对象的回调函数。
如何将这些回调添加到我的对象中?
我解决这个问题的方法是在类上创建公共方法。然后您可以查询元素并直接调用自定义方法。
这是一个简单的例子来说明我的意思。下面的类定义有一个可以直接调用的
changeToRed
函数,因为它只是一个像其他任何对象属性一样的对象属性。
class CustomElement extends HTMLElement {
constructor() {
super();
}
changeToRed() {
this.style.color = 'red';
}
connectedCallback() {
this.innerHTML = `<p>I'm a custom element.</p>`
}
}
customElements.define("custom-element", CustomElement);
要访问此方法,我们首先在 HTML 中创建自定义元素的实例并为其分配一个
id
。
<custom-element id="custom-element"></custom-element>
现在,我们可以通过 DOM 访问该自定义元素并使用公共方法。
const customEl = document.getElementById('custom-element');
customEl.changeToRed();
请参阅 CodePen 上的工作示例。