H5頁面PC富文本內容自適應顯示

上篇博客,如今增長一個新需求:h5頁面B區顯示富文本HTML片斷。html

功能描述

  • 要求git

    • 有一段PC端顯示的富文本HTML片斷,在手機H5頁面B區上加載顯示github

    • 保持PC端的樣式縮放適應手機屏幕瀏覽器

    • 若是HTML富文本有圖片服務器

      • 圖片默認不加載
      • 當手機可視區間到B區時候,圖片觸發懶加載顯示
      • 點擊富文本圖時候,有彈層加載圖片,可放大查看
  • 提示框架

    • 能夠考慮用iframe方式處理富文本
    • 可是要考慮到iframe的父子頁面的通訊和兼容性
    • 還有考慮到iframe裏富文本圖片懶加載致使高度變化帶來的父頁面的高度自適應

具體實現過程

爲何選擇iframe

看到需求時,第一想到的是隻是顯示一段富文本內容,爲何要用iframe,直接顯示不就好了。 iframe仍是有挺多缺點的:ide

  1. 會產生不少頁面,不容易管理
  2. 不容易打印
  3. 瀏覽器的後退按鈕無效
  4. 代碼複雜,沒法被一些搜索引擎索引到,這一點很關鍵,如今的搜索引擎爬蟲還不能很好的處理iframe中的內容,因此使用iframe會不利於搜索引擎優化。
  5. 多數小型的移動設備(PDA 手機)沒法徹底顯示框架,設備兼容性差。
  6. 多框架的頁面會增長服務器的http請求,對於大型網站是不可取的。

這麼多缺點爲何還要用呢(關鍵是我對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();
            ...
        }
    });
複製代碼

最終效果

最終效果

優化

代碼實現的較爲粗糙,還有不少能夠優化提升的地方。

  • 阻尼效果:AB區實現思路如出一轍,可考慮抽成公共插件。
  • 圖片點擊:使用fastclick或zepto對移動端的click事件進行優化。
  • 真機調試:只是在Google開發者工具上調試了下,沒有在真機上調試,估計有點兼容性問題。

具體代碼見個人github,並詳細介紹了項目的使用方法。 由於懶,我沒有把此次的代碼單獨放到一個repo,就和上次的放在一塊兒,實在慚愧。。。

相關文章
相關標籤/搜索