React js - 将事件侦听器添加到 html 字符串
React js - Add an event listener to an html string
我正在 React js 上开发一个聊天应用程序,我有以下内容:
{messages.map((chat, index) => {
return (
<p className="ctext" id={chat.id} dangerouslySetInnerHTML={{ __html:
chat.body.replace(/\B(\#[a-zA-Z0-9]+\b)/g, match => `<span className="linkHashtag" onclick={hashTagClicked(${match})}>${match}</span>`) }}>
</p>
)
})}
所以基本上,我有一个消息映射,我将 HTML 字符串中的所有标记替换为 class 并尝试添加一个函数(运行时),但是当我尝试这个时,函数像字符串而不像函数:
<span class="linkHashtag" onclick="{" clicktagsearch(#MARKET)="" }="">#MARKET</span>
有什么想法吗?
编辑:
我认为这是无需直接操作 DOM 即可获得相同结果的更好方法:
const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;
const DeclarativeRendering = ({ handler }) => (
<div>
{messages.map((chat, index) => {
return (
<p className="ctext" id={chat.id}>
<TaggedString
str={chat.body}
onClick={handler}
style={{ marginRight: '5px' }}
className="linkHashtag"
/>
</p>
);
})}
</div>
);
const makeTag = (txt, props) => {
return <span {...props}>{txt}</span>;
};
const TaggedString = ({ str, ...props }) => {
const stringsArray = useMemo(
() =>
str
.split(' ')
.map((el) => (reg.test(el) ? makeTag(el, props) : el + '\n')),
[str, props]
);
return stringsArray;
};
您可以在此处测试这两种方法:https://stackblitz.com/edit/react-u7k6od?file=src%2FApp.js
// 旧答案
我认为由于拼写错误(HTML 和 JSX 以不同的方式声明属性)样式不起作用,并且事件侦听器不起作用,因为您需要将它们手动附加到 DOM渲染后的节点,像这样的东西应该可以工作:
const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;
const ImperativeManipulation = ({ handler }) => {
const handleEl = (el) => {
if (!el) return;
el.querySelectorAll("span").forEach((child) => (child.onclick = handler));
};
return (
<div ref={handleEl}>
{messages.map((chat, index) => {
const newText = chat.body.replace(reg, match => `<span class="linkHashtag">${match}</span>` )
return (
<p
className="ctext"
id={chat.id}
dangerouslySetInnerHTML={{
__html: newText,
}}
></p>
);
})}
</div>
);
};
但我认为有更好的方法来实现这一点,避免完全命令式 DOM 操作,这是一种 React 反模式。
注意:
为了避免在重新挂载时发生内存泄漏,我使用 .onclick 语法来附加事件侦听器,因此每次重新挂载组件时它们都会被简单地覆盖,如果你想将 eventListener 附加到节点,你必须确保在卸载时清理它,所以你需要使用 useEffect 来处理这个逻辑。
我正在 React js 上开发一个聊天应用程序,我有以下内容:
{messages.map((chat, index) => {
return (
<p className="ctext" id={chat.id} dangerouslySetInnerHTML={{ __html:
chat.body.replace(/\B(\#[a-zA-Z0-9]+\b)/g, match => `<span className="linkHashtag" onclick={hashTagClicked(${match})}>${match}</span>`) }}>
</p>
)
})}
所以基本上,我有一个消息映射,我将 HTML 字符串中的所有标记替换为 class 并尝试添加一个函数(运行时),但是当我尝试这个时,函数像字符串而不像函数:
<span class="linkHashtag" onclick="{" clicktagsearch(#MARKET)="" }="">#MARKET</span>
有什么想法吗?
编辑:
我认为这是无需直接操作 DOM 即可获得相同结果的更好方法:
const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;
const DeclarativeRendering = ({ handler }) => (
<div>
{messages.map((chat, index) => {
return (
<p className="ctext" id={chat.id}>
<TaggedString
str={chat.body}
onClick={handler}
style={{ marginRight: '5px' }}
className="linkHashtag"
/>
</p>
);
})}
</div>
);
const makeTag = (txt, props) => {
return <span {...props}>{txt}</span>;
};
const TaggedString = ({ str, ...props }) => {
const stringsArray = useMemo(
() =>
str
.split(' ')
.map((el) => (reg.test(el) ? makeTag(el, props) : el + '\n')),
[str, props]
);
return stringsArray;
};
您可以在此处测试这两种方法:https://stackblitz.com/edit/react-u7k6od?file=src%2FApp.js
// 旧答案
我认为由于拼写错误(HTML 和 JSX 以不同的方式声明属性)样式不起作用,并且事件侦听器不起作用,因为您需要将它们手动附加到 DOM渲染后的节点,像这样的东西应该可以工作:
const messages = [{ body: 'Hello #world two' }, { body: '#Hello Universe' }];
const reg = /\B(\#[a-zA-Z0-9]+\b)/g;
const ImperativeManipulation = ({ handler }) => {
const handleEl = (el) => {
if (!el) return;
el.querySelectorAll("span").forEach((child) => (child.onclick = handler));
};
return (
<div ref={handleEl}>
{messages.map((chat, index) => {
const newText = chat.body.replace(reg, match => `<span class="linkHashtag">${match}</span>` )
return (
<p
className="ctext"
id={chat.id}
dangerouslySetInnerHTML={{
__html: newText,
}}
></p>
);
})}
</div>
);
};
但我认为有更好的方法来实现这一点,避免完全命令式 DOM 操作,这是一种 React 反模式。
注意: 为了避免在重新挂载时发生内存泄漏,我使用 .onclick 语法来附加事件侦听器,因此每次重新挂载组件时它们都会被简单地覆盖,如果你想将 eventListener 附加到节点,你必须确保在卸载时清理它,所以你需要使用 useEffect 来处理这个逻辑。