点击body元素时,如何在ReactJs中从父节点获取带data-mask的子节点?
问题:通过dataset属性查找指定DOM节点
我有一个包含若干子节点的父容器,DOM结构如下:
<div class="main"> <div class="child1">some content1</div> <div class="child2">some content4</div> <p></p> <span></span> <div class="child3" data-mask="child3-content">some content5</div> <!-- 希望通过其附带的dataset属性访问该子节点 --> <div class="child4">some content13</div> </div>
需求是:点击body元素时,通过data-mask这个dataset属性找到对应的子节点,若该属性存在则返回null。我的React示例代码如下:
componentDidMount() { window.addEventListener("click", this.onBodyClick); } onBodyClick(eve) { const rc = ReactDOM.findDOMNode(this); /*此方法会返回整个DOM节点: <div class="main"> <div class="child1">some content1</div> <div class="child2">some content4</div> <p></p> <span></span> <div class="child3" data-mask="child3-content">some content5</div> <div class="child4">some content13</div> </div> */ /* 想要查找的子节点: <div class="child3" data-mask="child3-content">some content5</div> */ // 不确定如何使用`eve`通过dataset获取该节点。 }
解决思路
方法1:通过父节点直接查找目标元素
既然已经通过ReactDOM.findDOMNode(this)获取到了父容器rc,可以直接用DOM选择器在父容器范围内查找带data-mask属性的子节点:
const targetNode = rc.querySelector('[data-mask]'); // 若找到目标节点,按需求返回null if (targetNode) { return null; }
querySelector('[data-mask]')会返回父容器内第一个带有data-mask属性的元素,若要获取所有符合条件的元素,可改用querySelectorAll。
方法2:利用事件对象判断点击关联的目标节点
如果是要判断点击的元素是否属于带data-mask的节点(或其子元素),可以用事件对象的closest方法向上查找:
const clickedMaskNode = eve.target.closest('[data-mask]'); // 若点击的区域关联到带data-mask的节点,返回null if (clickedMaskNode) { return null; }
closest方法会从当前元素开始向上遍历,找到最近的匹配选择器的元素,找不到则返回null。
方法3:React最佳实践——使用Ref替代DOM查找
React不推荐直接使用findDOMNode,更优雅的方式是给目标节点添加ref,直接获取节点引用:
- 在组件中定义ref:
class YourComponent extends React.Component { constructor(props) { super(props); this.maskRef = React.createRef(); } componentDidMount() { window.addEventListener("click", this.onBodyClick); } onBodyClick(eve) { const targetNode = this.maskRef.current; // 判断点击是否关联到该节点,或直接按需求处理 if (targetNode) { // 若节点存在,返回null return null; } } render() { return ( <div className="main"> {/* 其他子节点 */} <div className="child3" data-mask="child3-content" ref={this.maskRef}>some content5</div> </div> ); } }
这种方式避免了手动查找DOM,更符合React的数据流理念。
内容的提问来源于stack exchange,提问作者user1234
相关产品推荐
相关产品推荐

