繁体   English   中英

如何将DOM选择器作为数据属性传递

[英]How to pass DOM selector as data-attribute

我正在编写一些共享的模态功能(用户单击一个按钮,我的模态方法获取一些关联的DOM元素并将其克隆到模态),不幸的是,例如,触发器和内容之间的关系在HTML中存在一些不一致之处:

// Sibling

<button class="modal__button">Trigger</button>
<div class="modal__content">Content</div>


// Separated by other elements

<button class="modal__button">Trigger</button>
<div>Other Elements</div>
<div>Other Elements</div>
<div class="modal__content">Content</div>


// Trigger's parent is content's sibling

<div>
    <button class="modal__button">Trigger</button>
</div>
<div class="modal__content">Content</div>


// Argh!

<div>
    <div>
        <button class="modal__button">Trigger</button>
    </div>
</div>
<div>Other Elements</div>
<div>Other Elements</div>
<div>
    <div>
        <div class="modal__content">Content</div>
    </div>
</div>

不幸的是,对于我的用例,使用ID来建立关系的明显答案是不可能的(因为它们必须是唯一的,并且这些组件可以在单个页面中多次出现,并且从服务器端的角度来看每个组件都不知道)有关是否已将其添加到页面中的信息,因此无法确保这种唯一性)。

我能看到的唯一方法是,是否可以将模态方法作为数据属性传递给DOM选择器(相对于触发器),然后让模态方法执行此选择器。 我还需要确定范围,使其相对于按钮触发器。 但是,我不确定在JavaScript中是否可以实现以上任何一项? 基本上,我希望能够编写如下所示的按钮:

<button data-modal-content="this.nextElementSibling">Trigger</button>
<button data-modal-content="this.parentNode.querySelectorAll('modal__content')">Trigger</button>
<button data-modal-content="this.parentNode.nextElementSibling">Trigger</button>

然后让我的模态方法找到选择器。 我知道我可以像这样使用eval()

 document.querySelectorAll('[data-modal-content]').forEach(el => { el.addEventListener('click', button => { const selector = button.target.getAttribute('data-modal-content').replace('this','button.target'); console.log(eval(selector)); }); }); 
 <button data-modal-content="this.nextElementSibling">Trigger</button> <div>Content</div> 

...但是我也知道与此相关的安全性问题,这意味着我可能必须对字符串进行清理(我想通过检查字符串的每个部分是否只在使用选择器 y进行处理之后,才能将其移到eval()附近)。

这是最好的方法吗,是否有更好的方法可以解决我从未考虑过的问题? 一种不依赖风险eval()的选择器内容的方法将是理想的。

我宁愿寻求一个更简单的解决方案,只需选择所有模态,然后找到单击按钮之后的第一个模态。

 document.querySelectorAll("button.modal__button").forEach(function(b) { b.addEventListener("click", clickHandler); }); function clickHandler() { const contents = document.querySelectorAll("div.modal__content"); const c = Array.from(contents).find(c => this.compareDocumentPosition(c) == Node.DOCUMENT_POSITION_FOLLOWING ); if (c) c.classList.add("found"); else console.log("Unable to find content from:", this); } 
 .found { background: red; color: white; } .modal__content { margin: 10px; padding: 10px; border: 2px solid orange; } 
 // Sibling <button class="modal__button">Trigger</button> <div class="modal__content">Content</div> // Separated by other elements <button class="modal__button">Trigger</button> <div>Other Elements</div> <div>Other Elements</div> <div class="modal__content">Content</div> // Trigger's parent is content's sibling <div> <button class="modal__button">Trigger</button> </div> <div class="modal__content">Content</div> // Argh! <div> <div> <button class="modal__button">Trigger</button> </div> </div> <div>Other Elements</div> <div>Other Elements</div> <div> <div> <div class="modal__content">Content</div> </div> </div> 


另一种解决方案是在单击按钮时为按钮提供一个临时ID,然后将其包含在内容元素的DOM选择中。 这样,您只需要在集合中找到按钮,就知道内容是下一个(或上一个)按钮,因为结果始终按“文档顺序”返回。

 document.querySelectorAll("button.modal__button").forEach(function(b) { b.addEventListener("click", clickHandler); }); function clickHandler() { const temp = this.id; this.id = generateUniqueId(); const els = document.querySelectorAll(`#${this.id}, div.modal__content`); const idx = Array.from(els).findIndex(el => this.id == el.id); this.id = temp; if (idx !== -1) { const el = this.dataset.position === "before" ? els[idx - 1] : els[idx + 1]; el.classList.add("found"); } else console.log("Unable to find content from:", this); } function generateUniqueId() { do { const id = "__temp_id__" + (Math.floor(Math.random()) * Number.MAX_SAFE_INTEGER); if (!document.querySelector(id)) return id; } while (true); } 
 .found { background: red; color: white; } .modal__content { margin: 10px; padding: 10px; border: 2px solid orange; } 
 // Sibling <button class="modal__button">Trigger</button> <div class="modal__content">Content</div> // Separated by other elements <button class="modal__button">Trigger</button> <div>Other Elements</div> <div>Other Elements</div> <div class="modal__content">Content</div> // Content comes before trigger's parent <div class="modal__content">Content</div> <div> <button class="modal__button" data-position="before">Trigger</button> </div> // Trigger's parent is content's sibling <div> <button class="modal__button">Trigger</button> </div> <div class="modal__content">Content</div> // Argh! <div> <div> <button class="modal__button">Trigger</button> </div> </div> <div>Other Elements</div> <div>Other Elements</div> <div> <div> <div class="modal__content">Content</div> </div> </div> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM