React api: dangerouslySetInnerHTML

今天在项目中,遇到了一个需求:将后台返回的 [微笑] [撇嘴] 这种表情文字转化为emoji表情...

表情转化组件

// 定义所有表情文字
const word = ["微笑","撇嘴","色","发呆","得意" ...]
    ...

class Face extends React.PureComponent<Props, State> {
    ...
// 文字转图片接口
public insetFace(content: string): any {
    if (!content || content.trim().length <= 0) {
        return "";
    }
    let reg = /\[.*?\]/gi;  //匹配表情正则
    let rgArr = content.match(reg);
    if (rgArr && rgArr.length > 0) {
        rgArr.map((item: string) => {
            let w = item.replace(/^\[|\]$/gi, "");
            if (word.indexOf(w) != -1) {
                content = content.replace(
                    item,
                    `<img class="emoji-item" src='${require("@img/face/face_" +word.indexOf(w) +".png")}'/>`
                );
            }
        });
    }
    return content;
}
    ...
export const insetFace = FaceFun.insetFace;

类似于微信聊天,由于数据中既有 图片 又有 文字+表情,所以这里要判断是否是图片this.isImg,是图片的话就将地址赋值给src,若包含[微笑]这种emoji标签,则需要引用insetFace这个接口,将data传入进行转换。

index.tsx

// 引入
import { insetFace } from "@component/face";
  ...
export default class ScriptBox extends ListPage<Props, State> {
    constructor(props: Props) {
        super(props);
    }
    ...
    // 判断是否图片函数
    isImg(data: string) {
        if (!data || data.length <= 0) {
            return false;
        }
        let reg = /^https?:\/\/.*?.(png|jpg|jpeg)$/gi;
        return reg.test(data);
    }
  ...
     {targetData &&targetData.scriptmessage &&targetData.scriptmessage.length > 0 &&
        targetData.scriptmessage.map(
                (v: any, i: number) => {
                    return (
                        <React.Fragment key={i}>
                            {v[0] && v[0].length > 0 && (
                                <div className="detail-item">
                                    <div className="name"> A:</div>
                                    <div className="content">
                                        {this.isImg(v[0]) ?
                                          (<img className="detail_img" src={v[0]} />) : ( insetFace(v[0]) )}
                                    </div>
                                </div>
                                )}
                               ...
                               ...
                      </React.Fragment>
}

渲染出来结果是下图:


失败.png

总结原因:

这里将insetFace接口返回的<img class="emoji-item" src='${require("@img/face/face_" +word.indexOf(w) +".png")}'/>当作字符串来渲染。类似于JS的innerText,而需求则是将其作用为innerHTML
所以这里需要引入react的一个apidangerouslySetInnerHTML

dangerouslySetInnerHTML api官方文档介绍

dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易无意中使用户暴露于跨站脚本(XSS)的攻击。因此,你可以直接在 React 中设置 HTML,但当你想设置 dangerouslySetInnerHTML 时,需要向其传递包含 key 为 __html 的对象,以此来警示你。例如:

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

在此次应用中,将index.tsx中的代码改为:

...
...
{targetData.scriptmessage.map(
        (v: any, i: number) => {
            return (
                <React.Fragment key={i}>
                    {v[0] && v[0].length > 0 && (
                        <div className="detail-item">
                            <div className="name">A:</div>
                            <div className="content"
                                dangerouslySetInnerHTML={{
                                    __html: this.isImg(v[0])
                                        ? `<img class="detail_img" src=${v[0]} />`
                                        : insetFace( v[0] )
                                }}
                            >
                            </div>
                        </div>
                    )}
                </React.Fragment>
                ...
                ...

结果:

成功.png

注意:

  1. dangerouslySetInnerHTML的语法:第一层{ }代表JSX语法,第二层{ }是一个__html:string键值对
  2. 最初未用反引号包裹<img className="detail_img" src=${v[0]} />结果渲染的全是[object Object],想了半天才反应过来__html:string
  3. 用反引号包裹的html代码不再是JSX语法,所以clasName要改为class
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • 前言 在Jq,原生javascript时期,在写页面时,往往强调的是内容结构,层叠样式,行为动作要分离,三者之间分...
    itclanCoder阅读 715评论 0 2
  • HTML模版 之后出现的React代码嵌套入模版中。 1. Hello world 这段代码将一个一级标题插入到指...
    ryanho84阅读 6,229评论 0 9
  • GUIDS 第一章 为什么使用React? React 一个提供了用户接口的JavaScript库。 诞生于Fac...
    jplyue阅读 3,532评论 1 11
  • 以下内容是我在学习和研究React时,对React的特性、重点和注意事项的提取、精练和总结,可以做为React特性...
    科研者阅读 8,229评论 2 21
  • 今天傍晚,刚下完雨,空气湿润,落山的太阳恋恋不舍,一道彩虹挂在天上,五颜六色很好看,像一座彩色的桥。这是我第一次见...
    美人如玉剑如虹_a962阅读 285评论 0 0