Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在照明元素上实现外部单击_Javascript_Typescript_Lit Element_Lit Html - Fatal编程技术网

Javascript 在照明元素上实现外部单击

Javascript 在照明元素上实现外部单击,javascript,typescript,lit-element,lit-html,Javascript,Typescript,Lit Element,Lit Html,我正在使用LitElements制作一个自定义下拉web组件,在实现click outside dropwdown to close功能时,我注意到一些意外的行为阻碍了我。在下面的async firstUpdated()函数中,我将作为创建事件侦听器。注销下拉列表按预期工作,但注销目标每次都返回根…元素,虽然在一定程度上是准确的,但不够具体。如果有更好的方法来处理外部点击事件,我洗耳恭听 作为参考,这里有一些我正在尝试复制的已经构建的东西(尽管源代码是隐藏的): async firstUpdat

我正在使用LitElements制作一个自定义下拉web组件,在实现click outside dropwdown to close功能时,我注意到一些意外的行为阻碍了我。在下面的
async firstUpdated()
函数中,我将作为创建事件侦听器。注销
下拉列表
按预期工作,但注销
目标
每次都返回根
元素,虽然在一定程度上是准确的,但不够具体。如果有更好的方法来处理外部点击事件,我洗耳恭听

作为参考,这里有一些我正在尝试复制的已经构建的东西(尽管源代码是隐藏的):

async firstUpdated(){
等待新承诺((r)=>setTimeout(r,0));
this.addEventListener('click',event=>{
const dropdown=this.shadowRoot?.getElementById('dropdown-select');
const target=event.target;
如果(!dropdown?.contains(目标)){
console.log('im-out');
}
});
}    
@customElement(“自定义下拉列表”)
public render():TemplateResult{
返回html`
${this.value}
${this.dropdownItems(this.options)}
`;
}
目标
属性设置为

最顶端的事件目标必须是渲染顺序中最高的元素,该元素能够成为一个事件目标

因为影子DOM封装了它的内部结构,所以事件是。在您的示例中,
单击
事件的
目标
被重新定位到
自定义下拉列表
,因为这是能够成为目标的第一个也是最高的元素

如果需要针对自定义元素中的元素,可以采用以下方法之一:

  • 在元素中注册一个事件侦听器
  • 使用元素用在light DOM中声明的元素填充自定义元素
  • 使用on events with确定事件从哪个内部元素冒泡

  • 下面是一个我相信您正在寻找的功能示例。如果单击
    自定义元素
    ,它将切换其活动状态(类似于切换下拉列表)。如果单击页面上的任何其他元素,自定义元素将自动停用(类似于在失去焦点时隐藏下拉列表)

    //定义自定义元素类型
    类MySpan扩展了HTMLSpanElement{
    构造函数(){
    超级();
    this.attachShadow({mode:'open'});
    常量文本='自定义元素';
    const style=document.createElement('style');
    style.textContent=`
    跨度{
    填充物:5px;
    保证金:5px;
    背景颜色:灰色;
    颜色:白色;
    }
    .主动{
    背景颜色:浅绿色;
    颜色:黑色;
    }      
    `;
    this.span=document.createElement('span');
    this.span.innerText=文本;
    this.span.addEventListener('单击',(事件)=>{
    log('自定义元素:在自定义元素内单击');
    这是一个“handleClick”(事件);
    });
    this.shadowRoot.append(样式,this.span);
    }
    handleClick(事件){
    //如果事件来自内部事件侦听器,
    //目标将是我们的span元素,我们可以切换它。
    //如果事件来自元素外部,
    //目标不能是我们的span元素,我们应该
    //去激活它。
    if(event.target==this.span){
    this.span.classList.toggle('active');
    }
    否则{
    this.span.classList.remove('active');
    }
    }
    }
    define('my-span',MySpan,{extends:'span});
    //插入自定义元素的实例
    const div1=document.querySelector('#target');
    const mySpan=新mySpan();
    第1部分:儿童(mySpan);
    //将事件侦听器添加到页面
    函数handleClick(事件){
    //如果我们没有单击自定义元素,就让它
    //了解事件,以便可以停用其范围。
    如果(event.target!==mySpan){
    log(`PAGE:单击${event.target}。通知自定义元素。`);
    mySpan.handleClick(事件);
    }
    }
    document.body.addEventListener('click',(事件)=>handleClick(事件))
    
    p{
    填充物:5px;
    背景颜色:浅灰色;
    }

    这是一个段落

    这是第二段

    这是第三段


    这是第四段。

    好的,后续问题。。。比如说,我一直在关注页面上任何地方的点击,而不仅仅是在影子DOM中。那可能吗?我能够让合成路径位工作,但它只在单击阴影DOM内部时触发。我在帖子中添加了一个例子,希望能更好地解释。当然,这是可能的。我在自定义元素中添加了一个事件监听器示例,用于处理直接交互,以及一个页面范围的事件监听器,用于将外部事件传播到自定义元素中。感谢这个示例,它并不完全匹配,但我能够将您的一些输入拼凑起来,以获得一个工作示例。
    async firstUpdated() {
      await new Promise((r) => setTimeout(r, 0));
      this.addEventListener('click', event => {
        const dropdown = <HTMLElement>this.shadowRoot?.getElementById('dropdown-select');
        const target = <HTMLElement>event.target;
        if (!dropdown?.contains(target)) {
          console.log('im outside');
        }
      });
    }    
    
    
    @customElement('custom-drop-down')
    public render(): TemplateResult {
      return html`
        <div>
          <div id="dropdown-select" @action=${this.updateValue}>
            <div class="current-selection" @click=${this.toggleDropdown}>
              ${this.value}
            </div>
            <div class="dropdown-options" id="dropdown-options">
              ${this.dropdownItems(this.options)}
            </div>
          </div>
        </div>
      `;
    }