• react-native渲染富文本的几种方案


    前言

    在日常开发中,经常需要用到富文本编辑器来编辑业务内容,例如新闻、论坛等,然后在用到的地方进行渲染,一般在web端可以直接在html中载入编辑好的内容(一般是一段html),不过在react-native的app中不能直接把html渲染进去,接下来我介绍几种渲染html的方案。

    正文

    1、使用已有的组件

    既然已经有人造好了轮子,我们就直接拿来用就可以了。可以在网上搜 react-native 富文本组件,可以有几个选择方案,我这边以react-native-render-html,npm地址:www.npmjs.com/package/rea…

    使用方法:

    import RenderHTML , {IMGElementContainer, useIMGElementProps, useIMGElementState, IMGElement} from "react-native-render-html";
    
    // 其他代码 ...
    _previewImg = (src) => {const images = [{ uri : src}];Overlay.show(({flex: 1}}overlayOpacity={1}ref={v => this.fullImageView = v}>{flex: 1}}control={true}images={images}defaultIndex={0}onPress={() => {this.fullImageView && this.fullImageView.close()}}/>));
    };
    
    _imagesNode = (props) => {const imgElementProps = useIMGElementProps(props);return ();
    };
    
    render() {const styles = this.styles;const Props = this.props;return ({html: this._handleContent(Props.data)}}renderers={{img: this._imagesNode}}tagsStyles={{p: {marginVertical: 5}}}{...Props}/>);
    }
    // 其他代码 ... 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这个组件的原理就是把富文本的html标签一个个的解析出来,转换成react-native的标签,再进行渲染就可以了。

    注意:如果需要点击放大预览的话,图片需要单独处理。

    2、使用webview

    我们除了直接使用已有的组件之外,还有可以使用webview进行渲染。webview就相当于嵌在App里面的浏览器一样,可以直接访问和渲染html代码。其中webview载入html资源还有两种方法:

    (1)直接在source上写html,然后把内容(data)放进去:

    import WebView from 'react-native-webview'
    // 其他代码...
     render() {const Props = this.props;const { webHeight } = this.state;let data = this._handleContent(Props.data);return {html: `${data}`, baseUrl:Platform.OS === "ios" ? undefined : ''}}style={{height: webHeight}}contentInset={{top:0,left:0}} >}
    // 其他代码... 
    
    • 1
    • 2
    • 3
    • 4

    (2)使用资源文件载入:

    具体实现是,先新建一个html文件,在里面写好初始化方法init,提供入参data(html内容)和fn(需要执行的方法),代码如下:

    测试富文本
     
    
    • 1
    • 2

    然后再webview引入这个html,注意ios安卓平台引入的路径问题,代码如下:

    // 其他代码...
    bootstrapJS() {let data = this._handleContent(this.props.data);let fun =`(function () { console.log("我是预留的方法");} ())`;return `init(${JSON.stringify(data)}, ${fun})`
    }
    render() {const Props = this.props;const { webHeight } = this.state;const source = (Platform.OS == 'ios') ? require('../../../html/renderHtml.html') : { uri: 'file:///android_asset/html/renderHtml.html' };return {!!Props.data && {height: webHeight}}contentInset={{top:0,left:0}}injectedJavaScript={this.bootstrapJS()}scalesPageToFit={false}/>}
    }
    // 其他代码... 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3)webview高度自适应问题

    以上两种方法都能满足App渲染富文本html的需求,但是高度得需要写死,这样肯定是没有达到预期的,所以我们需要根据内容自适应。webview有个参数是onNavigationStateChange:当导航状态发生变化的时候调用。

    我们可以在html里面写个方法,把body的高度写到html 的title标签上,这样就会触发导航状态变化,然后再把高度设置到webview样式上就可以了。具体实现:

    import WebView from 'react-native-webview'
    // 其他代码...
     render() {const Props = this.props;const { webHeight } = this.state;let data = this._handleContent(Props.data);return {html: `${data}`, baseUrl:Platform.OS === "ios" ? undefined : ''}}style={{height: webHeight}}contentInset={{top:0,left:0}}onNavigationStateChange={(event)=>{if(event.title && !Props.webHeight) {if (this.uuid === event.target) {this.setState({webHeight:((isNaN(parseInt(event.title)) ? 0 : parseInt(event.title)))})}}}}>}
    // 其他代码... 
    
    • 1
    • 2
    • 3
    • 4

    html的高度不确定多数来源于图片的加载,如果有多个图片的话,onload方法里面拿高度并不一定能得到最后的高度,因为可能有图片没有加载出来。所以需要不断的监听body高度的变化,再设置回去,所以我们可以在onload方法中写,每加载完一个图片就执行一次changeHeight方法:

    var height = null;
    function changeHeight() {if (document.body.scrollHeight != height) {document.title = document.body.scrollHeight;}
    }
    
    setTimeout(function(){let images = document.querySelectorAll("img");for (let i = 0; i < images.length; i++) {images[i].onload = function() {changeHeight();}}
    },300) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (4)图片预览及链接跳转问题

    使用webview进行渲染html的话,就不能直接操作里面的图片及链接(a标签)了,不过webview提供了一个与App通信的功能,也就是onMessage

    onMessage:在 webview 内部的网页中调用 window.postMessage 方法时可以触发此属性对应的函数,从而实现网页和 RN 之间的数据交换。

    所以我们可以在html上的onload方法写图片的点击事件,然后发送给react-native这边,react-native在用预览图片的方法进行预览或者对链接的跳转。

    html代码:

     // 图片处理let imgArr = document.querySelectorAll("img");for(let i = 0; i < imgArr.length; i ++){imgArr[i].onclick = function() {window.postMessage(JSON.stringify({type: "img", url: imgArr[i].getAttribute("src")}));}}// a标签处理let aArr = document.querySelectorAll("a");for(let i = 0; i < aArr.length; i ++){let elem = aArr[i];let url = elem.getAttribute("href");elem.onclick = function() {window.postMessage(JSON.stringify({type: "a", url: url}));};elem.setAttribute("href", "javascript: void(0)");} 
    
    • 1

    react-native代码:

     // 其他代码...
    _onLinkPress = (url) => {Linking.openURL(url);
    };
    
    _previewImg = (url) => {let images = [];if (url) {images = [{uri: url}];} Overlay.show(({flex: 1}}overlayOpacity={1}ref={v => this.fullImageView = v}>{flex: 1}}control={true}images={images}defaultIndex={0}onPress={() => {this.fullImageView && this.fullImageView.close()}}/>));
    };
    _onMessage = (event) => {let data = JSON.parse(decodeURIComponent(decodeURIComponent(event.nativeEvent.data))) || {};data.type === "img" && this._previewImg(data.url);data.type === "a" && this._onLinkPress(data.url);
    };
     // 其他代码... 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (5)通过postMessage设置高度

    所以我们也可以使用postMessage来发送html的高度,html中的changeHeight方法可以改成以下代码:

    function changeHeight() {if (document.body.scrollHeight != height) {height = document.body.scrollHeight;window.postMessage(JSON.stringify({type: 'setHeight',height: height,}))}
    } 
    
    • 1
    • 2

    可以监听设置高度的 react-native代码:

    _onMessage = (event) => {let data = JSON.parse(decodeURIComponent(decodeURIComponent(event.nativeEvent.data))) || {};data.type === "img" && this._previewImg(data.url);data.type === "a" && this._onLinkPress(data.url);try {if (data.type === 'setHeight' && data.height > 0) {this.setState({ webHeight: data.height })}} catch (error) {// ...}
    }; 
    
    • 1
    • 2

    至此,react-native渲染富文本的方案介绍完了,有写的不好以及错误的地方欢迎大家指出。

  • 相关阅读:
    QQ频道导航退出
    C#底层库--操作Excel帮助类(读取、导出表格)
    微服务开发系列 第五篇:Redis
    vs2022+resharper创建模板——实现在新建文件的时候自动生成防卫式声明和自定义语句
    决策树算法:原理与python实现案例
    jsp 技术
    java 多线程&wait条件发生变化与使用while的必要性——77
    Thread中的方法测试(run,yield,sleep,start,join等)
    Web App、Hybrid App、Native App 横向对比
    C#不通过byte[],直接对内存映射文件复制内存
  • 原文地址:https://blog.csdn.net/web2022050903/article/details/126302933