- 微信小程序項目開發實戰:用WePY、mpvue、Taro打造高效的小程序
- 張帆
- 4052字
- 2019-09-23 11:07:55
2.3 媒體組件和導航組件
媒體組件和導航組件是微信組件中非常零散的一個部分。尤其是導航組件,可能是從小程序發布以來改動最多的一個組件。
2.3.1 導航組件:navigator
navigator組件存在兩種應用:一種是實現應用內的跳轉;另一種是實現小程序之間的跳轉。對于應用內的跳轉,支持5種跳轉方式,分別對應著API中的5種跳轉方式,如表2-5所示。
表2-5 應用內的跳轉方式

應用之間的跳轉現在也必須要使用navigator組件實現,最新的小程序更新不再支持從任何API直接跳轉至其他小程序。為了防止大量不合規的小程序矩陣,跳轉的任何小程序都必須在app.json中進行全局配置,指定需要跳轉的AppID。而現在,每個小程序可跳轉的目的小程序的數量限制為10個,超過的小程序將會無法通過上傳和審核。
navigator組件的使用方法如下所示。
<navigator url="跳轉地址和參數" open-type="redirect" hover-class="other-navigator-hover" >單擊此處跳轉</navigator >
應用之間的跳轉方法如下所示。
<navigator target="miniProgram" open-type="navigate" app-id="" path="" extra-data="" version="release" >打開綁定的小程序</navigator >
2.3.2 圖片組件:image
顧名思義,image就是為了顯示一張圖片而存在的組件,當然該組件還支持綁定單擊事件。同時,為了方便用戶的使用和適應各種不同橫縱比的圖片,微信為開發者準備了方便的縮放和裁剪模式,通過更改mode的有效值就可以實現。mode的有效值如表2-6所示。
表2-6 mode的有效值

應用中大量使用圖片制作的UI組件,則需要使用image組件顯示在一個頁面中。基于屏幕顯示分辨率的差異,甚至橫縱比例不同,要想在不同的手機端達到類似的顯示效果是一件非常困難的事情。這時有一個思路,就是使用大量重復性的背景或者圖片。
如果一些單頁的場景為了美觀需要大量使用圖片作為UI背景,需要采用<image mode="widthFix"></image>這樣的方式調用圖片。這種調用方式會自動設置圖片的高度。如果以寬度為標準,則需要指定圖片的寬度,這時可以使用相對的百分比或者vw、vh這種相對于屏幕的寬度或者高度。
如果想實現圖2-2這樣的應用效果并在每個手機中都保證其基本的顯示不出現大的變化,則需要拆分頁面,使用相對化布局進行微調。為了不使圖片本身的比例出現問題,應盡量使用mode="widthFix"這個模式。

圖2-2 實例小程序
這里通過一個完整的小程序來使用image組件,也會用到button組件和form組件。該小程序的頁面部分代碼如下所示。
<view class="christmasPage"> <!--用戶的樹--> <view class="christmasTree"> <!-背景--> <image src=" url " mode="widthFix" style="position: absolute;width: 100vw;bottom: 0"></image> <!-標題詞--> <image src=" url " mode="widthFix" style="position: absolute;top:13vw;width: 80vw;left: 10vw"></image> <!-圣誕樹--> <image src="url" mode="widthFix" style="position: absolute;bottom: 2vw;width: 100vw"></image> </view> </view>
注意:在同樣的在image組件上也可以綁定事件,即單擊圖片時觸發單擊事件。
雖然在image組件上也可以綁定事件,但在一般情況下,用戶單擊image組件時雖然會觸發事件,但該事件并不會觸發攜帶一個用戶的formId。這時需要將圖片和按鈕結合在一起使用,參考下面的image頁面。
image頁面中的一張圖的外部嵌套了一個按鈕組件,但如果直接嵌套在image組件的外部,如以下代碼所示,則整個頁面布局會因為按鈕組件自帶的樣式而發生錯亂,如圖2-3所示。

