将 HTML 插入到 Snackbar 消息中
Posted
技术标签:
【中文标题】将 HTML 插入到 Snackbar 消息中【英文标题】:Inserting HTML into a Snackbar message 【发布时间】:2021-03-03 07:34:32 【问题描述】:所以我要分叉一个示例 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 的任何建议?
【问题讨论】:
【参考方案1】:TL;DR:函数stringToHTML
在将消息传递给NotiStack时返回一个DOM元素引用而不是React元素,尝试用React元素包装它:
//const newMessage = stringToHTML(message);
enqueueSnackbar(<div dangerouslySetInnerHTML=__html:message />);
NL;PR: 和/或我不确定为什么您在两个组件中将消息值传递给 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)?
【讨论】:
【参考方案2】:感谢您的反馈。我以两种不同的方式处理消息,具体取决于是否传递了 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.
【讨论】:
以上是关于将 HTML 插入到 Snackbar 消息中的主要内容,如果未能解决你的问题,请参考以下文章
Vue Snackbar 消息条队列显示,依次动画消失的实现
Android:MVVM 是不是可以显示来自 ViewModel 的消息(toast/snackbar 等)
在 RecyclerView 中配置 ItemTouchHelper 以使 Snackbar 被显示的另一个 Snackbar 解散