1
本文作者: 張丹 | 2017-01-13 16:12 | 專題:雷峰網(wǎng)公開課 |
1月9日,微信小程序正式上線,互聯(lián)網(wǎng)迎來了一次狂歡。
張小龍?jiān)谏蟼€(gè)月的公開演講中表示,“小程序是一種比現(xiàn)有所有 App 更加靈活,更加唾手可得的一種形態(tài),并將無處不在。”作為微信的一種新形態(tài),小程序不僅擴(kuò)大了微信的生態(tài),也被看作是移動(dòng)互聯(lián)網(wǎng)的“革命者”。
任何文字解析都不如視頻直播直觀。
本次硬創(chuàng)公開課雷鋒網(wǎng)請到了「開眼」視頻的技術(shù)負(fù)責(zé)人為大家直播演示講解如何開發(fā)一款視頻微信小程序?!搁_眼」視頻是一款短視頻日報(bào)應(yīng)用。由「開眼」視頻團(tuán)隊(duì)制作微信小程序「開眼Eyepetizer」,作為為數(shù)不多的第一批上線的視頻類小程序,受到了許多開發(fā)者的關(guān)注。
嘉賓介紹:
楊凱,「開眼」視頻團(tuán)隊(duì)技術(shù)負(fù)責(zé)人。
曾供職于 360,是 360 手機(jī)桌面創(chuàng)始團(tuán)隊(duì)成員之一,由他參與研發(fā)的該款桌面在國內(nèi)第三方桌面市場很長時(shí)間排名第一。2014 年加入豌豆莢,任豌豆莢 Tech Lead,負(fù)責(zé)豌豆莢主程序開發(fā),主要參與網(wǎng)絡(luò)庫優(yōu)化,UI 性能調(diào)優(yōu),通過代理緩存多媒體 web 頁等工作。后加入「開眼」視頻團(tuán)隊(duì),作為技術(shù)負(fù)責(zé)人,負(fù)責(zé)技術(shù)開發(fā)、迭代工作。
下文為雷鋒網(wǎng)整理的本次公開課直播分享中的要點(diǎn)。課后陳凱老師還分享了本次課程中完成的 demo,關(guān)注雷鋒網(wǎng)「唯物 」公眾號(hào)(ID:okweiwu),回復(fù)「 小程序」即可獲取鏈接。
今天主要講一下微信小程序的開發(fā),希望通過直播開發(fā)一個(gè)「開眼」視頻的小程序,幫大家了解微信小程序的開發(fā)步驟、流程以及基本 API 的使用,內(nèi)容主要包括以下幾個(gè)方面:
開發(fā)一個(gè)可滾動(dòng)列表,在這個(gè)列表的制作中,我們會(huì)熟悉微信小程序數(shù)據(jù)綁定的方法,以及怎么樣發(fā)起一個(gè)網(wǎng)絡(luò)請求;
處理點(diǎn)擊事件,通過這一操作了解微信是怎樣做事件綁定的;
在列表的指定位置,展現(xiàn)一個(gè)視頻播放器,通過這一操作了解微信小程序給我們的視頻標(biāo)簽是怎樣使用的;
將頁面分享給好友,在好友對話里可以看到制作的微信小程序。
大家可以看到「開眼」視頻小程序就是一個(gè)簡單的列表,列表中的每一個(gè)畫面其實(shí)都是一個(gè)可以點(diǎn)開播放的視頻。進(jìn)一步分析可以得知,在我們看到的每一個(gè)視頻封面圖上有一個(gè) icon,圖下面是這個(gè)視頻的文字介紹,標(biāo)題以及分類。繼續(xù)向下拉會(huì)發(fā)現(xiàn),有多少視頻,就會(huì)顯示多個(gè)元素,并且是刷新不到頭的。當(dāng)我們點(diǎn)擊一個(gè)視頻封面或播放按鈕 icon 時(shí),視頻會(huì)開始播放,接著點(diǎn)擊播放第二視頻時(shí),第一個(gè)視頻就會(huì)自動(dòng)停止播放,以上就是我們這堂課想要完成的事情。
|步驟一:開發(fā)一個(gè)可滾動(dòng)列表
由于時(shí)間關(guān)系,本次直播不會(huì)從零開始做這款小程序,會(huì)直接從微信的 demo (小程序組件)中開始操作。
這是微信小程序官方給出的一個(gè) demo,可以看到有兩個(gè) tab,今天的操作主要是在第二個(gè) tab 的右邊再添加一個(gè) tab,在第三個(gè) tab 中實(shí)現(xiàn)一個(gè)跟「開眼」視頻小程序一樣的功能。
可以看到 pages 列表內(nèi)容非常多,其內(nèi)容主要是定義或聲明一下在這個(gè)小程序中會(huì)用到一些界面。windows 花括號(hào)里面的一些選項(xiàng)是幫你定義 tool bar 上的顏色和信息,可以在這個(gè)頁面看到demo 中 toolbar 的顏色就在這里設(shè)置的。
在 tab bar 里新加一個(gè)“開眼視頻”文件夾,配置地址是剛剛寫好的,抄過來就好,配制完成可以看到左邊的頁面已經(jīng)出來了,雖然沒有內(nèi)容,但第三個(gè) tab 的框架已經(jīng)完成了。接下來是繼續(xù)開發(fā)這個(gè) tab,我一般會(huì)直接從之前寫好的代碼里復(fù)制過來,然后進(jìn)行一些簡單的修改,演示一下變化過程。
注意要把相關(guān)文件名也改成“開眼視頻”,否則會(huì)出現(xiàn)找不到布局文件的情況發(fā)生。
文件夾名稱改完后,可以看到剛在第三個(gè) tab 里添加的內(nèi)容,已經(jīng)可以顯示出來了,這是一個(gè)微信小程序官方 audio 的頁面,還需要對這個(gè)頁面進(jìn)行一些改動(dòng)。
首先寫一下這個(gè)頁面的布局文件,把沒有用的布局文件刪掉,在最上層定義一個(gè) view,進(jìn)行最外層的展示,然后會(huì)加一個(gè) image 標(biāo)簽,這個(gè)標(biāo)簽主要的功能是展示剛才看到的 cover 圖(由于時(shí)間關(guān)系,直播時(shí)省略了敲代碼步驟,直接從之前的文件中拷貝)。
解釋一下拷過來的這幾行代碼。第一代碼是 WX : for,前面 WX 是微信的簡稱,后面的 for 是說,它會(huì)在你的 JS 文件里找到一個(gè)名字叫 videos 的變量,該變量是一個(gè)數(shù)組,image 這個(gè)便簽會(huì)重復(fù)多次,直到和 videos 數(shù)組長度一致。
后面 for-item 標(biāo)簽是指,每一個(gè) image 標(biāo)簽可以通過 video 變量名拿到和它綁定在一起的視頻數(shù)據(jù),例如下面 video.coverForFeed 就是把當(dāng)前綁定的視頻數(shù)據(jù)中 coverForFeed 字段賦值給 image 的 src。
接下來看下 GS 的寫法,先定義一個(gè) videos,也就是剛剛在布局文件里聲明需要的,這個(gè) videos 會(huì)在 onload 里賦值。解釋一下 onload 這個(gè)方法:頁面被加載的時(shí)候,onload 會(huì)被調(diào)用。在微信小程序官方開發(fā)文檔中也可以看到這個(gè)方法的相關(guān)聲明,其中:
onload 是頁面被加載;
onready 是第一次渲染完畢;
onshow 是監(jiān)聽事件顯示;
onhide 是監(jiān)聽頁面被隱藏。
如果有前端開發(fā)經(jīng)驗(yàn)的話,可以看到跟 window 的很多頁面很像.最常用的是 onload,再仔細(xì)看一下這個(gè)方法的使用,在這個(gè)地方會(huì)嘗試調(diào)用一個(gè)叫 load 的方法,并且把“我們自己”傳進(jìn)去,再傳一個(gè)options。解釋一下 options,舉個(gè)簡單的例子,如果想調(diào)一個(gè)這樣的配置,可以看到它的 url=page/item/item,后面會(huì)帶一個(gè)參數(shù),參數(shù)名叫 id 值等于 1,這個(gè)方法是在調(diào)用者那邊使用的,被調(diào)用者也就是被喚起的頁面怎么樣讀到這個(gè) id 等于 1 的參數(shù)呢?是通過 const id = options.id 這個(gè)代碼,options 相當(dāng)于頁面間傳遞參數(shù)傳遞的一個(gè)工具。
再看下 load 的方法,一行一行的來看,第一行 pages 和 options 是兩個(gè)傳參,第二行 wx.ewqiest 是發(fā)送一個(gè) API 請求,注意,小程序官方文檔里的對 wx.ewqiest 的定義是發(fā)送一個(gè) HTTPS 請求,現(xiàn)在是本地操作,如果是線上環(huán)境的話,一定要寫成 HTTPS,否則會(huì)被攔截。完整示例寫法如下:
url 是請求的地址;
data 是 url 里的參數(shù),也就是我們傳進(jìn)去的參數(shù);
header 是我們發(fā)送 HTTPS 請求的時(shí)候所帶的 header;
success 當(dāng)發(fā)送成功時(shí),這個(gè)方法會(huì)被回掉;
fail 當(dāng)請求失敗時(shí),會(huì)回調(diào)這個(gè)方法,通知你失敗的原因。
再回到開發(fā)頁面,video:videoData 是說把本地變量變?yōu)榕渲玫膮?shù),要注意的是微信小程序和 Vue 不同,小程序的數(shù)據(jù)不是雙向綁定的,或者說不是默認(rèn)雙向綁定的,如果數(shù)據(jù)或數(shù)據(jù)結(jié)構(gòu)發(fā)生了改變,想通知到 video 層級(jí)上,讓 video 去刷新,必須要通過 page 中的 setdata 來實(shí)現(xiàn)。也就是說必須要這樣寫, videos 才會(huì)生效(video=videoData 的形式不不會(huì)生效)。
現(xiàn)在已經(jīng)把簡單的列表寫好了,回到微信小程序的開發(fā)列表里可以看到,已經(jīng)顯示出了我們想要的效果,我們請求到了 6 個(gè)視頻,界面上顯示了六個(gè) cover 圖。微信會(huì)對 image 標(biāo)簽有默認(rèn)的高和寬(240*320 像素),所以需要對圖片進(jìn)行微調(diào)。
接著寫 css,微信的 css 語法和標(biāo)準(zhǔn)的 css 語法幾乎沒有區(qū)別,只是有一些子集不支持,這些在微信的開發(fā)文檔里也有寫,但是我們一般用到的都有。需要額外講下 rpx,這是微信小程序里自己定義的一個(gè)屬性。這個(gè)屬性的定義是說它認(rèn)為所有屏幕的寬都是 750 個(gè) rps,也就是說,你拿到一臺(tái) iphone 5 和一臺(tái) iphone 6S,它的寬都是750 rpx。
但是會(huì)反過來算一個(gè)像素等于多少 rpx,在 iphone5 里,假如說一個(gè)像素等于一個(gè) rpx的話,在 iphone 6 里,兩個(gè)像素等于一個(gè) rpx。這樣做的好處是降低了 UI 的適配成本。
到這里本堂課的第一個(gè)目標(biāo)已經(jīng)完成,已經(jīng)開發(fā)完成了一個(gè)可滾動(dòng)的列表,并熟悉了數(shù)據(jù)綁定和網(wǎng)絡(luò)請求。
|步驟二:處理點(diǎn)擊事件
接下來要處理一個(gè)點(diǎn)擊事件,點(diǎn)擊事件觸發(fā)之后,會(huì)在圖片原來的位置展示一個(gè)視頻播放器,并且播放圖片所代表的視頻。
先看一下微信小程序定義的的事件綁定過程是怎樣的:
在組件中綁定一個(gè)事件處理函數(shù),如 bindtap,這個(gè)用戶在點(diǎn)擊組件的時(shí)候,就會(huì)出發(fā)到這個(gè) video 的 bindtap。
高亮的這幾行意思是我把一個(gè)函數(shù) tapname 綁在 video 標(biāo)簽的點(diǎn)擊上。也就是說當(dāng)前這個(gè) video 標(biāo)簽被點(diǎn)擊時(shí),系統(tǒng)會(huì)調(diào)用名字為 tapname 的方法,并且把當(dāng)前 video 的一些參數(shù)傳到這個(gè) tapname 函數(shù)里。
接下來在項(xiàng)目里定義一個(gè)綁定,把 image 的點(diǎn)擊事件綁定在一個(gè) onTap 的方法上。接下來要在 JS 里實(shí)現(xiàn)這個(gè) onTap 的方法。
在 JS 里 onload 下面,重起一行接著寫 onTap:function (element),微信小程序官方文檔中對 element 的定義中包涵了幾個(gè)屬性:
type (事件類型);
timeStamp(事件生成時(shí)的時(shí)間戳)
target(觸發(fā)事件組件的一些屬性值結(jié)合)
currentTarget(當(dāng)前時(shí)間的一些屬性值集合)
接下來要實(shí)現(xiàn)一個(gè)方法叫 tap,它需要兩個(gè)傳參,第一個(gè)是 page,第二個(gè)是 element。page 就是 this,element 就是剛剛定義的 element,傳進(jìn)來后可以看到這個(gè)方法就被調(diào)用了。打一個(gè) log 可以看到以下結(jié)果。
每點(diǎn)一次,下面都會(huì)出現(xiàn)一個(gè) tap,也就是說已經(jīng)成功的把 video 上的事件傳遞到了 JS 的處理函數(shù)中。
第一段代碼中的 element 就是剛剛傳過來的被點(diǎn)擊元素,currenttarget 是當(dāng)前被點(diǎn)擊的目標(biāo)… 重點(diǎn)講下videoUrl,videoUrl 是剛在開發(fā)中定義的一個(gè)內(nèi)容,不是系統(tǒng)自帶的,看下它是從哪里來的
data-video-id 的意思是把當(dāng)前視頻 id 附給 image 標(biāo)簽,作為這個(gè) image 標(biāo)簽上的屬性,當(dāng)點(diǎn)擊一個(gè) image 標(biāo)簽是,JS 可以從傳入的 element 中讀到這個(gè)值。
因?yàn)榱斜砝镉?6 個(gè)標(biāo)簽,所以必須要知道當(dāng)前點(diǎn)擊的標(biāo)簽是什么,以及當(dāng)前被點(diǎn)擊的標(biāo)簽上綁定的 video 數(shù)據(jù),來決定后面需要播哪一個(gè)視頻。
id 我們用不到,先刪去。上面的寫法是 -video-url 這個(gè)地方寫成 videoUrl 略有不同。原因是微信小程序會(huì)幫開發(fā)者們做一件事情,把 data 和后面的橫線去掉,然后自動(dòng)駝峰。
上面這句話的意思是從被點(diǎn)擊的 element 中拿到當(dāng)前標(biāo)簽綁定的 video 的播放 url 是什么??赡芎芏嘧銮岸说耐瑢W(xué)心里會(huì)有疑問,為什么要費(fèi)這么大勁去拿,而不通過一些其它的手段。因?yàn)槲⑿判〕绦驈U除了 document,以及 window 的很多方法,目的是讓小程序變成純數(shù)據(jù)驅(qū)動(dòng)的編程思想,也就是說所有的事件和所有的數(shù)據(jù),一定是以事件或者是消息這樣的方式來傳遞的,開發(fā)者沒有辦法主動(dòng)的去拿到當(dāng)前顯示的 video。
舉一個(gè)簡單的例子,如果在頁面加載完后,設(shè)一個(gè) timer 定時(shí)器,每五秒中告知當(dāng)前列表中展示的第一個(gè)元素是什么,這個(gè)在小程序里做不到。因?yàn)闆]有辦法主動(dòng)拿到當(dāng)前列表這個(gè)元素,也就沒辦法拿到列表上展示的內(nèi)容,只有一種辦法,用戶手動(dòng)觸發(fā)了一個(gè)事件時(shí),開發(fā)者才可能拿到這個(gè)事件相關(guān)的(并不是所有的)一些信息。
為了取到當(dāng)前被點(diǎn)擊的這個(gè) item 上面綁定的 video 的播放地址,要通過這種方式來實(shí)現(xiàn),而不能通過其它的方式來實(shí)現(xiàn),這個(gè)確實(shí)有點(diǎn)繞。
這個(gè)思想在微信小程序里可以說是最重要的思想,也就是 DOM 模型幾乎完全不能用。這個(gè)可能給很多前端開發(fā)帶來非常大的困擾。
|步驟三:在列表指定位置展示視頻播放器
接著來看一下,現(xiàn)在還要做另外一件事,要在界面里加一個(gè) video 標(biāo)簽,id 叫 video,class 叫 video,這樣寫主要是為了一會(huì)兒 CSS 綁定用。
后面它的 style 寫法,第一是 display,為什么用這個(gè)屬性,據(jù)我個(gè)人的經(jīng)驗(yàn),在微信里如果想隱藏一個(gè) video 標(biāo)簽,只有這一種方法可以隱藏,也就是說 display 屬性設(shè)成 none,才可以把 video 隱藏,visibility hidden 方式都不行。
top 就是說這個(gè)視頻標(biāo)簽在列表中距離頂端的位置,所有帶兩層大括號(hào)的東西都是引用到 JS 里的變量,兩個(gè)變量一個(gè)是 covertop,一個(gè)是 videoDisply,src 是 currentUrL,就是說 video 播放地址是什么,這也是第三個(gè)變量。
對上面三個(gè)變量做個(gè)定義:
videoDisplay 是 none,默認(rèn)隱藏 video 標(biāo)簽;
covertop 是 video 標(biāo)簽?zāi)J(rèn)頂部,隱藏在那里都可以;
currentUrl 開始時(shí)為空,也就是說在開始時(shí),視頻播放器里是沒有地址的。
再來看一下 tap 事件,直接復(fù)制過來三行。前面 page.setdata 是給下面的 data 進(jìn)行一種更新,這是一種特殊的復(fù)制方法。offsettop 這個(gè)屬性會(huì)告訴你當(dāng)前被點(diǎn)擊的元素,相對它的父節(jié)點(diǎn)向下挪了多少位置 。currentUrl,就是剛才拿到的 url。后面的 videodisply:block,是指現(xiàn)在可以顯示出視頻元素了。
試一下,頁面刷新了,說明更改生效了。可以看到視頻播放器已經(jīng)出現(xiàn)了,而且進(jìn)度條已經(jīng)顯示出時(shí)間了,但是還沒有開始播。下一步想辦法讓它開始播放。
先看一下微信小程序的的定義:
微信定義一個(gè)方法叫 creatVideoContext,意思是說在傳入一個(gè) videoid 時(shí),它會(huì)把當(dāng)前 videoid 的 video 元素與系統(tǒng)的播放器進(jìn)行綁定,也就是完成這個(gè)操作后的你添加的這個(gè)元素就可以播了。
微信官方共提供了play、pause、seek、sendDanmu 四種方法。
看下代碼,可以看到 creatVideoContext,傳入的參數(shù)叫video,就是剛才說布局文件里定義的一個(gè) id 等于 video。
可以發(fā)現(xiàn)視頻已經(jīng)開始播了,劃動(dòng)一下列表,視頻跟著這個(gè)列表在走,第二個(gè)視頻顯示出來后,并沒有播放。
這是我自己發(fā)現(xiàn)的微信小程序里 bug,點(diǎn)擊第二個(gè)視頻時(shí)不能自動(dòng)播放,手動(dòng)點(diǎn)控制條的時(shí)候有可能觸發(fā)播放,這是小程序系統(tǒng)的 bug。但有方法可以繞過:在原來的方法上加兩句話,就是設(shè)一個(gè) timeout,也就是將這個(gè)事件延遲一段時(shí)間再出發(fā),點(diǎn)擊事件結(jié)束之后 500 毫秒再去觸發(fā)視頻的播放。
微信官方推薦用自帶的 IDE 來做開發(fā)。但是我平時(shí)還會(huì)做其它平臺(tái)的開發(fā),所以會(huì)比較傾向統(tǒng)一用 intellij,寫好代碼后只在微信小程序里做調(diào)試。繞過 bug 后可以看到滑視頻隨著列表滾動(dòng)可以自動(dòng)播放了。這樣我們基本上完成第二個(gè)目標(biāo),在列表中播放視頻,而且在滾動(dòng)列表時(shí)只有一個(gè)視頻在播放。
|步驟四:將頁面分享給好友
在微信小程序官方文檔的最后,可以看到有一個(gè)關(guān)于 onShareAppMessage 的說明,意思是如果你在頁面里定義了這個(gè)函數(shù),這個(gè)函數(shù)叫 onShareAppMessage,右上角會(huì)出現(xiàn)分享按鈕。
可以看到,不定義這個(gè)函數(shù)時(shí),點(diǎn)擊右上角會(huì)出現(xiàn)“當(dāng)前頁面未設(shè)置分享”的提示。
接下來寫這個(gè)代碼,直接把官方文檔抄過來即可,要注意,設(shè)置頁面元素時(shí),一定要在 page 后的括號(hào)中寫,也就是說,一定要在 page 頁面里設(shè)置有關(guān)這個(gè)頁面的系統(tǒng)回調(diào)。保存后回到 IDE,點(diǎn)擊右上角,會(huì)出現(xiàn)分享按鈕,可以自定義分享標(biāo)題與自定義分享描述。
看一下代碼也是這么寫的:自定義標(biāo)題、自定義描述、自定義 path。自定義 path 是最外層還有一個(gè) APP.gaisen,里面定義了所有的頁面地址,把頁面地址可以寫過來后我們今天的任務(wù)就完成了。
雷峰網(wǎng)原創(chuàng)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。