我正在尝试侦听自定义组件中的文本更改
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="component.js"></script>
</head>
<body>
<fancy-p>
<p>Bar</p>
<!-- the input should be listened to -->
<input id="foo" type="text" name="text" placeholder="Hello"></input>
</fancy-p>
</body>
</html>
component.js
customElements.define('fancy-p', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
get foo() {
return "foo"
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
p {
color: red;
}
:host {
background-color: blue;
}
</style>
<div data-foo="bar">
<slot></slot>
</div>
`;
let input = this.querySelector("input");
console.log("input is:" + input);
}
});
我尝试收听文本更改,并在querySelector
中使用connectedCallback
,但是在Chrome 70.xx中,选择器返回了null
。
当我设置一个断点时,lightDOM似乎没有被填充(即,插槽),但是我不知道如何向输入中添加事件监听器。
我该怎么做?
答案 0 :(得分:2)
在您的示例中,<input>
被放置在<slot>
中,这意味着自定义元素之外的代码拥有<input>
标记。
在下面的代码中,您看到我在自定义元素外部使用document.querySelector
来获取<input>
元素,而不在自定义内部使用this.querySelector
或this.shadowRoot.querySelector
元素代码。
customElements.define('fancy-p', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
get foo() {
return "foo"
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
p {
color: red;
}
:host {
background-color: blue;
}
</style>
<div data-foo="bar">
<slot></slot>
</div>
`;
let input = this.shadowRoot.querySelector("input");
console.log('inside input=',input); // input will be null
}
});
//Since the `<input>` tag is *owned* by the outside DOM you need to get the events from the outside:
let input = document.querySelector("input");
console.log('outside input=', input);
input.addEventListener('input', () => {
console.log("input is:" + input.value);
});
<fancy-p>
<p>Bar</p>
<input id="foo" type="text" name="text" placeholder="Hello"/></fancy-p>
如果要通过shadowDOM访问它,则需要在shadowDOM中定义它:
customElements.define('fancy-p', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
get foo() {
return "foo"
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
p {
color: red;
}
:host {
background-color: blue;
}
</style>
<div data-foo="bar">
<slot></slot>
<input id="foo" type="text" name="text" placeholder="Hello">
</div>
`;
let input = this.shadowRoot.querySelector("input");
console.log('inside input=',input);
input.addEventListener('input', () => {
console.log("input is:" + input.value);
});
}
});
<fancy-p>
<p>Bar</p>
</fancy-p>
答案 1 :(得分:1)
调用connectedCallback()
方法时,<input>
元素尚未附加到轻型DOM。因此,您当时无法使用this.querySelector('input')
来获得它。
这并不是真正的问题:您可以在自定义元素本身上监听{input}
事件,因为该事件会冒泡到父元素。
this.addEventListener( 'input', ev => console.log( ev.target, ev.target.value ) )
请参见运行示例:
customElements.define('fancy-p', class extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
.innerHTML = `
<style>
::slotted(p) { color: red; }
:host { display:inline-block; background-color: blue; }
</style>
<div data-foo="bar">
<slot></slot>
</div>`
this.addEventListener('input', ev => console.log( '%s value is %s', ev.target, ev.target.value))
}
})
<fancy-p>
<p>Bar</p>
<input id="foo" type="text" name="text" placeholder="Hello">
</fancy-p>