圖2-3 顯示問題
<button> <image src="../public/testImg.png" mode="widthFix" style="width: 80%"></image> </button>
如圖2-3所示,該按鈕的寬度依舊是100%,其本身的邊框依舊存在,甚至還留下了一些padding造成的間距。所以,應該對這類按鈕組件進行樣式的覆蓋,并加上button組件外部嵌套的form組件,這樣單擊圖片按鈕時,就可以在執行事件時收獲一個用戶的formId。
對小程序而言,微信開發時獲得的幾乎所有的開放能力,包括用戶的數據,都必須要由用戶完成一個單擊事件,因此我們同時在這個按鈕上加上open-type屬性。也就是說,當用戶單擊一個圖片時,實際上觸發了按鈕組件上3個事件,而在實例中這3個事件會在控制臺中打印。
本實例頁面和樣式部分的代碼如下所示,其中樣式common_img_btn和button[class^="common"]::after是去除按鈕本身樣式的自定義樣式。
<style lang="less"> .common_img_btn { border: none !important; padding: 0 !important; background-color: rgba(0,0,0,0)!important; } button[class^="common"]::after { border: 0; } .pageButton { position: fixed; width: 60vw; top: 0; left: 20vw; } </style> <template> <form bindsubmit="formSubmit" report-submit="true"> <!--綁定按鈕上的3個事件--> <button class="common_img_btn pageButton" @tap="someFun()" formType="submit" open-type="getUserInfo" bindgetuserinfo="onGotUserInfo"> <image src="../public/testImg.png" mode="widthFix" style="width: 100%"></image> </button> </form> <!--<button>--> <!--<image src="../public/testImg.png" mode="widthFix"--> <!--style="width: 80%"></image>--> <!--</button>--> </template>
頁面的監聽函數寫在了methods對象中,完整的代碼如下所示,分別是在控制臺中打印和按鈕的原本監聽方法的彈窗。
methods = { someFun(){ wepy.showModal({ title: '提示', content: '用戶單擊圖片事件' }) }, onGotUserInfo(e){ console.log(e.detail) }, formSubmit(e){ console.log(e.detail.formId) } }
本例最終效果如圖2-4所示,當單擊事件觸發時會提示用戶獲取資料的權限。這個彈窗在現在的所有微信小程序中是不能避免的,而用戶選擇后在一段時間內都不會再次出現。

圖2-4 權限獲取提示
當用戶單擊“允許”按鈕后,可以在控制臺打印出formId并且彈出原本綁定按鈕中的彈出框,如圖2-5所示。

圖2-5 打印用戶資料和formId
2.3.3 視頻組件:video和API:wx.createVideoContext
視頻類的應用在之前的小程序中并不多見,但這幾年短視頻和直播類應用普遍火熱,使用小程序制作的視頻類應用也越來越多了,小程序中video組件正好為我們提供了這個功能。
video組件是一個原生組件,也就是說,video組件并不能覆蓋cover-*以外的其他組件。當然,一般使用video組件時也不會在其上覆蓋其他組件。video組件不僅為我們提供了視頻播放的功能,還提供了包括彈幕、全屏、進度控制等功能,這些功能只需要簡單配置即可。video組件的屬性如表2-7所示。
表2-7 video組件的屬性

除了上述屬性,video還包括了多個綁定事件,可以說video組件是所有組件中屬性和內容最多的一個組件。支持的綁定事件包括:
● Bindplay:當開始/繼續播放時觸發play事件。
● Bindpause:當暫停播放時觸發pause事件。
● Bindended:當播放到末尾時觸發ended事件。
● Bindtimeupdate:播放進度變化時觸發,event.detail = {currentTime,duration}。觸發頻率為250ms一次。
● Bindfullscreenchange:視頻進入和退出全屏時觸發,event.detail = {fullScreen,direction},direction取vertical或horizontal。
● Bindwaiting:視頻出現緩沖時觸發。
● Binderror:視頻播放出錯時觸發。
● Bindprogress:加載進度變化時觸發,只支持一段加載。event.detail = {buffered},百分比。
video除了視頻播放功能,本身的可用性和難度并不高,只需要配置src就可以實現視頻的播放和控制了。服務器端的video視頻內容會導致自身服務器大量帶寬被占用,出現播放卡頓等,所以推薦使用騰訊云文件方式進行播放。
注意:<video>默認寬度為300px、高度為225px,可通過wxss設置寬度和高度。
在video組件的使用中,不僅用戶可以在界面上進行基本的操作,開發者通過JavaScript腳本也可以實現對視頻的控制和操作,但這需要使用專門為video提供的一個API—wx.createVideoContext(string id,Object this)。其中的id為video組件的id,Object表示如果在自定義組件中使用該元素,需要指定其實例的this。
這個API會返回一個JavaScript對象VideoContext,它包含了一些視頻的控制方法,如表2-8所示。
表2-8 VideoContext包含的視頻控制方法

