H5页面PC富文本内容自适应显示

简介: 有一段PC端显示的富文本HTML片段,在手机H5页面B区上加载显示

上篇博客,现在增加一个新需求:h5页面B区显示富文本HTML片段。

功能描述

  • 要求

    • 有一段PC端显示的富文本HTML片段,在手机H5页面B区上加载显示

    • 保持PC端的样式缩放适应手机屏幕

    • 如果HTML富文本有图片

      • 图片默认不加载
      • 当手机可视区间到B区时候,图片触发懒加载显示
      • 点击富文本图时候,有弹层加载图片,可放大查看
  • 提示

    • 可以考虑用iframe方式处理富文本
    • 但是要考虑到iframe的父子页面的通信和兼容性
    • 还有考虑到iframe里富文本图片懒加载导致高度变化带来的父页面的高度自适应

具体实现过程

为什么选择iframe

看到需求时,第一想到的是只是显示一段富文本内容,为什么要用iframe,直接显示不就行了。 iframe还是有挺多缺点的:

  1. 会产生很多页面,不容易管理
  2. 不容易打印
  3. 浏览器的后退按钮无效
  4. 代码复杂,无法被一些搜索引擎索引到,这一点很关键,现在的搜索引擎爬虫还不能很好的处理iframe中的内容,所以使用iframe会不利于搜索引擎优化。
  5. 多数小型的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。
  6. 多框架的页面会增加服务器的http请求,对于大型网站是不可取的。

这么多缺点为什么还要用呢(关键是我对iframe的使用不太熟悉,手动微笑。。。)
高人指点,因为想用iframe隔离全局样式对富文本样式的影响,emmmm,确实很有道理。

比如你在全局样式里写了一个样式:

	p {
		font-size: 18px; 
	}
复制代码

那么富文本的内容也会受到这个全局样式的影响,所有p里面的字体大小都会是18px。这可不是我们想得到的。

其实看到这,肯定会想到,只要在全局样式里注意一下,不要写一些可能会影响全局的样式就行了,比如不写标签的样式。这对于一个新项目可能较为容易去实现,如果一个项目已经非常庞大或经过多人的修改,把不规范的样式全部改掉好像有点不太现实。

好了,暂时没有想到其他好的办法,只能选择iframe。

实现思路

图片自适应

因为返回的数据是一段html片段,所以选择iframe的srcdoc属性(规定在<iframe>中显示的页面的 HTML 内容),我们可以在获取到数据之后对数据进行一些处理(图片懒加载,后面会讲到),然后再字符串拼接成一段完整的HTML。
html中设置meta标签,允许用户缩放:

<meta name="viewport" content="width=device-width, initial-scale=1">
复制代码

设置全局样式

<style>
    body {height: ${clientHeight}px;}   
    img {max-width: ${clientWidth}px;}
</style>
复制代码

clientHeight是屏幕高度,clientWidth是屏幕宽度。
设置body的高度是因为这篇博客需求是接着上篇博客的需求来的(需要实现阻尼效果),在iframe里,我禁用了scroll,具体思路可参考上篇博客
设置img最大宽度是为了实现图片自适应,不会因为太大而超出屏幕。

图片懒加载

直接上代码:
修改字符串内容:

    const newHtml = result.content.replace(/<img.*?\/>/g, match => {
        return match.replace('src', 'src="./images/iframe/loading.gif" data-src');
    });
复制代码

懒加载函数:

    const clientHeight = $(window).height();
	    let continueLoading = true;
	    const imgTags = document.getElementsByTagName('img');
	    const lazyload = () => {
	        let num = 0;
	        for (let img of imgTags) {
	            const { top } = img.getBoundingClientRect();
	            if (/loading.gif/.test(img.src)) {
	            	top < clientHeight && (img.src = img.dataset.src);
	            } else {
	            	num++;
	            }
	        }
	        num === imgTags.length && (continueLoading = false);
    };

    $('.main').on('touchmove', e => {
        continueLoading && lazyload();
    });
复制代码

我这里是先用正则进行替换,先显示loading,并用data-src记住图片地址。然后再touchmove事件中检测并进行懒加载:
getBoundingClientRect()用来检测图片是否在可视区域内。
continueLoading是一个标志,当所有图片都加载完成后,就不再触发lazyload函数。

图片弹层查看

这个非常简单了,用一个绝对定位的div去显示图片就可以了,div背景色设置成白色(或者是其他你喜欢的颜色),display: none,当点击iframe中的图片时,设置div里img标签src的值,并显示div。再次点击弹层的图片,隐藏弹层。

    $('.main img').on('click', e => {
        $('.img-modal .img-detail').attr('src', e.target.src);
        $('.img-modal').show();
    });
    $('.img-modal').on('click', () => {
    	$('.img-modal').hide();
    });
