- 在列表page點選進入詳情頁面時,用mounted()方法 去獲取資料去展示資料,但是有些資料需要在onShow()方法中呼叫,因為mpvue框架問題,所以在返回的時候如果不將data中定義的資料清除的話,再次點選進入詳情頁面的話,還是會顯示第一次進入詳情頁的資料,可以在methods中寫一個初始化資料的方法
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()的時候在給賦值就可以了。
- 在請求資料的時候,我們選用flyio.js來進行資料的請求獲取,所以我們會對請求方法進行二次封裝,在封裝的時候我們會加入一個微信原生提供的loading方法(wx.showLoading())方法用於在請求介面時的等待顯示,使使用者體驗會更好。這樣做在其他請求頁面請求介面還好,但是在列表頁面下拉載入時,
onPullDownRefresh() {
this.refreshClassList();
},
refreshClassList() {
wx.request({
success: res => {
...
wx.hideLoading();
wx.stopPullDownRefresh();
}
})
}
複製程式碼
由於小程式提供下拉重新整理方法,所以使用原生的下拉重新整理方法,但是下拉回彈的動畫總是會過度回彈,導致頂部元素被遮擋,同時多次下拉會有機率觸發頁面卡下來的bug,通過查詢,確認是兩個loading共用導致,小程式的下拉重新整理有頂部動畫效果,所以下拉重新整理時不需要做wx.showLoading的提示,最終在封裝得請求中去掉了wx.showLoading()方法,在列表頁面使用微信自帶的下拉loading。
- 微信小程式在最新版將不再提供預設彈出授權視窗,需要使用者去點選觸發才能彈出授權視窗,經過商討,我們決定在新增一個授權頁面,在app.vue的onLaunch()方法中判斷是否授權,如果沒有授權將跳到授權頁面,點選按鈕進行授權,反之,則繼續執行正常操作,這個地方還有一個坑,就是分享出去的頁面邏輯裡面不要再去判斷授權,要不然會彈出兩個授權頁面。
- 我們在寫元件的時候,往往會用到slot插槽,但是在巢狀元件中使用slot插槽無法正常顯示渲染,最終在mpvue的Issues中找到解決辦法,要在mpvue@1.0.11,mpvue-template-compiler@1.0.11,mpvue-loader@1.0.13的環境下巢狀元件的slot才可以正常使用。目前已降級到指定版本,暫時沒有發現bug。
- 在專案中有用到城市聯級選擇的情景,當時選用mpvue-picker外掛來開發,因為聯動需要迴圈,第一級或者第二級改變都需要遍歷一遍陣列,省市可能資料量比較大,然後就出現了卡頓,所以棄用,然後又找到了mpvue-citypicker,這個外掛將citypicker單獨出來,改變了城市資料結構,沒有出現卡頓現象。但是這個外掛裡面的城市列表跟公司的城市不對應,返回的資料也不是我們想要的。所以我把它的原始資料給替換成了公司所需要的城市資料,並返回業務所需要的資料。考慮到這個小程式是多人開發,然後把這個外掛整合了一下,發到了npm包上,供大家下載使用,npm包名為mpvue-citypicker-ht
- 小程式分享朋友圈功能,首先請求後端生成的小程式碼(生成小程式碼需要access token,後端生成比較方便),要使用小程式碼的圖片路徑,如果直接使用的話使用canvas是畫不上去的,必須要通過wx.downloadFile這個api先把圖片下載到本地,拿到臨時路徑
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中只能傳遞一個引數,所以我們將引數用一個特殊符號拼接起來,比如
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
}
複製程式碼
在對應的頁面
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()方法將引數分割成陣列,在去拿對應的引數就可以了
7.mpvue在npm run build的後在ios低版本8, 9中會如下的錯:
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檔案中把
{
test: /\.js$/,
include: resolve('src'),
use: [
'babel-loader',
{
loader: '@f-loat/mpvue-loader',
options: {
checkMPEntry: true
}
},
]
},
複製程式碼
替換成
{
test: /\.js$/,
include: [resolve('src'), resolve('test'), /mpvue-wxparse/],
use: [
'babel-loader',
{
loader: '@f-loat/mpvue-loader',
options: {
checkMPEntry: true
}
},
]
}
複製程式碼
就可以成功的解決這個bug了。
- 真機和模擬器的問題總結
- input 標籤中設定為placeholder屬性,縮排樣式text-indent在模擬器中失效,在真機上可以的,但是value值是不起作用的,只能用padding-left來進行縮排了
- 測試過程中,域名為http格式的請求,在模擬器下可以正常執行,在真機中必須開啟除錯才能看到效果
- 由於video元件呼叫的是客戶端建立的原生元件,它的層級是最高的,模擬器中不會出現這個問題,而真機中會覆蓋其他的內容,要使用對應的cover-view標籤或者cover-image標籤
- 定時器問題 在有些頁面需要進行倒數計時效果,再離開頁面的時候一定要把定時器清除乾淨,不然會影響效能,再次進入頁面的時候時間也會亂跳
10.頁面連續點選之後跳轉多次詳情頁面問題 在使用wx.navigateTo()方法跳轉時,會有complete這個回撥方法, 可以設定一個flag,預設為true,在點選的時候,將flag設定為false,然後在這個complete這個回撥裡再將flag設定為true,這樣可以有效避免快速連續點選跳轉多次詳情頁問題。還有一種是需要在點選的時候調介面做判斷是否跳轉,這種的情況用上述方法是不能解決的,目前想到的解決辦法就是在調介面的時候加個loading,mark設定尾true,mark屬性就是為了顯示透明蒙層,防止觸控穿透
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