1. 首页
  2. css

CSSJavaScript的closest()方法的实际用例

在JavaScript中查找DOM节点的父节点时,您是否遇到过这样的问题,但您不确定需要遍历多少层才能找到它?让我们看看这个HTML,例如:

That\”s pretty straightforward, right? Say you want to get the value of data-id在用户单击按钮后:
var => {console.log(evt.target.parentNode.dataset.id);// prints \”123\”});
在这个例子中节点.父节点API就足够了。它所做的是返回给定元素的父节点。在上面的例子中,evt.target是被单击的按钮;它的父节点是具有data属性的div。
但是如果HTML结构嵌套得比这个更深呢?它甚至可以是动态的,这取决于它的内容。

Our job just got considerably more difficult by adding a few more HTML elements. Sure, we could do something like element.parentNode.parentNode.parentNode.dataset.id,但是拜托…这不优雅,可重用或可扩展。旧方法:使用while-循环
一种解决方案是使用while循环,直到找到父节点为止。
function getParentNode(el, tagName) {while (el && el.parentNode) == tagName.toUpperCase()) {return el;}}return null;}
再次使用上面相同的HTML示例,它看起来是这样的:
var>
This solution is far from perfect. Imagine if you want to use IDs or classes or any other type of selector, instead of the tag name. At least it allows for a variable number of child nodes between the parent and our source.There\”s also jQuery
Back in the day, if you didn\”t wanted to deal with writing the sort of function we did above for each application (and let\”s be real, who wants that?), then a library like jQuery came in handy (and it still does). It offers a .closest()方法就是这样的:
The new way: Using Element.closest()
尽管jQuery仍然是一种有效的方法(嘿,我们中的一些人对此很感激),但将它添加到一个项目中仅仅是因为这一种方法太过简单了,尤其是如果您可以使用与本机JavaScript相同的方法,
这就是Element.closest开始起作用的地方:
var>
There we go! That\”s how easy it can be, and without any libraries or extra code.
Element.closest()允许我们遍历DOM,直到得到与给定选择器匹配的元素。令人敬畏的是,我们可以通过任何选择器,我们也会给Element.querySelector或Element.querySelectorAll。它可以是一个ID、类、数据属性、标记或任何东西。
element.closest(\”#my-id\”); // yepelement.closest(\”.some-class\”); // yepelement.closest(\”[data-id]:not(article)\”) // hell yeah
如果Element.closest根据给定的选择器找到父节点,它将以与document.querySelector相同的方式返回。否则,如果找不到父级,它将返回null,这使得它很容易与if条件一起使用:
var>
Ready for a few real-life examples? Let\”s go!Use Case 1: DropdownsCodePen Embed Fallback
Our first demo is a basic (and far from perfect) implementation of a dropdown menu that opens after clicking one of the top-level menu items. Notice how the menu stays open even when clicking anywhere inside the dropdown or selecting text? But click somewhere on the outside, and it closes.
The Element.closestAPI是检测外部单击的API。下拉列表本身是一个带有.menu-dropdown类的元素,因此单击菜单外的任何位置都将关闭它。这是因为evt.target.closest(\”.menu-dropdown\”)的值将是null,因为这个类没有父节点。
function handleClick(evt) {// …// if a click happens somewhere outside the dropdown, close it.if (!evt.target.closest(\”.menu-dropdown\”)) {menu.classList.add(\”is-hidden\”);navigation.classList.remove(\”is-expanded\”);}}
在handleClick回调函数中,一个条件决定了要做什么:关闭下拉列表。如果单击无序列表中的其他地方,Element.closest将找到并返回它,使下拉列表保持打开状态。用例2:TablesCodePen Embed Fallback
第二个示例呈现一个显示用户信息的表,例如作为仪表板中的组件。每个用户都有一个ID,但是我们没有显示它,而是将它保存为每个元素的数据属性。

The last column contains two buttons for editing and deleting a user from the table. The first button has a data-action属性edit,第二个按钮是delete。当我们单击其中一个时,我们希望触发一些操作(例如向服务器发送请求),但为此,需要用户ID。
全局窗口对象附加了一个click事件侦听器,因此每当用户单击页面上的某个位置时,调用回调函数handleClick。
function handleClick(evt) {var { action = getUserId(evt.target);if (action == \”edit\”) {alert(`Edit user with ID of ${userId}`);} else if (action == \”delete\”) {alert(`Delete user with ID of ${userId}`);} else if (action == \”select\”) {alert(`Selected user with ID of ${userId}`);}}}
如果在这些按钮之外的其他地方单击,则不存在data-action属性,因此不会发生任何事情。但是,当单击任一按钮时,操作将被确定(顺便说一下,这称为事件委派),并且作为下一步,将通过调用getUserId:
function getUserId(target) {// `target` is always a button or checkbox.return target.closest(\”[data-userid]\”).dataset.userid;}
来检索用户ID。此函数需要一个DOM节点作为唯一的参数,并且在调用时,使用Element.closest来查找包含已按下按钮的表行按钮。然后它返回data-userid值,现在可以使用该值向服务器发送请求。用例3:React中的表让我们继续使用表示例,看看如何在React项目中处理它。下面是返回表的组件的代码:
function TableView({ users }) {function handleClick(evt) {var => (
I find that this use case comes up frequently — it\”s fairly common to map over a set of data and display it in a list or table, then allow the user to do something with it. Many people use inline arrow-functions, like so:
handleClick(user.id)}>Edit
虽然这也是解决问题的有效方法,但我更喜欢使用data-userid技术。inline arrow函数的一个缺点是,每次React重新呈现列表时,它都需要再次创建回调函数,从而导致在处理大量数据时可能出现性能问题。
在回调函数中,我们只是通过提取目标(按钮)并获取父级来处理事件元素,它包含data-userid值。
function handleClick(evt) {var>Use Case 4: ModalsCodePen Embed Fallback
This last example is another component I\”m sure you\”ve all encountered at some point: a modal. Modals are often challenging to implement since they need to provide a lot of features while being accessible and (ideally) good looking.
We want to focus on how to close the modal. In this example, that\”s possible by either pressing Esc在键盘上,单击模态中的按钮,或单击模态之外的任何地方。
在我们的JavaScript中,我们希望侦听模态中某处的单击:
var>
The modal is hidden by default through a .is-hidden实用程序类。只有当用户单击大红色按钮时,模式才会通过删除此类打开。一旦模态打开,点击它里面的任何地方——除了关闭按钮——都不会无意中关闭它。事件侦听器回调函数负责:
function handleModalClick(evt) {// `evt.target` is the DOM node the user clicked on.if (!evt.target.closest(\”.modal-inner\”)) {handleModalClose();}}
evt.target是单击的DOM节点,在本例中,它是模态后面的整个背景,. This DOM node is not within , hence Element.closest()可以

CSSJavaScript的closest()方法的实际用例 为WP2原创文章,链接:https://www.wp2.cn/css/cssjavascript%e7%9a%84closest%ef%bc%88%ef%bc%89%e6%96%b9%e6%b3%95%e7%9a%84%e5%ae%9e%e9%99%85%e7%94%a8%e4%be%8b/