第一次接觸小程序大概是17年初,當時小程序剛剛內(nèi)側,當時就被各種限制折騰的死去活來的,單向綁定, 沒有promise,請求數(shù)限制,包大小限制,各種反人類,...反正我是感受到了滿滿的惡意. 最近接到一個工程類的小程序項目,做技術選型的時候,又把以前的東西撿起來看了看,重新熟悉了一下, 感覺小程序還是有在努力的,支持大部分es6語法了,還出了一個類Vue的mvvm框架wepy,還支持redux狀態(tài)管理, 就大致建了個demo,跑了起來,趕緊雖然沒有vue那么酸爽,但是還是挺ok的,至少比原生的小程序語法親民很多. 然后就開始用wepy搭項目,寫靜態(tài)頁面(由于公司的開發(fā)模式是先寫靜態(tài)頁面, 等待后端的同學接口出來了再綁定數(shù)據(jù)),雖然wepy用起來比原生的順手, 但是還是有很多坑的,這里就不列舉了..... 就在我們靜態(tài)頁面快寫完的時候,某天晚上論壇的時候看到一條消息, 美團出了個小程序框架mpVue (不知道為什么,每次看到這個名字,我只想到3個字,沒朋友,哈哈), 大致看了一下官方的介紹,主要有一下亮點:
也就是說,不但可以用我們熟悉的vue語法開發(fā),還有可能直接把你的h5頁面編譯成小程序. 該項目到目前位置,開源不到20天,已經(jīng)收到將近7000個star,可見天下苦秦已久。 建了個demo,跑了一下,感覺簡直就是開發(fā)界的良心之作啊.順便把之前寫的wepy的靜態(tài)頁面代碼復制過來看了一下, 發(fā)現(xiàn)只要改動一點點,就可以順利從wepy切換到mpvue上來(整個項目的切換時間在半天左右). 說做就做,當天就切到mpvue.一直到現(xiàn)在項目接近尾聲了,整個開發(fā)過程,真是令人愉悅. Bug....我今天好像不是來給mpvue做廣告的,我是來找茬的.. 下面就盤點一下我最近用mpvue開發(fā),遇到的一些需要需要注意的細節(jié).(或者說跟vue不同的地方) 一,這個個人感覺是最大的坑,除了缺少文件會報錯外,其他的代碼語法錯誤等, 控制臺大部分時間都是安靜的(偶爾也會報一個xxx is undefined) 比較經(jīng)常碰到的是這樣 this.xxx =5 有些情況下會報錯,而有些情況下則沒有任何反應, 具體什么情況下會,什么情況下不會,我現(xiàn)在還沒摸出規(guī)律來.. 有一次我把 this.dataObject.map(() => { ...這里省略... }) 結果map前面的 . 不小心給露掉了,實際代碼變成 this.dataObjectmap(() => { ...這里省略... }) 結果找了半天沒找到問題的原因 二,這個也是比較難受的地方,就是模板的數(shù)據(jù)綁定里面,沒辦法在模板語法里面調(diào)用methods方法 (或者說沒辦法調(diào)用computed以外的函數(shù)),有人也許會說,那可以用computed屬性,那如果我想給函數(shù)傳參怎么辦? 看下面代碼: <template> <view v-for="item in costList" > {{formatCost(item)}} </view> </template> <script> export default { data(){ return{ costList:[] } }, methods: { formatCost(item){ return item.toFixed(2) }, getData(){ let arr = [3.255,4.1,5,15] this.costList = arr } } </script> 這個時候 {{formatCost(item)}} 里面的內(nèi)容,會渲染成空字符串,理由就是因為不支持函數(shù),而且這中情況, 也無法使用computed屬性,除非你想為每個數(shù)組元素寫一個computed 這種情況,我的解決方案是在在獲取到數(shù)據(jù)的時候,就先把數(shù)據(jù)改了.如上面的例子,我們可以在 getData方法里面這樣寫 let arr = [3.255,4.1,5,15] // 遍歷數(shù)組里面的元素,然后格式化一下,添加到 costList里去 arr.map(item => { this.costList.push = this.formatCost(item) }) 三,所有頁面里面的created生命周期函數(shù) 都會在小程序加載的時候, 一次性執(zhí)行,而不是每進入一個頁面執(zhí)行一次,如,我有3個頁面 pageA ...省略一些代碼... creatted(){ console.log('pageA 的 created函數(shù)執(zhí)行') } pageB ...省略一些代碼... creatted(){ console.log('pageB 的 created函數(shù)執(zhí)行') } pageC ...省略一些代碼... creatted(){ console.log('pageC 的 created函數(shù)執(zhí)行') } 然后,啟動小程序,不進入這3個頁面,假設我現(xiàn)在有一個index頁面,我們打開這個頁面,會有一下輸出 pageA 的 created函數(shù)執(zhí)行 pageB 的 created函數(shù)執(zhí)行 pageC 的 created函數(shù)執(zhí)行 這個其實很好解決,用mounted或者onLoad或者onReady代替,說到這幾個函數(shù),那就順便提一下, 這里的created和mounted是vue(mpvue)的生命周期,而onLoad、onReady是小程序的生命周期,mpvue官方給的說明是: 除了 Vue 本身的生命周期外,mpvue 還兼容了小程序生命周期,這部分生命周期鉤子的來源于微信小程序的 Page, 除特殊情況外,不建議使用小程序的生命周期鉤子。 但是官方給的生命周期圖示里面,也表明了,小程序的onLoad、onReady比created、mounted執(zhí)行的早, 也就是說如果我們在和onLoad onReady里面去請求數(shù)據(jù)的話,會相對的減少白屏時間(這里說的白屏是指數(shù)據(jù)未渲染的界面), 而且官方?jīng)]說明為什么不建議使用小程序的生命周期,我們也嘗試了,用小程序的生命周期,沒發(fā)現(xiàn)生命問題, 所以我們還是比較傾向優(yōu)先使用小程序的生命周期,畢竟用戶體驗才是王道。 四、掛載在Vue.prototype上的屬性,在模板語法里面是undefined,必須經(jīng)過computed計算過一下才能用。 在用vue的時候,我喜歡把圖片的服務器路徑存到vue的原型里面: import config from './config' Vue.prototype.$serverPath = config.serverPath 然后 我們在頁面里面這樣用 <img :src="$serverPath + 'logo.png'" /> 這樣 就可以避免在每個頁面導入config文件,后期如果我們發(fā)布正式版的時候,只要在這邊修改一下config配置文件就可以了 然額,這樣寫在mpvue里面,實際渲染出來的會是 <image src="undefinedlogo.png" ></image> 要想在每個頁面里面使用,只能乖乖在每個頁面里面導入,或者在computed里面返回this.$serverPath 五、用 v-for循環(huán)的時候,如果要給當前項指定一個索引,在vue下,為了省事,我通常喜歡這樣做 v-for="item,index in list" 因為多打一對括號真的是很煩人。但是在mpvue下面卻不行,你必須老老實實這樣寫,否則會報錯。 v-for="(item,index) in list" 六、單獨為每個頁面的設置頁面頭部信息,有提供這個功能,不過文檔不是很詳細,幾經(jīng)嘗試,才試出來。 我們的入口文件main.js(延續(xù)vue的叫法,暫且這么稱呼吧,其實我覺得應該叫配置文件)里面可以這樣配置, 官方文檔大概也是這么說的 這部分內(nèi)容來源于 app 和 page 的 entry 文件,通常習慣是 main.js,你需要在你的入口文件中 export default { config: {} },這才能被我們的 loader 識別為這是一個配置,需要寫成 json 文件。 import Vue from 'vue'; import App from './app'; const vueApp = new Vue(App); vueApp.$mount(); // 這個是我們約定的額外的配置 export default { // 這個字段下的數(shù)據(jù)會被填充到 app.json / page.json config: { pages: ['static/calendar/calendar', '^pages/list/list'], // Will be filled in webpack window: { // 頂部欄的統(tǒng)一配置 backgroundTextStyle: 'light', navigationBarBackgroundColor: '#455A73', navigationBarTitleText: '美團汽車票', navigationBarTextStyle: '#fff' } } }; 同時,這個時候,我們會根據(jù) entry 的頁面數(shù)據(jù),自動填充到 app.json 中的 pages 字段。 pages 字段也是可以自定義的,約定帶有 ^ 符號開頭的頁面,會放到數(shù)組的最前面。 我們看到,可以在config.window下面配置全局的頂部欄樣式,但是如果我們想為每個頁面指定一個樣式呢?事實上, 以上方法只適合配置app.json里面的內(nèi)容,如果你想要為你的每個頁面都添加一種樣式,那么應該這樣做: 在頁面所屬的入口文件(main.js)里面添加以下內(nèi)容,比如我想為 userCenter/index頁面設置一個標題, 應該在userCenter/main.js里面加入 export default { config: { navigationBarTitleText: '個人中心', } } 注意這里跟上面那個全局配置不同的是,配置內(nèi)容navigationBarTitleText是config的屬性, 而全局配置里,則是config.window的屬性 七、組件的命名問題,有一次,我寫了一個局部的組件,為什么叫局部的組件呢,因為我只在某個頁面里面使用, 所以為了簡單化,我給這個組件取了個名字叫 list.vue ,然后在父組件引用: <template> <!-- 省略其他代碼 --> <list /> </template> <script> import list from './components/list' export default { components: {list}, // 省略其他代碼 } </script> 組件能正常顯示,樣式也沒問題,一切看上去都是那么的正常,然而組件里面的邏輯就是不會執(zhí)行。 加上本文第一點提到的,不會報錯,讓我一頓好找啊... 經(jīng)過排查發(fā)現(xiàn),跟組件的引入名稱有關,應該是跟微信的關鍵字同名了。 <template> <!-- 省略其他代碼 --> <listA /> </template> <script> import listA from './components/list' export default { components: {listA}, // 省略其他代碼 } </script> 這樣就能正常運行,出了list,我目前踩到的還有tabbar,搞得我現(xiàn)在命名的時候,看到一些疑似關鍵的字眼,心理都有點陰影。。 這個應該是微信的問題吧,總之遇到了,就一塊寫出來。 八、組件第一次加載的時候不能執(zhí)行onShow里面的內(nèi)容,只有在隱藏又顯示后,才會顯示,而頁面卻每次進入都會顯示 例如我們在一個組件里有一下代碼 onLoad () { console.log('onLoad') }, onShow () { console.log('onShow') }, mounted () { console.log('mounted') }, 頁面加載的時候,我們期望打印出來的是 onLoad onShow mounted 然后實際上,只打印出 onLoad mounted 這個問題,我已給官方提 Issue ,不過目前還沒得到回應 說到這里,我們順便看看小程序的頁面跳轉方式,小程序在一個頁面跳轉(調(diào)用wx.navigateTo)到另一個頁面的時候, 并不會銷毀原來的頁面,而是轉到后臺去,并且執(zhí)行原頁面里面的onHide里的代碼, 這也是為什么小程序的頁面路徑最多只能十層,因為你訪問過的頁面,正常都會保存在內(nèi)存里,相當于vue里的keep-alive, 如果允許跳轉非常多頁面的話,很容易導致內(nèi)存使用過高。 當然,我們也可以使用wx.navigateBack wx.redirectTo wx.reLaunch 來銷毀頁面,這3個方法,會調(diào)用頁面的onUnload函數(shù) 九、canvas放在scroll-view不會隨著頁面滾動,看起來好像是fixed固定在某個位置的,但是在普通的view里面卻可以正常滾動。 這個問題其實是微信的問題,官方文檔里面是有說明這點,不過我遇見問題的時候,沒想到會是微信官方出的問題,各種百度谷歌, 都沒找到這跟這個問題有關的,甚至我很懷疑是我自己代碼的問題,于是新建了一個項目,然后直接考官方的示例代碼,也是一樣的效果。 后面就準備放棄,想其他解決方案了,沒想到今天在官方文檔 - scroll-view組件 的介紹的最底部的 小字 里看到了 tip: 請勿在 scroll-view 中使用 textarea、map、canvas、video 組件 進一步查看了 canvas組件 的文檔,發(fā)現(xiàn)也有類似的提示 tip: 請勿在 scroll-view、swiper、picker-view、movable-view 中使用 canvas 組件。 之所以把這一點也算進來,一是為這個問題坑了我好幾天,我都在想其他方案了,二是這幾天各種百度谷歌, 是有搜到幾個類似的問題,但是都沒人回答,我就在這邊記錄一下,希望后面踩到這個坑的童鞋能搜到。 十、同一個子組件,在2個不同的地方引用,會導致2個地方的樣式都加載不了,而如果只在一個地方引用卻沒問題, 為什么把這個問題放到最后? 因為這只是前幾個版本的腳手架有這個問題,后面的應該就沒有這個問題了。 這個問題我也給官方提過Issue,官方給的回答是用新版本的腳手架重新生成項目,但是項目都快做完了, 這個時候重新生成,然后拷貝代碼,感覺心太累了,所以抱著不折騰不罷休的態(tài)度,終于找到原因,是因為早期版本的腳手架, 缺少了 webpack-mpvue-asset-plugin 這個插件,新版的cli里面會自動添加這個插件。具體看 Issue #180 還有一些官方明確指出的問題,這里就不一一列舉了,有興趣的童鞋可以直接查看mpvue官方文檔 另外,最近正在做一個mpvue的基礎教程,有興趣的童鞋請前往我的 github mpvue-tutorials , 您的一個Star,就是我最大的動力了。 |