复制代码

父子间通信

因为在ifame所在的B区也要实现阻尼效果。其他部分的思路和A区的阻尼效果实现思路相同,只不过当用户到达页面顶部并下拉到临界值时,使用postmessage通知父页面显示A区,隐藏B区。
iframe中:

	$('.main').on('touchend', e => {
    	//其他逻辑
    	...
        if (last_distance >= RANGE_TOP) {
            //切换到上一个页面
            window.parent.postMessage('prev', '*');
            ...
        }
    });
复制代码

父页面中:

	window.addEventListener('message', rs => {
        if (rs.data === 'prev') {
            $('.pageB').hide();
            $('.pageA').show();
            ...
        }
    });
复制代码

最终效果

最终效果

优化

代码实现的较为粗糙,还有很多可以优化提高的地方。

  • 阻尼效果:AB区实现思路一模一样,可考虑抽成公共插件。
  • 图片点击:使用fastclick或zepto对移动端的click事件进行优化。
  • 真机调试:只是在Google开发者工具上调试了下,没有在真机上调试,估计有点兼容性问题。

具体代码见我的github,并详细介绍了项目的使用方法。
因为懒,我没有把这次的代码单独放到一个repo,就和上次的放在一起,实在惭愧。。。



原文发布时间为:2018年06月26日
原文作者:BeckyWang
本文来源: 掘金  如需转载请联系原作者
相关文章
|
存储 缓存 资源调度
Koodo Reader : 一个开源免费的电子书阅读器
【1月更文挑战第3天】 今天在浏览 GitHub 的时候,偶然发现了一个非常有趣的开源项目——Koodo Reader。这个项目是一款开源免费的电子书阅读器,支持多种格式。它具有一些非常独特的功能,深深地吸引了我的注意。在接下来的内容中,我将为大家详细介绍一下这个备受关注的阅读器项目。
1940 3
Koodo Reader : 一个开源免费的电子书阅读器
|
应用服务中间件 nginx
Centos7.3 卸载 Nginx(彻底卸载) 并重新安装 Nginx(RPM源yum安装)
Centos7.3 卸载 Nginx(彻底卸载) 并重新安装 Nginx(RPM源yum安装)
1383 0
Centos7.3 卸载 Nginx(彻底卸载) 并重新安装 Nginx(RPM源yum安装)
目前还存活的多个电驴下载站点
<div id="link-report"> <div class="topic-content"> <p>0、<a href="http://www.douban.com/link2?url=http%3A//www.emule-project.net/" rel="nofollow" target="_blank">http://www.emule-pro<wbr>ject.net
22085 0
|
11月前
|
运维 应用服务中间件 nginx
docker运维查看指定应用log文件位置和名称
通过本文的方法,您可以更高效地管理和查看Docker容器中的日志文件,确保应用运行状态可控和可监测。
1710 28
|
人工智能 自然语言处理 搜索推荐
微软开源基于ChatGPT的,超级文本代码智能体
【7月更文挑战第17天】微软的TaskWeaver是开源的LLM框架,聚焦领域特定数据分析与个性化需求。它以代码优先,将用户请求转为可执行代码,增强处理复杂任务的效率和准确性。通过用户定义插件实现定制,适应多种场景。然而,转化请求可能引入复杂性和错误,非技术用户使用插件有难度,且开源带来的安全与隐私问题需关注。[论文链接](https://arxiv.org/abs/2311.17541)**
280 4
|
9月前
|
人工智能 大数据 BI
DeepSeek-R1模型全栈开发与部署实战培训高级研修班
掌握DeepSeek-R1模型从本地部署到工业级落地的全栈技术能力,包括环境配置、模型微调、推理优化及AI Agent开发等核心环节,能够独立完成基于RTX 4090的模型全生命周期开发任务。通过真实场景案例与全链路项目实战,培养将大模型技术转化为教育、企业服务等垂直领域解决方案的能力,涵盖需求分析、性能调优及工程化部署等关键技能,满足学术研究与产业落地的双重需求。
202 0
|
前端开发 JavaScript
轻松上手:基于single-spa构建qiankun微前端项目完整教程
轻松上手:基于single-spa构建qiankun微前端项目完整教程
622 0
Java的变量的作用域
Java的变量的作用域
345 1
|
传感器 监控 安全
物联网技术在智能家居安全监控中的应用
物联网技术在智能家居安全监控中的应用
|
负载均衡 Java Linux
管道,信号量,共享内存,socket的实际使用场景和NSPipe管道的使用
管道,信号量,共享内存,socket的实际使用场景和NSPipe管道的使用
272 0