React 16如何阻止点击事件传递至子组件?消息选择时屏蔽图片弹窗
问题:聊天界面选中模式下,点击图片仍弹出模态框的解决方法
场景描述
我有一个类似WhatsApp的聊天界面,包含消息列表。正常点击<ModalImageCors>组件会打开图片模态框,符合预期。但当selectingMsgs状态为true时,希望点击图片仅触发消息选中操作,不打开模态框。目前尝试阻止事件传播无效:消息能被选中,但模态框还是会弹出,需要在selectingMsgs === true时阻止点击事件触达图片组件。
当前代码
else if (message.mediaType === "image") { return ( <div onClick={(e) => { if (selectingMsgs) { e.stopPropagation(); e.preventDefault(); handleCheckboxChange(message.id); } }} > <ModalImageCors imageUrl={message.mediaUrl} /> </div> );
<ModalImageCors>组件代码
const ModalImageCors = ({ imageUrl }) => { const classes = useStyles(); const [fetching, setFetching] = useState(true); const [blobUrl, setBlobUrl] = useState(""); useEffect(() => { if (!imageUrl) return; const fetchImage = async () => { const { data, headers } = await api.get(imageUrl, { responseType: "blob", }); const url = window.URL.createObjectURL( new Blob([data], { type: headers["content-type"] }) ); setBlobUrl(url); setFetching(false); }; fetchImage(); }, [imageUrl]); return ( <ModalImage className={classes.messageMedia} smallSrcSet={fetching ? imageUrl : blobUrl} medium={fetching ? imageUrl : blobUrl} large={fetching ? imageUrl : blobUrl} showRotate="true" alt="image" /> ); };
<ModalImage>组件定义
import * as React from "react"; export interface ModalImageProps extends React.ImgHTMLAttributes<HTMLImageElement> { /* The small image to display */ small: string; /* The srcset attribute for the small image */ smallSrcSet?: string; /* The medium image to display */ medium?: string; /* The large image to display */ large?: string; /* The alt tag for the image */ alt?: string; /* Should the download button be hidden? */ hideDownload?: boolean; /* Should the zoom button be hidden? */ hideZoom?: boolean; /* Should the rotate button be shown? */ showRotate?: boolean; /* The color to display in the background. */ imageBackgroundColor?: string; /* The class name for the modal */ className?: string; } declare class ModalImage extends React.Component<ModalImageProps> {} declare class Lightbox extends React.Component<ModalImageProps> {} export default ModalImage; export { Lightbox };
React版本
"react": "^16.13.1", "react-dom": "^16.13.1",
已尝试方案
onClick={(e) => { if (selectingMsgs) { e.stopPropagation(); e.preventDefault();
直接在图片模态框或其父级div上添加上述代码,但未生效。
解决方案
问题根源在于事件传播顺序:父div的onClick在事件冒泡阶段触发,而<ModalImage>内部的点击事件可能更早被触发,导致stopPropagation无法阻止模态框弹出。以下是三种可行解决方式:
1. 根据选中状态替换图片组件
给<ModalImageCors>传入selectingMsgs状态,选中模式下直接渲染普通<img>,不使用可触发模态框的<ModalImage>:
修改<ModalImageCors>:
const ModalImageCors = ({ imageUrl, selectingMsgs }) => { const classes = useStyles(); const [fetching, setFetching] = useState(true); const [blobUrl, setBlobUrl] = useState(""); useEffect(() => { if (!imageUrl) return; const fetchImage = async () => { const { data, headers } = await api.get(imageUrl, { responseType: "blob", }); const url = window.URL.createObjectURL( new Blob([data], { type: headers["content-type"] }) ); setBlobUrl(url); setFetching(false); }; fetchImage(); }, [imageUrl]); // 选中模式下渲染普通图片 if (selectingMsgs) { return ( <img className={classes.messageMedia} src={fetching ? imageUrl : blobUrl} alt="image" /> ); } return ( <ModalImage className={classes.messageMedia} smallSrcSet={fetching ? imageUrl : blobUrl} medium={fetching ? imageUrl : blobUrl} large={fetching ? imageUrl : blobUrl} showRotate="true" alt="image" /> ); };
父组件传入状态:
else if (message.mediaType === "image") { return ( <div onClick={(e) => { if (selectingMsgs) { handleCheckboxChange(message.id); } }} > <ModalImageCors imageUrl={message.mediaUrl} selectingMsgs={selectingMsgs} /> </div> );
2. 使用事件捕获阶段拦截
将父div的onClick改为onClickCapture,在事件从外层向内层传递时先执行,阻止事件继续触达子元素:
else if (message.mediaType === "image") { return ( <div onClickCapture={(e) => { if (selectingMsgs) { e.stopPropagation(); handleCheckboxChange(message.id); } }} > <ModalImageCors imageUrl={message.mediaUrl} /> </div> );
3. 给<ModalImage>添加点击拦截
在<ModalImageCors>内部给<ModalImage>绑定onClick事件,选中模式下阻止事件传播:
// 给ModalImageCors添加selectingMsgs props return ( <ModalImage className={classes.messageMedia} smallSrcSet={fetching ? imageUrl : blobUrl} medium={fetching ? imageUrl : blobUrl} large={fetching ? imageUrl : blobUrl} showRotate="true" alt="image" onClick={(e) => { if (selectingMsgs) { e.stopPropagation(); e.preventDefault(); } }} /> );
内容的提问来源于stack exchange,提问作者Gian
相关产品推荐
相关产品推荐

