在有很多文檔采用的是PDF文件格式,我們可以通過“云展網(wǎng)”之類的在線服務(wù),將這些PDF轉(zhuǎn)換成帶3D翻頁效果的電子書,不但閱讀方便,效果酷炫,而且還能很方便地分享給自己的好友。
簡單上傳,PDF變身在線電子書
首先準(zhǔn)備好需要轉(zhuǎn)換的PDF文件,登錄https://book.yunzhan365.com/后按提示先注冊為用戶,登錄后選擇“創(chuàng)建HTML5文檔”,接著點(diǎn)擊“上傳我的文檔”,然后按提示將需要轉(zhuǎn)換的PDF文件上傳到網(wǎng)站進(jìn)行轉(zhuǎn)換處理,在這里還可以為在線電子書設(shè)置背景色、音樂等信息(圖1)。
圖1 轉(zhuǎn)換文件
小提示:如果要將常見的DOC、PPT等文檔轉(zhuǎn)化為在線書籍,那么可以利用Word 2016、PPT 2016等,打開文檔后點(diǎn)擊“文件→導(dǎo)出→創(chuàng)建PDF/XPS”,將文件轉(zhuǎn)化為PDF后再進(jìn)行上傳即可。
文件轉(zhuǎn)換完畢后會(huì)在“我的圖書”看到已經(jīng)轉(zhuǎn)換的書籍,按提示點(diǎn)擊即可開始閱讀,轉(zhuǎn)換后的書籍和在線電子書非常類似,在電腦上我們直接使用鼠標(biāo)進(jìn)行翻頁閱讀即可(圖2)。
圖2 閱讀轉(zhuǎn)換后的書籍
當(dāng)然這個(gè)在線書籍同樣可以轉(zhuǎn)發(fā)給微信、QQ好友,點(diǎn)擊上述頁面的分享按鈕,然后將類似http://www.yunzhan365.com/read/gnsc/biec/mobile/index.html這樣的網(wǎng)址復(fù)制。這樣我們需要和微信好友共享超過25MB的PDF文檔時(shí)。只要先通過上述的方法轉(zhuǎn)化為在線文檔,然后將分享的網(wǎng)址發(fā)動(dòng)給好友。好友在微信中直接打開其中的鏈接,在微信中就可以直接進(jìn)行閱讀,省去直接傳送PDF和微信25MB文件大小的限制,因?yàn)檫@里分享的只是一個(gè)網(wǎng)址(圖3)。
圖3 微信里閱讀在線書籍
當(dāng)然如果是企業(yè)宣傳使用,如直接把產(chǎn)品的說明文檔制作成翻頁電子書。那么可以將文檔上傳轉(zhuǎn)化,接著點(diǎn)擊“分享鏈接”,在彈出的窗口將“插入到網(wǎng)站”代碼復(fù)制。在公司主頁頁面,將這段代碼插入到首頁文件中,這樣用戶在訪問官網(wǎng)時(shí),就可以通過點(diǎn)擊鏈接直接打開宣傳點(diǎn)在文檔了(圖4)。
圖4 插入網(wǎng)頁代碼
隨著近幾年移動(dòng)營銷頁的火爆,催生了一個(gè)中國式的名詞「H5」。而 H5 最常見的形態(tài)就是類似幻燈片翻頁效果。
我們需要制作 H5 的時(shí)候,最快的辦法就是使用一些滑動(dòng)插件庫,如 iDangero.us 出品的 Swiper,百度 BE-FE 出品的 iSlider。通過這些翻頁庫提供的強(qiáng)大的配置功能,我們就能實(shí)現(xiàn)很酷炫的翻頁效果。當(dāng)然,這些庫還支持自動(dòng)播放,點(diǎn)擊切換和當(dāng)前頁面指示等配置,所以還能用在網(wǎng)頁上,實(shí)現(xiàn)一些 web carousel 的效果。
百度 H5 也先后使用了 Swiper 和 iSlider 作為 H5 運(yùn)行時(shí)的翻頁框架,隨著用戶越來越多,也遇到了一些問題:
而我們希望的 H5 翻頁庫能和平臺(tái)本身的功能完美貼合,在保持體積小的同時(shí),在翻頁的時(shí)候能做到「絲般順滑」。于是我們就開始了研(zao)究(lun)之(zi)旅。
H5 滑屏框架的開發(fā),第一個(gè)問題就是:頁面是否跟隨手指滑動(dòng)?這也是騰訊 ISUX 團(tuán)隊(duì)的《滑屏 H5 開發(fā)實(shí)踐九問》的第一問(這篇文章原文出處現(xiàn)在是 404 ,大家可以在其他的轉(zhuǎn)載網(wǎng)站看到),這里用這篇文章的圖片說明一下這個(gè)問題。
上圖:不跟隨手指滑動(dòng),下圖:跟隨手指滑動(dòng)。
左邊的是不跟隨手指滑動(dòng),只需要關(guān)注手指觸碰開始和離開兩個(gè)時(shí)間點(diǎn),中間過程不用考慮。所以實(shí)現(xiàn)起來比較簡單。但是用戶的操作沒有實(shí)時(shí)的反饋,體驗(yàn)不夠好。因此,盡管實(shí)現(xiàn)起來更復(fù)雜,我們?nèi)匀粵Q定實(shí)現(xiàn)前一種「跟隨手指滑動(dòng)」的效果。
下圖是跟隨手指滑動(dòng)的 H5 最直觀的版本,所有的「頁面」依次從上到下,首尾相接。需要說明一下,這里的「頁面」打引號(hào),是因?yàn)閷?shí)際上他們都是 div,后文說的頁面都指這些 div。同時(shí),我們這里以最常見的豎直方向滑動(dòng)為例,水平方向同理。
基本原理圖
這些 div 的寬度和高度都是 100% 的容器高度,可視區(qū)域是中間的部分,我們監(jiān)聽 touchstart, touchmove, touchend 事件,跟鼠標(biāo)拖拽的原理類似:
深入探究
簡單的版本在上一部分很容易就實(shí)現(xiàn)了,如果其他需求不多,頁面上元素和動(dòng)畫比較少,基本上就夠用了。但是本文要探究的是如何能做到「絲般順滑」,其實(shí)就是兩個(gè)字:性能。
性能的瓶頸是什么呢?
我們的目標(biāo)是:在「三多一低」(頁面多、元素多、動(dòng)畫多,配置低)的情況下,滑動(dòng)翻頁時(shí),盡可能不產(chǎn)生卡頓。
我們分成兩部分來看這問題:手指離開屏幕前和手指離開屏幕后。
手指離開屏幕前
此時(shí)比較耗費(fèi)性能的操作是:當(dāng) touchmove 觸發(fā)時(shí),計(jì)算出了要移動(dòng)的距離,所有的頁面都需要沿著 Y 軸移動(dòng)相同的距離。此時(shí)必然免不了進(jìn)行 DOM 操作,而 DOM 操作是非常「昂貴」的,再加上 touchmove 事件的頻繁觸發(fā),性能處理不夠好的話,很容易出現(xiàn)卡頓。
為了優(yōu)化性能,我們很自然的想到一個(gè)策略:減少 DOM 操作。
這里面包含兩部分:減少 DOM 操作的元素和減少 DOM 操作的屬性。前者比如,看不到的頁面不參與動(dòng)畫。后者比如,只改變元素的 css 屬性的一個(gè)或幾個(gè)。
減少 DOM 操作的元素
最開始簡易的版本的例子中,touchmove 觸發(fā)時(shí),所有的頁面都沿著 Y 軸移動(dòng)。其實(shí)沒有必要,因?yàn)橄喈?dāng)一部分頁面是看不見的。那一般情況下,我們最少需要操作幾個(gè)頁面呢?答案是兩個(gè)。可以回想一下,我們滑動(dòng)的時(shí)候,最多能同時(shí)看到兩個(gè)頁面。這個(gè)方法相對(duì)于所有的頁面一起移動(dòng),成倍地提升性能。
減少 DOM 操作的屬性
這個(gè)方法的主要意思是,只需要操作一次 DOM 能達(dá)到的效果,絕不用兩次。實(shí)際上,對(duì)于 slide 動(dòng)畫,我們只需要改變頁面的 transform的值,其他的 DOM 操作(增加 class,修改元素的 innerHTML)等能不做就不做。
我們得到了一個(gè)初步的方案:初始化時(shí),所有的頁面一次性全部置入 container,除了我們用到的兩頁,display 屬性都設(shè)置為 none。touchmove 的時(shí)候,只有這兩頁的 transform 屬性有變化。
touchmove 的過程,我們可以寫成數(shù)學(xué)表達(dá)式:
s=f(x),x∈[0,sideLength]
s=f(x),x∈[0,sideLength]
x
x 表示手指滑動(dòng)的距離,s
s 表示頁面滑動(dòng)距離,sideLength
sideLength 是當(dāng)前滑動(dòng)邊的長度,如果是沿 y 軸滑動(dòng),則是頁面高度。寫到這里,就跟時(shí)下很流行的「數(shù)據(jù)驅(qū)動(dòng)」的概念很類似了。我們要實(shí)現(xiàn)的就只有一個(gè) render 函數(shù),輸入是用戶的交互數(shù)據(jù),輸出是頁面表現(xiàn)。
手指離開屏幕后
當(dāng)手指離開屏幕時(shí),我們就已經(jīng)知道了這次滑動(dòng)的結(jié)果(向上還是向下?翻頁還是回彈?),要實(shí)現(xiàn)的只是動(dòng)畫效果,我們有兩個(gè)選擇:
方案一:復(fù)用 touchmove 的 render 邏輯,按照手指滑動(dòng)的速度,使用 requestAnimationFrame 控制動(dòng)畫;
方案二:使用 css3 transition 動(dòng)畫;
方案一的優(yōu)點(diǎn)在于:可以在手指滑動(dòng)和動(dòng)畫過程使用同樣的 render 函數(shù),最大限度復(fù)用了代碼,邏輯統(tǒng)一;同時(shí)可以精確控制動(dòng)畫的每一幀,動(dòng)畫曲線會(huì)比較流暢。 缺點(diǎn)就是可能存在的性能問題。方案二跟方案一剛好相反。其實(shí)說到底還是 js 動(dòng)畫 vs css 動(dòng)畫的問題。
動(dòng)畫性能實(shí)驗(yàn)
為了比較兩個(gè)方案在 H5 翻頁動(dòng)畫上的性能優(yōu)劣,我們?nèi)∫粋€(gè)稍微復(fù)雜點(diǎn)的例子:
H5:百度無人車招聘的 H5
動(dòng)畫:從第 1 頁翻到第 2 頁
CPU: 6 * slowdown
瀏覽器:Chrome 61.0.3163.100(64 位)
js 動(dòng)畫方案:點(diǎn)擊這里
css 動(dòng)畫方案:點(diǎn)擊這里
js 翻頁動(dòng)畫方案,Profile 結(jié)果
css 翻頁動(dòng)畫方案,Profile 結(jié)果
通過實(shí)驗(yàn)我們可以看到,js 的動(dòng)畫過程中,幀率大多維持在 30 fps 上下。而 css 動(dòng)畫,基本都在 60 fps 上下。而且在動(dòng)畫過程中,明顯感覺 js 動(dòng)畫有卡頓。這種情況在一些 CPU 和顯卡配置相對(duì)低的 Android 機(jī)型上尤為明顯。對(duì)于這個(gè)問題有興趣的同學(xué),可以看一下 swiper 庫的 raf 分支,這是本次對(duì)比測試所用到的 js 。
所以,盡管 js 的動(dòng)畫方案看起來比較「優(yōu)雅」,能用「數(shù)據(jù)驅(qū)動(dòng)」的理念,統(tǒng)一解決滑動(dòng)過程和動(dòng)畫過程的問題。實(shí)際上性能有瓶頸,我們只能在手指離開屏幕后,采用 css 的動(dòng)畫方案以保證性能。正應(yīng)了一句話「能用 css 做的,絕對(duì)不要用 js 解決」。
實(shí)施方案
下圖形象地展示了我們實(shí)施的基本思路,只有兩頁:
currentPage :當(dāng)前頁面
activePage:即將要翻到的下一頁
其余的頁面都是初始化的時(shí)候加載進(jìn) DOM 結(jié)構(gòu),但是 display 為 none 并且 z-index 都是 0。這里展示「層疊」的狀態(tài)是為了更形象的展示。
swiper 原理圖
為了方便獲取頁面,我們采用雙向鏈表保存頁面結(jié)構(gòu)。每個(gè) page 具有 prev 和 next 分別指向上一個(gè)和下一個(gè) page。
我們重點(diǎn)要關(guān)注的是,怎么樣確定 activePage ?即下一個(gè)要去到的頁面。答案很簡單,其實(shí),當(dāng)用戶開始觸碰屏幕,并且滑動(dòng)的時(shí)候,就能確定了:
翻頁效果
我們舉的例子中的翻頁效果是最普通的滑動(dòng)效果。怎么樣擴(kuò)展支持立方體、翻轉(zhuǎn)等效果呢?可以回頭看看「手指離開屏幕前」部分,我們提出了 s=f(x)
s=f(x),x
x 是用戶滑動(dòng)距離,s
s 是頁面滑動(dòng)距離。我們把 s
s 擴(kuò)展一下,變成「頁面翻轉(zhuǎn)角度」或「頁面縮放比率」,就可以支持其他的效果了。
事實(shí)上,我們在滑動(dòng)的時(shí)候,本身就是使用 css3 的 transform 屬性,將其中的 translate, rotate, scale 適當(dāng)?shù)慕M合就能做出千變?nèi)f化的翻頁效果了。
更令人愉悅的動(dòng)畫
這里指的是 animation-timing-function,拿最簡單的滑動(dòng)效果舉例。如果是線性的函數(shù),用戶滑動(dòng)的速度始終等于頁面滑動(dòng)速度。而「感覺上」更流暢、更靈敏的應(yīng)該是:剛開始頁面滑動(dòng)速度大于用戶滑動(dòng)速度,隨著翻頁的進(jìn)行,兩者趨于相同,過了某個(gè)點(diǎn)后,單位時(shí)間內(nèi),頁面滑動(dòng)速度開始逐漸小于用戶滑動(dòng)速度,將速度表示為距離,就可以得到 x
x 和 s
s 之間的關(guān)系如下圖:
x
x 和 s
s 的關(guān)系圖(橫軸為 x
x,縱軸為 s
s)
在這里,不得不再提起兩種動(dòng)畫方案: js 動(dòng)畫和 css 動(dòng)畫。
js 動(dòng)畫方案的一個(gè)優(yōu)點(diǎn)是,可以精確控制動(dòng)畫的進(jìn)程,而 css 無法做到。比如用戶在 x = 0.8 的時(shí)候手指離開屏幕,因?yàn)椴捎玫耐粋€(gè) render,js 可以知道手指離開屏幕的瞬間 x 處于 0.8 的位置,接下來的動(dòng)畫由 requestAnimationFrame 完成,整個(gè)過程流暢且完整。
而 css 動(dòng)畫則不同,css 動(dòng)畫只有在動(dòng)畫開始之前設(shè)定 animation-timing-function,當(dāng)用戶在 x = 0.8 手指離開屏幕時(shí),原本的 js 控制滑動(dòng)過程中斷,由 css 來完成剩余的動(dòng)畫,css 無法根據(jù)手指離開屏幕的瞬間動(dòng)態(tài)計(jì)算 animation-timing-function ,所以在銜接的那個(gè)點(diǎn),兩者速度不匹配,會(huì)影響整體動(dòng)畫效果。
但遺憾的是,js 的動(dòng)畫方案有性能問題,我們在用戶手指離開屏幕后的那一部分只能采取 css 動(dòng)畫方案。這個(gè)「更令人愉悅的動(dòng)畫」也只能用在手指滑動(dòng)期間。
本文講述了一個(gè)「絲般順滑」的 H5 翻頁庫的開發(fā)過程中遇到的一些問題和對(duì)應(yīng)的解決方法。基本的滑動(dòng)翻頁模型建立之后,重點(diǎn)關(guān)注了性能的問題,分為手指離開屏幕前和手指離開屏幕后兩個(gè)階段。前一階段主要聚焦于減少 DOM 操作。后一階段聚焦于動(dòng)畫的性能,并且對(duì)比了 js 動(dòng)畫和 css 動(dòng)畫的性能數(shù)據(jù),最后得出了在手指離開屏幕后使用 css 動(dòng)畫的結(jié)論。此外,我們還基于「數(shù)據(jù)驅(qū)動(dòng)」的思想,在翻頁效果和動(dòng)畫函數(shù)兩部分進(jìn)行了擴(kuò)展,增強(qiáng)了翻頁庫的功能,也豐富了 H5 的展現(xiàn)效果。
本文中嘗試用「數(shù)據(jù)驅(qū)動(dòng)」的思想去解釋整個(gè)過程,但是因?yàn)樾阅軉栴}只能暫時(shí)放棄,希望在未來能找到更好的方案。由于水平所限,文中難免會(huì)出現(xiàn)紕漏,歡迎大家批評(píng)指正,共同學(xué)習(xí)進(jìn)步。感謝 Swiper 和 islider 翻頁庫的啟發(fā),特別感謝和 @Ronny 的熱烈討論。
本文所述的 swiper 庫地址:https://github.com/fex-team/swiper。master 分支所用的代碼是目前百度 H5 線上使用的。raf 分支是文中提到的使用 js 動(dòng)畫方案。
點(diǎn)贊+轉(zhuǎn)發(fā),讓更多的人也能看到這篇內(nèi)容(收藏不點(diǎn)贊,都是耍流氓-_-)
關(guān)注 {我},享受文章首發(fā)體驗(yàn)!
每周重點(diǎn)攻克一個(gè)前端技術(shù)難點(diǎn)。更多精彩前端內(nèi)容私信 我 回復(fù)“教程”
原文鏈接:http://fex.baidu.com/blog/2017/10/build-a-silky-smooth-slide-library/
作者:zhangbobell
近 requests 庫的作者,有更新了一個(gè)庫,requests-html for humans ,試用了一下,效果真的很好。
使得開發(fā)者使用的時(shí)候更方便調(diào)用。它依賴于 PyQuery、Requests、lxml 等庫。
不信你也試試,支持Python3 爬蟲工作者有福利了
這個(gè)爬蟲庫支持翻頁功能:
有沒有經(jīng)驗(yàn)到啊。
關(guān)注小編,一起學(xué)習(xí)python吧
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。