美文网首页Web前端之路
React api: dangerouslySetInnerHT

React api: dangerouslySetInnerHT

作者: vinoooooo | 来源:发表于2019-08-01 20:58 被阅读14次

    今天在项目中,遇到了一个需求:将后台返回的 [微笑] [撇嘴] 这种表情文字转化为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

    相关文章

      网友评论

        本文标题:React api: dangerouslySetInnerHT

        本文链接:https://www.haomeiwen.com/subject/lpzcdctx.html