将 HTML 插入 Snackbar 消息
Inserting HTML into a Snackbar message
所以我正在分叉一个示例 Twilio 视频聊天应用程序 (https://github.com/twilio/twilio-video-app-react)。对于聊天功能,采用了 Snackbar 消息。哪个工作正常。但是我想让用户发送以http开头的消息,这样消息就会作为超链接发送URL.
ChatInput 组件可以很好地将此消息显示为本地用户(即发件人)的超链接 URL。但是远程用户的 DataTrack 事件处理程序不会将消息显示为超链接。只显示文字。
这里是 ChatInput.tsx,其中任何以 http 开头的消息都会正确显示给本地用户。
import React, { useState } from 'react';
import { Button, FormControl, TextField } from '@material-ui/core';
import { useSnackbar } from 'notistack';
import useVideoContext from '../../../hooks/useVideoContext/useVideoContext';
export default function ChatInput() {
const [message, setMessage] = useState('');
const { room } = useVideoContext();
const { enqueueSnackbar } = useSnackbar();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setMessage(e.target.value);
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (message) {
// Get the LocalDataTrack that we published to the room.
const [localDataTrackPublication] = [...room.localParticipant.dataTracks.values()];
// Construct a message to send
const fullMessage = `${room.localParticipant.identity} says: ${message}`;
if (message.startsWith('http')) {
// Send the message
localDataTrackPublication.track.send(`<a href="${message}">${message}</a>`);
// Render the message locally so the local participant can see that their message was sent.
enqueueSnackbar(<a href={message}>{message}</a>);
} else {
// Send the full message
localDataTrackPublication.track.send(fullMessage);
// Render the full message locally so the local participant can see that their message was sent.
enqueueSnackbar(fullMessage);
}
//Reset the text field
setMessage('');
}
};
return (
<form autoComplete="off" style={{ display: 'flex', alignItems: 'center' }} onSubmit={handleSubmit}>
<FormControl>
<label htmlFor="chat-snack-input" style={{ color: 'black' }}>
Say something:
</label>
<TextField value={message} autoFocus={true} onChange={handleChange} id="chat-snack-input" size="small" />
</FormControl>
<Button type="submit" color="primary" variant="contained" style={{ marginLeft: '0.8em' }}>
Send
</Button>
</form>
);
}
这里是 DataTrack.ts,它只显示任何远程用户的字符串文字。
import { useEffect } from 'react';
import { DataTrack as IDataTrack } from 'twilio-video';
import { useSnackbar } from 'notistack';
var stringToHTML = function (str) {
var parser = new DOMParser();
var doc = parser.parseFromString(str, 'text/html');
return doc.body;
};
export default function DataTrack({ track }: { track: IDataTrack }) {
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
const handleMessage = (message: string) => {
if (message.startsWith('http')) {
const newMessage = stringToHTML(message);
enqueueSnackbar(newMessage);
}
else {
enqueueSnackbar(message); }
};
track.on('message', handleMessage);
return () => {
track.off('message', handleMessage);
};
}, [track, enqueueSnackbar]);
return null; // This component does not return any HTML, so we will return 'null' instead.
}
关于如何让远程用户接收发件人看到的相同超链接 URL 有什么建议吗?
TL;DR: 函数 stringToHTML
在将消息传递给 NotiStack 时返回一个 DOM 元素引用而不是 React 元素,请尝试包装它使用 React 元素:
//const newMessage = stringToHTML(message);
enqueueSnackbar(<div dangerouslySetInnerHTML={{__html:message}} />);
NL;PR: And/Or 我不确定为什么您在两个组件中以不同的方式将消息值传递给 NotiStack:
if (message.startsWith('http')) {
//local user
enqueueSnackbar(<a href={message}>{message}</a>); //1)
//vs. remote user
const newMessage = stringToHTML(message);
enqueueSnackbar(newMessage); // should it be the same as 1)?
感谢反馈。我正在以两种不同的方式处理消息,具体取决于 URL 是否被传递。实际上,项目作者实际上提供了一个干净的解决方案。安装 Linkify 包只允许那些被推断为 HTML 的字符串元素被格式化为这样。
这里是修改后的DataTrack.tsx内容。表现出色!
import React from 'react';
import { useEffect } from 'react';
import { DataTrack as IDataTrack } from 'twilio-video';
import { useSnackbar } from 'notistack';
import Linkify from 'react-linkify';
export default function DataTrack({ track }: { track: IDataTrack }) {
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
const handleMessage = (message: string) =>
enqueueSnackbar(
<Linkify
componentDecorator={(decoratedHref, decoratedText, key) => (
<a target="_blank" rel="noopener" href={decoratedHref} key={key}>
{decoratedText}
</a>
)}
>
{message}
</Linkify>
);
track.on('message', handleMessage);
return () => {
track.off('message', handleMessage);
};
}, [track, enqueueSnackbar]);
return null; // This component does not return any HTML, so we will return 'null' instead.
}
所以我正在分叉一个示例 Twilio 视频聊天应用程序 (https://github.com/twilio/twilio-video-app-react)。对于聊天功能,采用了 Snackbar 消息。哪个工作正常。但是我想让用户发送以http开头的消息,这样消息就会作为超链接发送URL.
ChatInput 组件可以很好地将此消息显示为本地用户(即发件人)的超链接 URL。但是远程用户的 DataTrack 事件处理程序不会将消息显示为超链接。只显示文字。
这里是 ChatInput.tsx,其中任何以 http 开头的消息都会正确显示给本地用户。
import React, { useState } from 'react';
import { Button, FormControl, TextField } from '@material-ui/core';
import { useSnackbar } from 'notistack';
import useVideoContext from '../../../hooks/useVideoContext/useVideoContext';
export default function ChatInput() {
const [message, setMessage] = useState('');
const { room } = useVideoContext();
const { enqueueSnackbar } = useSnackbar();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setMessage(e.target.value);
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (message) {
// Get the LocalDataTrack that we published to the room.
const [localDataTrackPublication] = [...room.localParticipant.dataTracks.values()];
// Construct a message to send
const fullMessage = `${room.localParticipant.identity} says: ${message}`;
if (message.startsWith('http')) {
// Send the message
localDataTrackPublication.track.send(`<a href="${message}">${message}</a>`);
// Render the message locally so the local participant can see that their message was sent.
enqueueSnackbar(<a href={message}>{message}</a>);
} else {
// Send the full message
localDataTrackPublication.track.send(fullMessage);
// Render the full message locally so the local participant can see that their message was sent.
enqueueSnackbar(fullMessage);
}
//Reset the text field
setMessage('');
}
};
return (
<form autoComplete="off" style={{ display: 'flex', alignItems: 'center' }} onSubmit={handleSubmit}>
<FormControl>
<label htmlFor="chat-snack-input" style={{ color: 'black' }}>
Say something:
</label>
<TextField value={message} autoFocus={true} onChange={handleChange} id="chat-snack-input" size="small" />
</FormControl>
<Button type="submit" color="primary" variant="contained" style={{ marginLeft: '0.8em' }}>
Send
</Button>
</form>
);
}
这里是 DataTrack.ts,它只显示任何远程用户的字符串文字。
import { useEffect } from 'react';
import { DataTrack as IDataTrack } from 'twilio-video';
import { useSnackbar } from 'notistack';
var stringToHTML = function (str) {
var parser = new DOMParser();
var doc = parser.parseFromString(str, 'text/html');
return doc.body;
};
export default function DataTrack({ track }: { track: IDataTrack }) {
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
const handleMessage = (message: string) => {
if (message.startsWith('http')) {
const newMessage = stringToHTML(message);
enqueueSnackbar(newMessage);
}
else {
enqueueSnackbar(message); }
};
track.on('message', handleMessage);
return () => {
track.off('message', handleMessage);
};
}, [track, enqueueSnackbar]);
return null; // This component does not return any HTML, so we will return 'null' instead.
}
关于如何让远程用户接收发件人看到的相同超链接 URL 有什么建议吗?
TL;DR: 函数 stringToHTML
在将消息传递给 NotiStack 时返回一个 DOM 元素引用而不是 React 元素,请尝试包装它使用 React 元素:
//const newMessage = stringToHTML(message);
enqueueSnackbar(<div dangerouslySetInnerHTML={{__html:message}} />);
NL;PR: And/Or 我不确定为什么您在两个组件中以不同的方式将消息值传递给 NotiStack:
if (message.startsWith('http')) {
//local user
enqueueSnackbar(<a href={message}>{message}</a>); //1)
//vs. remote user
const newMessage = stringToHTML(message);
enqueueSnackbar(newMessage); // should it be the same as 1)?
感谢反馈。我正在以两种不同的方式处理消息,具体取决于 URL 是否被传递。实际上,项目作者实际上提供了一个干净的解决方案。安装 Linkify 包只允许那些被推断为 HTML 的字符串元素被格式化为这样。
这里是修改后的DataTrack.tsx内容。表现出色!
import React from 'react';
import { useEffect } from 'react';
import { DataTrack as IDataTrack } from 'twilio-video';
import { useSnackbar } from 'notistack';
import Linkify from 'react-linkify';
export default function DataTrack({ track }: { track: IDataTrack }) {
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
const handleMessage = (message: string) =>
enqueueSnackbar(
<Linkify
componentDecorator={(decoratedHref, decoratedText, key) => (
<a target="_blank" rel="noopener" href={decoratedHref} key={key}>
{decoratedText}
</a>
)}
>
{message}
</Linkify>
);
track.on('message', handleMessage);
return () => {
track.off('message', handleMessage);
};
}, [track, enqueueSnackbar]);
return null; // This component does not return any HTML, so we will return 'null' instead.
}