公司需求要作app.微信小程序,支付寶小程序三端的東西,查閱了一些資料,最終選擇用uni-app,如下是一些其餘前輩技術選型的文章,各位能夠學習一下。html
uni-app官方文檔:vue
掘金上選型文章:git
juejin.im/post/5c4ec3…github
對比和參照以後,再結合我司狀況,技術總監選擇了uni-appvuex
其實我以爲本身的水平不可以去評價一款框架的好壞,只是簡單的說一下開發體驗,我認爲坑大概分三種。json
1:該框架確實沒有的功能,存在不能實現的東西。canvas
2:明顯的bug,致使程序出現問題,影響開發進度和結果小程序
3:在開發過程當中,本身憑藉直覺和經驗在開發,結果和預期不一樣,閱讀文檔事後才發現和以前經驗積累的寫法不同,會不禁自主的說一句真坑,或者說在不一樣端有的不一樣寫法,但本身沒有作好兼容,就出現了不一樣端效果不一致,當再次閱讀文檔找到問題後也會來一句真坑。
總的來說,此次Uni-app的開發之旅仍是比較通暢的。
前言:我只說我碰見過的問題,和一些注意點,以及怎麼去解決,不會講uni-app怎麼用,怎麼用你們仍是去閱讀文檔吧,文檔上寫的更清楚
使用upx 而不是 px
修改內容(評論區大佬的訂正): 1px = 2upx是不許確的,upx和rpx是響應式單位,以750px爲基準寬度,根據設備屏幕寬度自動調整
1px = 2upx
mian.js
中,vue原型上掛載一次
uni-app的路由所有配置在page.json
這個文件中,問題就在於多人開發的時候,路由沒法拆分,若是處理的很差,常常發生衝突。至於其中的一些配置項,就請見官方文檔。
在頁面中沒有專門的 $route
和 $router
對象 僅能在頁面的生命週期裏面接受路由傳參,詳情見文檔。
路由傳參方式
let url = `/pages/shopManagement/sonPage/billDetails?StoreID=${StoreID}`
複製代碼
路由接參方式:
onLoad(route){
this.getData.StoreID=route.StoreID
this.getCurryInfo()
},
onLoad接收到一個參數對象
複製代碼
若是你的項目僅是h5,那能夠放心大膽的使用dom操做,但若是要在小程序和app跑,就不要作dom操做了,不生效。
不過ref仍是能夠用的,同樣能夠獲取到這個節點,該幹啥幹啥。
說到ref我就要提一下生命週期
具體的生命週期在文檔中能夠看詳情
大體上和vue的差很少,分紅頁面生命週期和應用生命週期,頁面生命週期就是針對單頁面的,應用生命週期就是針對整個小程序/app的,不過我提出在開發時的一些狀況
在組件中,沒有生命週期,對,你沒看錯!好比頁面a引用了組件b 在組件b中,onLoad,onShow,onReady所有失效,不過用created和mounted是生效的,可是我在開發的時候仍是沒有用created和mounted,畢竟文檔明確寫到
因此我在組件中規避使用原vue的生命週期,另外,在上面說了ref,若是要在初始化使用ref要注意生命週期,在onload和show的鉤子中,內部若是是同步操做是用不了的,拿不到$refs
,我不知道怎麼解釋這個問題,在vue中很好解釋,在created拿不到ref是由於dom尚未渲染出來,只有在mounted時dom渲染出來了才能拿到ref,可是uniapp中不是沒得dom嘛。。。。。我也沒深究過,若是要用,只能異步,能夠加setTimeout 或者 放在某個請求後用,這個時候是能夠拿到ref的
咱們最開始的時候是本身簡單的封裝了一下發送的請求
export const HttpRequest_ = {
config: function(name) {
var info = null;
if (name) {
var name2 = name.split("."); //字符分割
if (name2.length > 1) {
info = configdata[name2[0]][name2[1]] || null;
} else {
info = configdata[name] || null;
}
if (info == null) {
let web_config = cache.get("web_config");
if (web_config) {
if (name2.length > 1) {
info = web_config[name2[0]][name2[1]] || null;
} else {
info = web_config[name] || null;
}
}
}
}
return info;
},
post: function(url, data, header) {
header = header || "application/x-www-form-urlencoded";
//url = this.config("APIHOST")+url;
return new Promise((succ, error) => {
showLoading_()
uni.request({
url: url,
data: data,
method: "POST",
header: {
"content-type": header
},
success: function(result) {
hidLoading_()
succ.call(self, result.data)
},
fail: function(e) {
hidLoading_()
error.call(self, e)
}
})
}).then(res=>{
console.log(res)
return res
},err=>{
console.log('err:',err)
})
},
get: function(url, data, header) {
header = header || "application/x-www-form-urlencoded";
//url = this.config("APIHOST")+url;
return new Promise((succ, error) => {
showLoading_()// 加載中
uni.request({
url: url,
data: data,
method: "GET",
header: {
"content-type": header
},
success: function(result) {
hidLoading_() //關閉加載中
succ.call(self, result.data)
},
fail: function(e) {
hidLoading_() //關閉加載中
error.call(self, e)
}
})
}).then(res=>{
console.log(res)
return res
},err=>{
uni.showToast({
duration:2000,
title:'數據異常,請稍後再試',
icon:'none'
})
console.log('err:',err)
})
}
}
複製代碼
以前我覺得在Uniapp中發送請求只能用他們請求方法,後來同事說也能夠用其餘的。
咱們便引入其餘的庫。
導航欄注意的一個問題就是不一樣端的不一樣展現形式,因此須要處理兼容問題。
導航欄,能夠用自定義的,能夠用框架提供的,也有一些插件,都仍是能夠用的,就是注意顯示的區別,若是有多端需求,必定要在不一樣端跑一下看看效果,否則到時候會很煩。
在支付寶小程序中,原生的導航欄是取消不了,因此不能用自定義的插件,就須要在page.json
中配置原生的導航欄
隨便找了一個頁面,咱們的頭部導航是條件編譯的:
具體的文檔在這裏:
我一開始是沒有注意到這一點,按照個人一些常規習慣寫而且一直在用h5調試,沒有任何問題,後來上真機和小程序開發工具以後才發現所有失效。
在app端想要打開第三方的網址或者程序,必定要區分ios和安卓端。
首先,ios和安卓喚起第三方app的地址是不同的。
不論是在調試仍是打包,要喚起第三方程序,在ios端要配置白名單
以微信登陸位例:
在app端,uni-app集成的幾個方法,能夠很順利的拿到unionId,openid等一些列信息
uni.getProvider({//獲取uniapp支持的第三方數據
service:'oauth'
}).then(data=>{
var [err,res] = data
var providers=res.provider//類型(微信,新浪,小米,qq)
var flagIndex=providers.indexOf(provider)
if(flagIndex>-1){
return providers[flagIndex] /
}
}).then(res=>{
return uni.login({//登錄接口(能夠獲取用戶信息)
provider:res,
scopes:'auth_base',
timeout:20000,
})
}).then(data=>{//返回一系列登錄信息
var [err,res] = data
if(res.errMsg==="login:ok"){
self.authResult=res.authResult
return res.authResult
}
}
}).then(res=>{//獲取用戶的信息 頭像,地址,等等等
return uni.getUserInfo({
provider:provider,
timeout:20000,
withCredentials:true
})
}).then(data=>{//獲得一些列用戶信息
var [err,res] = data
console.log(res)
if(res.errMsg==="getUserInfo:ok"){
return res
}
})
複製代碼
可是若是在小程序端,不少方法就失效了,由於小程序有一套本身的三方登陸交互策略。
還記得當時剛在app上測成功微信三方登錄後,領導過來看進度,問小程序怎麼樣,我給他放了個體驗版,讓他看看,他問我這個微信登陸也能夠嗎?我拍拍胸脯說沒得問題,隨便登,結果。。。。。。。。。。。。。。。臉疼
uni.login({//登錄接口
provider:'weixin',
scopes:'auth_base',
timeout:20000,
}).then(data=>{//返回一系列登錄信息
let [err,res] = data
if(res.code){
let data ={//這個code很重要,須要拿到code向後臺去換unionid等
js_code: res.code
}
return this.$Request.get(this.$store.state.getopenidUrl,data)
}else{
setTimeout(()=>{
this.$api.msg('數據異常')
},500)
uni.switchTab({
url:'/pages/index/index'
})
}
}).then(res=>{
let res_ = JSON.parse(res.Data)
if('unionid' in res_){
this.getIsBindData.openid=res_.unionid
this.getDataWX.openid = res_.unionid
this.getDataWX.unionid = res_.openid
}else{
this.getIsBindData.openid=res_.openid
this.getDataWX.openid = res_.openid
this.getDataWX.unionid = res_.openid
}
return this.WXuserInfo
})
複製代碼
其餘的三方登陸我沒有試過,可是必定要注意各端之間的差別性
另外,支付寶三方登陸uni-app沒有集成,要是本身想作,就用原生來寫,理論上是能夠作的。因爲咱們團隊沒有會原生的,咱們試過用webview作支付寶的三方登陸,最後仍是卡在了受權這一塊,不得而終,遂閹了該需求。
2019 8.20 更新:
在插件市場已經有了安卓端和ios端受權登陸的插件(是付費插件)詳情:
寫成組件在小程序上失效,僅能在index頁面上使用。在h5生效,封裝成組件也能夠,渲染效果也不是太好,app端沒有試過,由於後來看效果很差就暫時擱置這個需求了。
評論區朋友的訂正: canvas在組件中使用時,記得傳遞第二個參數組件實例對象:uni.createCanvasContext(canvasId, this)
我試過了,封裝成組件的狀況下,傳入this,在小程序是生效的.以前是沒有傳入的
我以前從未寫過app和小程序,對一些東西不夠敏感
在我調試地圖,導航等功能的時候用的很順暢,後來打包就失效了,就是由於沒配sdk,原來在咱們調試的時候用的sdk,key等是Uniapp的。
另外須要用到一些權限的時候記得也要去manifest.json中去配置,總的來說,圖形化界面配置仍是比較友好,源碼配置也沒有那麼複雜,基本上都能查到
原生子窗體:不支持upx ,不支持百分比,不支持background-image 若是放image的話必需要寬高,這都是weex的標準,因此在用東西以前仍是要仔細讀一下文檔,不要就是什麼都不讀,憑着感受在寫。
2019 8.20 更新:
評論區朋友補充: nvue要支持upx,須要使用uni-app編譯模式,而不是weex編譯模式
uni-app沒得開屏這個配置項,只能用一些策略來作。
實質上是是用swiper組件+本地緩存作的模擬開屏引導,注意的是,若是產品一開始就定位了要作引導頁,那就考慮好index的怎麼寫,咱們是後期纔打算加的,若是要把index改掉成本有點大,因此用了另外一種策略,但若是在性能很差的手機上會出現尷尬的事情,就不細說怎麼尷尬了,若是用上面的策略,再尷尬也不過是白屏,在上面的dome中,index僅是一箇中轉頁面,什麼都沒有寫。因此我的建議仍是用以上的策略。
至今我沒有我沒有找到如何配置路徑別名的文件或者方法。
在uniapp中 @ 是表示根路徑,不過整個文件結構仍是很清晰的,沒有那麼多的配置文件,整個根文件很像常規的src目錄,用@基本上也很舒服。
總的來說,Uniapp的插件市場仍是不錯的,大多數能用到的插件均可以找到,找不到的也能夠從個別類似的插件中找到靈感,本身再魔改一下,論壇也還行,基本上本身遇到的問題都能找到答案,可是也有找不到的或者有人提出卻無人回答的,官方qq羣也仍是比較熱鬧,有些東西本身沒碰見的看看別人的問題和解決方案也算是一種成長,本身碰見過的給別人解答,換來一聲謝謝也是很開心的。
2019 8.16更新
文檔:
我不知道爲何 uni.compressImage(OBJECT) 這個接口在app端失效微信小程序生效,報錯信息也很簡單,就是說壓縮失敗,沒有其餘的提示,我在官方羣問了一圈沒人給我回答,看了下社區也沒有太有價值的回答。
後來本身慢慢琢磨了一下,也參考了這位老哥的文章(文章中也包含了轉換base64的方法),簡單的封裝了個函數。
參考文章:
/* src:圖片的本地路徑 quality:壓縮範圍 0-100 */
function zipImage(src,quality=30){
// #ifdef APP-PLUS app
let index = src.lastIndexOf(".")
let imgDirname = src.substring(0,index)//圖片的原始地址
let imgName = new Date().getTime();//壓縮後的文件
let imgType = src.substring(index+1,src.length);//圖片的類型
return new Promise((resolve,rej)=>{
plus.zip.compressImage({
src,
dst: imgDirname+imgName+'.'+imgType,
quality,
}, res => {
resolve(res.target)
}, err => {
console.log(err);
rej(err)
});
})
// #endif
// #ifdef MP-WEIXIN 微信小程序
return new Promise((resolve,rej)=>{
uni.compressImage({
src,
success:(res)=>{
console.log(res,1)
let path = res.tempFilePath
resolve(path)
// this.imgList.push(path)
// this.imgList.push
},
fail:(e)=>{
uni.showToast({
title:'上傳失敗,請從新上傳',
duration:2000
})
},
complete:(val)=>{
console.log(val,3)
}
})
})
// #endif
}
複製代碼
調用的時候,直接會吐出來壓縮後的圖片路徑
uni.chooseImage({
success:(res)=>{
res.tempFiles.forEach(async (it)=>{
let localPath =it.path
localPath = await this.$api.zipImage(localPath) //await一下就能夠接住了
this.imageList.push({
value:localPath
})
})
}
});
複製代碼
注意各端的差別性,不少東西,h5對着的,上真機就錯了,真機好着的,換小程序就錯了,不一樣小程序之間還有差別,總之就是考慮好不一樣的狀況,重點是仔細閱讀文檔。
雖然可能一些原生能夠實現的功能uniapp實現不了,不過總體開發下來仍是比較愉快,不少的坑仍是由於多端不兼容,除了寫起來麻煩一點,基本上都仍是有能夠解決的策略。
新的項目也即將開始,這一次是h5+小程序,仍是打算用uniapp。
最後也但願uniapp越作越好,各方面愈來愈完善,爲我這種搬磚碼農增長一份生存的籌碼。
這是開發出來的微信小程序,有興趣的朋友能夠掃碼從註冊到登陸試一下