2.3.4 拍照組件:camera和API:wx.createCameraContext
使用拍照組件會調用系統的相機操作,調用camera組件時會在界面上顯示相機的拍照界面。
camera組件是系統原生組件,會懸浮在一般組件的最上層。在微信客戶端達到了6.7.3之后可以使用掃二維碼的功能,但是使用該組件會默認要求用戶的授權,如果用戶不允許則不會出現該組件。
注意:camera組件在隱藏時設置成hidden或者display:none,或者使用fixed定位將整個組件移出屏幕,在部分手機或者系統中可能會出現無法隱藏的情況,而官方暫時沒有給出解決方案,可以使用跳轉頁面的方式進行拍照。
一般而言,camera組件用于需要拍照的業務,如果只是處理圖片或從用戶相冊中選擇照片的應用場景,并不推薦使用camera組件,而是直接使用wx.chooseImage(Object object)這個API,直接使用系統的相冊和相機來選擇照片或拍照。
使用camera組件也可以實現拍照和攝像功能,下面在2.3.2節的小程序中添加camera頁面。
頁面代碼如下所示,這里除camera組件以外,還在相機上覆蓋了一個基礎的cover-view組件,用來繪制一個方形的框,這使得用戶的頭像可以根據我們的意愿出現在該方形區域中。當然,camera組件并不能直接截取或僅獲取該區域的圖像,截取工作需要在后端或者小程序中調用Canvas組件截取。
<template> <view style="position: fixed;width:100vw;"> <!-添加相機組件--> <camera device-position="front" flash="off" binderror="error" style="width: 100vw; height: 100vh;"> <!—覆蓋在相機組件上的組件--> <cover-view class="controls"> <cover-view class="coverImg"> </cover-view> <cover-view style="bottom: 20vh;text-align:center;position: fixed;color: #fff;font-size: 28rpx;width: 100vw"> 您框內的圖片將會作為您的抽獎頭像 </cover-view> <!-拍照事件的監聽按鈕--> <button @tap="takePic" class="input" style="bottom:10vh;color: #000">單擊 拍照</button> </cover-view> </camera> </view> </template>
上述代碼實現了一個全屏幕的相機(配置使用了前置攝像頭并且不使用閃光燈的效果),并且在相機上繪制了一個方形的框、一行提示文字,以及一個拍照的按鈕,此按鈕已經綁定了takePic方法用于獲取照片。頁面的基本樣式代碼如下所示。
<style lang="less"> .controls { width: 100vw; height: 100vh; } .coverImg { position: fixed; left: 1vw; top: 25vh; width: 96vw; height: 96vw; border: 1vw solid #fff7cc; } .input { position: fixed; width: 60vw; left: 20vw; border-radius: 5vw; height: 10vw; text-align: center; color: #fff; font-size: unit(28,rpx); } </style>
下面要做的就應該是對用戶拍照事件的監聽和使用Camera組件獲取照片了。這里采用存儲在緩存文件的形式,也可以僅獲取臨時地址,或者在拍照結束后直接將圖片上傳到服務器端。
這里介紹一個新的API方法wx.createCameraContext,用于獲取一個相機的實例,從而實現拍照功能。該實例擁有3個方法:CameraContext.takePhoto用于拍攝照片,CameraContext.startRecord和CameraContext.stopRecord用于開始和結束錄像。在CameraContext.takePhoto方法中應用success回調可以獲得拍攝照片的臨時地址,而使用CameraContext.stopRecord可以獲得拍攝視頻的臨時文件地址。這里簡單地采用了CameraContext.takePhoto這個API方法來拍攝照片,其使用效果和方法如以下邏輯代碼所示。
<script> import wepy from 'wepy' // 頁面代碼 export default class camera extends wepy.page { components = {} // 頁面數據內容 data = { imgPath: '', imgWidth: 0, imgHeight: 0 } computed = {} // 頁面監聽方法 methods = { takePic(){ const that = this const ctx = wx.createCameraContext() wx.showLoading() // 拍照API的使用 ctx.takePhoto({ // quality: 'high', success:(res)=> { that.imgPath = res.tempImagePath that.$apply() wx.getImageInfo({ src: that.imgPath, success:(res)=> { that.imgWidth = res.width that.imgHeight = res.height wx.saveFile({ tempFilePath: that.imgPath, success(res){ wepy.setStorageSync('userImg',{ path: res.savedFilePath, width: that.imgWidth, height: that.imgHeight }) setTimeout(()=> { wx.hideLoading() wepy.reLaunch({ url: '跳轉回的路徑' }) },2000) } }) // wepy.setStorageSync('userImg', {path: that.imgPath, width: that.imgWidth,height: that.imgHeight}) } }) }, fail(res){ // 失敗時的打印 console.log('takePhoto fail res') console.log(res) }, complete(res){ // 最終打印結果 console.log('takePhoto complete res') console.log(res) } } ) }, error(e){ console.log(e.detail) } } events = {} onLoad(){ } } </script>
wx.createCameraContext獲得一個基礎的Camera的實例,而后調用其takePhoto方法獲得用戶拍攝的照片。這里選擇將文件保存后,獲取其路徑和使用wx.getImageInfo這個API方法獲得該照片的高度和寬度信息并且保存。
頁面的調試不一定非要在首頁或者底部增加一個跳轉至該頁面的鏈接,只需要新建一個編譯模式即可,如圖2-6所示。

圖2-6 新增編譯模式
編譯模式需要選擇啟動頁面的地址、攜帶的參數、如何進入場景(用于確定模擬觸發當前的頁面狀態是重新加載,還是從隱藏到顯示)。通過該編譯模式即可調試任何頁面及頁面攜帶的參數,也可以測試二維碼和小程序碼,顯示效果如圖2-7所示。

圖2-7 camera頁面顯示效果
注意:由于模擬器的限制,在沒有選擇專門的設備時都會顯示如圖2-7所示的效果。在這里可以選真機測試,在手機上運行,如果用戶阻止了該組件,則會出現空白頁面。