initData() { this.videoFlag = false //是否顯示視頻 this.classDes = {} this.promotionData = {} this.activeIndex = 0 this.classDetailData = null this.classId = null this.isShow = false this.networkType = 'wifi' this.classVideoData = {} }
須要在onUnload()函數中調用這個方法,這樣才能保證下次進來會展現新的數據,這個問題只在mpvue框架會出現,在原生小程序中是不會出現的。mpvue的子元素生命週期很混亂,若是咱們在頻繁的更換頁面詳情得時候,會出現子元素數據不變緩存的問題,咱們須要在onHide()中將傳遞給子元素的數據重置,而後在onShow()的時候在給賦值就能夠了。
2. 在請求數據的時候,咱們選用flyio.js來進行數據的請求獲取,因此咱們會對請求方法進行二次封裝,在封裝的時候咱們會加入一個微信原生提供的loading方法(wx.showLoading())方法用於在請求接口時的等待顯示,使用戶體驗會更好。這樣作在其餘請求頁面請求接口還好,可是在列表頁面下拉加載時,html
onPullDownRefresh() { this.refreshClassList(); }, refreshClassList() { wx.request({ success: res => { ... wx.hideLoading(); wx.stopPullDownRefresh(); } }) }
因爲小程序提供下拉刷新方法,因此使用原生的下拉刷新方法,可是下拉回彈的動畫老是會過分回彈,致使頂部元素被遮擋,同時屢次下拉會有概率觸發頁面卡下來的bug,經過查找,確認是兩個loading共用致使,小程序的下拉刷新有頂部動畫效果,因此下拉刷新時不須要作wx.showLoading的提示,最終在封裝得請求中去掉了wx.showLoading()方法,在列表頁面使用微信自帶的下拉loading。
3. 微信小程序在最新版將再也不提供默認彈出受權窗口,須要用戶去點擊觸發才能彈出受權窗口,通過商討,咱們決定在添加一個受權頁面,在app.vue的onLaunch()方法中判斷是否受權,若是沒有受權將跳到受權頁面,點擊按鈕進行受權,反之,則繼續執行正常操做,這個地方還有一個坑,就是分享出去的頁面邏輯裏面不要再去判斷受權,要否則會彈出兩個受權頁面。
4. 咱們在寫組件的時候,每每會用到slot插槽,可是在嵌套組件中使用slot插槽沒法正常顯示渲染,最終在mpvue的Issues中找到解決辦法,要在mpvue@1.0.11,mpvue-template-compiler@1.0.11,mpvue-loader@1.0.13的環境下嵌套組件的slot才能夠正常使用。目前已降級到指定版本,暫時沒有發現bug。
5. 在項目中有用到城市聯級選擇的情景,當時選用mpvue-picker插件來開發,由於聯動須要循環,第一級或者第二級改變都須要遍歷一遍數組,省市可能數據量比較大,而後就出現了卡頓,因此棄用,而後又找到了mpvue-citypicker,這個插件將citypicker單獨出來,改變了城市數據結構,沒有出現卡頓現象。可是這個插件裏面的城市列表跟公司的城市不對應,返回的數據也不是咱們想要的。因此我把它的原始數據給替換成了公司所須要的城市數據,並返回業務所須要的數據。考慮到這個小程序是多人開發,而後把這個插件整合了一下,發到了npm包上,供你們下載使用,npm包名爲mpvue-citypicker-ht
6. 小程序分享朋友圈功能,首先請求後端生成的小程序碼(生成小程序碼須要access token,後端生成比較方便),要使用小程序碼的圖片路徑,若是直接使用的話使用canvas是畫不上去的,必需要經過wx.downloadFile這個api先把圖片下載到本地,拿到臨時路徑vue
wx.getImageInfo({ src: _this.GenerateQrcode, success: function(res) { const background = '/static/canvas/canvas.png' const GenerateQrcode_s = res.path console.log(GenerateQrcode_s) wx .createSelectorQuery() .select('.box') .boundingClientRect(function(rect) { const { user, title, price, teacher, configs1, configs2, content, message } = _this.friendCircleParam const shareModule = wx.createCanvasContext('shareCanvas') const { width, height } = rect const canvas_w = width * wx.getSystemInfoSync().windowWidth / 400 // 375 const canvas_h = height * wx.getSystemInfoSync().windowWidth / 380 const centerX = canvas_w / 2 const rpx = _this.rpxchange // rpx // 初始化 canvas寬度 _this.shareCanvasWidth = `width:${canvas_w}px;height:${canvas_h}px;` // 繪製背景 shareModule.drawImage(background, 0, 0, canvas_w, canvas_h) // 繪製分享人 shareModule.setTextAlign('center') shareModule.setFontSize(rpx(24)) shareModule.setFillStyle('#FFFFFF') shareModule.fillText(user, centerX, rpx(48 + 24 + 6)) // 繪製文案 shareModule.setFontSize(rpx(60)) shareModule.setFillStyle('#FCE9A7') shareModule.fillText(title, centerX, rpx(106 + 36 + 16)) // 繪製價格 shareModule.setFontSize(rpx(28)) shareModule.setFillStyle('#FFFFFF') shareModule.fillText(price, centerX, rpx(216 + 28)) shareModule.setStrokeStyle('#fff') shareModule.beginPath(); shareModule.arc(rpx(210) + rpx(20), rpx(210) + rpx(20), rpx(20), Math.PI, Math.PI * 3 / 2); shareModule.lineTo(rpx(200) - rpx(20) + rpx(210), rpx(210)); shareModule.arc(rpx(200) - rpx(20) + rpx(210), rpx(20) + rpx(210), rpx(20), Math.PI * 3 / 2, Math.PI * 2); shareModule.lineTo(rpx(200) + rpx(210), rpx(48) + rpx(210) - rpx(20)); shareModule.arc(rpx(200) - rpx(20) + rpx(210), rpx(48) - rpx(20) + rpx(210), rpx(20), 0, Math.PI * 1 / 2); shareModule.lineTo(rpx(20) + rpx(210), rpx(48) +rpx(210)); shareModule.arc(rpx(20) + rpx(210), rpx(48) - rpx(20) + rpx(210), rpx(20), Math.PI * 1 / 2, Math.PI); shareModule.closePath(); // shareModule.strokeRect(rpx(220), rpx(200), rpx(200), rpx(20)) // shareModule.fillText(price, centerX, rpx(220 + 38)) // 繪製描述 shareModule.font = `bold ${rpx(36)}px PingFangSC-Semibold` shareModule.setFillStyle('#000') _this.drawText( shareModule, content, centerX, rpx(340 - 42), canvas_w * 0.9, rpx(50) ) // 繪製老師 shareModule.font = `normal ${rpx(24)}px PingFangSC-Semibold` shareModule.setFillStyle('#888888') // shareModule.fillText(teacher, centerX, rpx(410 + 24 + 6)) _this.drawText( shareModule, teacher, centerX, rpx(410 - 60), canvas_w * 0.7, rpx(30) ) // 繪製中間提示文案 shareModule.font = `normal ${rpx(26)}px PingFangSC-Semibold` shareModule.setFillStyle('#FF6d73') shareModule.fillText(configs1, centerX, rpx(450 + 54 + 6)) shareModule.font = `normal ${rpx(26)}px PingFangSC-Semibold` shareModule.setFillStyle('#FF6d73') shareModule.fillText(configs2, centerX, rpx(480 + 74 + 6)) shareModule.drawImage(_this.GenerateQrcode, centerX, rpx(584), rpx(252), rpx(250)) console.log(_this.GenerateQrcode) shareModule.drawImage( GenerateQrcode_s, canvas_w * 0.3, rpx(594), rpx(200), rpx(200) ) // 長按識別小程序碼,一塊兒省錢! shareModule.setFontSize(rpx(26)) shareModule.setFillStyle('#Afafaf') shareModule.fillText(message, centerX, rpx(824 + 28 + 8)) // line shareModule.stroke() shareModule.draw() wx.hideLoading() }) .exec() }, fail: function(err) { wx.hideLoading() wx.showToast({ title: '生成失敗,請從新嘗試', icon: 'none', duration: 3000, mask: true }) } })
_this.GenerateQrcode是從後臺活動的小程序二維碼,若是須要背景圖的話,須要在本地保存一張圖片當作背景圖。切記不能使用線上圖片,不起做用。
識別圖片跳轉到小程序相關頁面時,須要在生成圖片傳遞須要的參數,參數要在scene中傳遞。可是有些頁面須要多個參數才能夠打開,可是scene中只能傳遞一個參數,因此咱們將參數用一個特殊符號拼接起來,好比webpack
var par = `${this.$root.$mp.query.activityId}_${ this.$root.$mp.query.classId }_${this.$root.$mp.query.isLive}` this.GenerateParam = { // 小程序二維碼參數 scene: par, page: `pages/activityInfo/components/activityDetail`, width: 250, auto_color: false, line_color: { r: '236', g: '66', b: '76' }, is_hyaline: true }
在對應的頁面ios
onLoad(options) { var that = this if (options.scene) { that.scene = decodeURIComponent(options.scene) var arr = that.scene.split('_') that.getPara = arr console.log('value', arr) } },
用split()方法將參數分割成數組,在去拿對應的參數就能夠了git
7.mpvue在npm run build的後在ios低版本8, 9中會以下的錯:github
Page[pages/index/main] not found. May be caused by: 1.forgot to add page route in app.json. 2.Invoking Page{} in async task. thirdScriptError sdk uncaught third error SyntaxError line:16045,column:0,SynataxError:Unexpected keyword 'const'. Const declarations are not supported in strict mode. Stack:
報這個錯得緣由是由於咱們的項目安裝了mpvue-wxparse這個插件,由於微信小程序不能像vue同樣用v-html解析帶有html標籤的數據,因此咱們安裝了這個插件。解決這個報錯的方法是在webpack.base.conf.js文件中把web
{ test: /\.js$/, include: resolve('src'), use: [ 'babel-loader', { loader: '@f-loat/mpvue-loader', options: { checkMPEntry: true } }, ] },
替換成npm
{ test: /\.js$/, include: [resolve('src'), resolve('test'), /mpvue-wxparse/], use: [ 'babel-loader', { loader: '@f-loat/mpvue-loader', options: { checkMPEntry: true } }, ] }
就能夠成功的解決這個bug了。
8. 真機和模擬器的問題總結json
10.頁面連續點擊以後跳轉屢次詳情頁面問題
在使用wx.navigateTo()方法跳轉時,會有complete這個回調方法,
能夠設置一個flag,默認爲true,在點擊的時候,將flag設置爲false,而後在這個complete這個回調裏再將flag設置爲true,這樣能夠有效避免快速連續點擊跳轉屢次詳情頁問題。還有一種是須要在點擊的時候調接口作判斷是否跳轉,這種的狀況用上述方法是不能解決的,目前想到的解決辦法就是在調接口的時候加個loading,mark設置尾true,mark屬性就是爲了顯示透明蒙層,防止觸摸穿透canvas
11.同路由跳轉問題
在同一個路由下跳轉,例如課程詳情頁跳轉到另外一個課程詳情頁時,在點擊返回按鈕時,數據仍是停留在第二個詳情頁,這是mpvue存留的bug,暫時沒人修復,只能經過如下代碼去解決。
在utils裏建立一個initData.js的文件,內容爲:
const pageDatas = {} export default { install(_Vue) { // 添加全局方法或屬性 _Vue.prototype.$isPage = function isPage() { return this.$mp && this.$mp.mpType === 'page' } _Vue.prototype.$pageId = function pageId() { return this.$isPage() ? this.$mp.page.__wxWebviewId__ : null } // 注入組件 _Vue.mixin({ methods: { stashPageData() { return { data: { ...this.$data } } }, restorePageData(oldData) { Object.assign(this.$data, oldData.data) }, }, onLoad() { if (this.$isPage()) { // 新進入頁面 Object.assign(this.$data, this.$options.data()) } }, onUnload() { if (this.$isPage()) { // 退出頁面,刪除數據 delete pageDatas[this.$pageId()] this.$needReloadPageData = true } }, onHide() { if (this.$isPage()) { // 將要隱藏時,備份數據 pageDatas[this.$pageId()] = this.stashPageData() } }, onShow() { if (this.$isPage()) { // 若是是後退回來的,拿出歷史數據來設置data if (this.$needReloadPageData) { const oldData = pageDatas[this.$pageId()] if (oldData) { this.restorePageData(oldData) } this.$needReloadPageData = false } } }, }) }, }
在main.js˙中引入一下就能夠了。
import initData from '@/utils/initData'; Vue.use(initData)
切記若是引入這段js,就不要再onShow()方法裏獲取數據了,要在mounted()方法中獲取數據,這樣才能解決上述bug