Javascript 将选择框包装到自定义元素中

Javascript 将选择框包装到自定义元素中,javascript,typescript,polymer,custom-element,lit-element,Javascript,Typescript,Polymer,Custom Element,Lit Element,我想构建一个html自定义元素,该元素的行为应该与本机元素几乎相同,但除此之外,它还必须在每次属性或子节点更改时调用特定的更新函数。(背景:这是在elm框架内使用元素的必要步骤。另请参见。) 使用LitElement框架,我能够构建一个与上述描述类似的工作自定义元素(称为)。但不幸的是,我无法让它接受html或元素作为子元素。相反,用户必须将选项列表作为json编码的字符串传递给某个属性 也就是说,我不打电话了 福 酒吧 用户必须调用 我必须以何种方式更改我对的定义才能进行第一次呼叫?我

我想构建一个html自定义元素,该元素的行为应该与本机
元素几乎相同,但除此之外,它还必须在每次属性或子节点更改时调用特定的更新函数。(背景:这是在elm框架内使用元素的必要步骤。另请参见。)

使用LitElement框架,我能够构建一个与上述描述类似的工作自定义元素(称为
)。但不幸的是,我无法让它接受html
元素作为子元素。相反,用户必须将选项列表作为json编码的字符串传递给某个属性

也就是说,我不打电话了


福
酒吧
用户必须调用


我必须以何种方式更改我对
的定义才能进行第一次呼叫?我知道
元素,但不幸的是,该元素不允许在
中使用,因此浏览器只是将其删除

提前谢谢你


更新1

事实上,有一些限制使问题比我最初想象的更具挑战性:

  • 我必须避免阴影。这是因为我的自定义元素正在通过bootstrap(和bootstrap select)css/js进行样式化/增强,它只查看普通DOM。正如我刚刚了解到的,这排除了
    slot
    元素,因为它们是特定于阴影DOM的
  • 我的自定义元素必须完全响应更改(添加/删除子注释、更改属性)。这是因为我计划在虚拟DOM中使用元素(在我的例子中是elm,但它也应该与react一起使用)

附录

我对
的定义:

从'lit element'导入{LitElement,html,customElement,property};
从“jquery”导入*为$;
导入“引导”;
导入“引导选择”;
@customElement('lit-select')
导出类LitSelect扩展了LitElement{
@属性({type:Array})项=[]
更新的(){
$(this.find(“.selectpicker”).selectpicker('refresh');
}
createRenderRoot(){
归还这个;
}
私有renderItem(项:字符串){
返回html`
${item}
`;
}
render(){
返回html`
${this.items.map(item=>this.renderItem(item))}
`;
}
}

为什么不从本机W3C标准自定义元素开始

您所要做的就是移动一些
元素


我的永不待办事项清单
长大
学习反应
使用照明
忘记W3C自定义元素API
定义(“我的选择”,类扩展HtmleElement{
静态get ObservedAttribute(){
return[“name”];//使用一个来触发attributeChangedCallback
}
connectedCallback(){
console.log('connected');
//克隆模板
append(document.getElementById(this.nodeName.content.cloneNode(true));
//在“选择”中移动选项:
this.querySelector('select').append(…this.querySelector('option'));
}
attributeChangedCallback(){
setTimeout(()=>this.updated(…arguments))//在事件循环完成后执行
}
已更新(名称、旧值、新值){
日志('updated',name,oldValue,newValue);
}
})

为什么不从本机W3C标准自定义元素开始

您所要做的就是移动一些
元素


我的永不待办事项清单
长大
学习反应
使用照明
忘记W3C自定义元素API
定义(“我的选择”,类扩展HtmleElement{
静态get ObservedAttribute(){
return[“name”];//使用一个来触发attributeChangedCallback
}
connectedCallback(){
console.log('connected');
//克隆模板
append(document.getElementById(this.nodeName.content.cloneNode(true));
//在“选择”中移动选项:
this.querySelector('select').append(…this.querySelector('option'));
}
attributeChangedCallback(){
setTimeout(()=>this.updated(…arguments))//在事件循环完成后执行
}
已更新(名称、旧值、新值){
日志('updated',name,oldValue,newValue);
}
})

这个解决方案怎么样

从'lit element'导入{LitElement,html};
导出类GraniteSelect扩展LitElement{
静态获取属性(){
返回{
选项:{
类型:对象,
}
}
}
构造函数(){
超级();
this.options=[];
}
connectedCallback(){
super.connectedCallback();
this.observer=新突变观察者((突变)=>{
突变。forEach((突变)=>{
突变.removedNodes.forEach((节点)=>{
如果(node.nodeName==='OPTION'){
this.options=[…this.options,节点];
log(`options-${this.options}`);
console.dir(this.options);
}
});
});
});
观察者观察{
儿童名单:是的,
});
}
第一次更新(){
this.observer.disconnect();
}
createRenderRoot(){
/**
*没有阴影DOM的渲染模板
*封装的CSS和插槽不可用。
*/
归还这个;
}
render(){
console.log('Rendering',this.options);
返回html`
${this.options}
`;
}
}
window.customElements.define('granite-select',GraniteSelect');
它使用light dom(创建ShadowRoot的
部分),并将元素的所有选项子元素放在
选择
中。非选项子项只是被忽略,但您可以对它们做任何事情

您可以在中看到完整的示例

你觉得这种方法怎么样?

那么