接上篇博客,如今增长一个新需求:h5页面B区显示富文本HTML片断。html
要求git
有一段PC端显示的富文本HTML片断,在手机H5页面B区上加载显示github
保持PC端的样式缩放适应手机屏幕浏览器
若是HTML富文本有图片服务器
提示框架
看到需求时,第一想到的是只是显示一段富文本内容,为何要用iframe,直接显示不就好了。 iframe仍是有挺多缺点的:ide
这么多缺点为何还要用呢(关键是我对iframe的使用不太熟悉,手动微笑。。。)
高人指点,由于想用iframe隔离全局样式对富文本样式的影响,emmmm,确实颇有道理。函数
好比你在全局样式里写了一个样式:工具
p {
font-size: 18px;
}
复制代码
那么富文本的内容也会受到这个全局样式的影响,全部p里面的字体大小都会是18px。这可不是咱们想获得的。post
其实看到这,确定会想到,只要在全局样式里注意一下,不要写一些可能会影响全局的样式就好了,好比不写标签的样式。这对于一个新项目可能较为容易去实现,若是一个项目已经很是庞大或通过多人的修改,把不规范的样式所有改掉好像有点不太现实。
好了,暂时没有想到其余好的办法,只能选择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();
...
}
});
复制代码
代码实现的较为粗糙,还有不少能够优化提升的地方。
具体代码见个人github,并详细介绍了项目的使用方法。 由于懒,我没有把此次的代码单独放到一个repo,就和上次的放在一块儿,实在惭愧。。。