uni-app的開發經歷(持續更新)

技術選型

公司需求要作app.微信小程序,支付寶小程序三端的東西,查閱了一些資料,最終選擇用uni-app,如下是一些其餘前輩技術選型的文章,各位能夠學習一下。html

uni-app官方文檔:vue

uniapp.dcloud.io/READMEios

掘金上選型文章:git

juejin.im/post/5c4ec3…github

juejin.im/post/5ca173…web

對比和參照以後,再結合我司狀況,技術總監選擇了uni-appvuex

我認爲的坑?

其實我以爲本身的水平不可以去評價一款框架的好壞,只是簡單的說一下開發體驗,我認爲坑大概分三種。json

1:該框架確實沒有的功能,存在不能實現的東西。canvas

2:明顯的bug,致使程序出現問題,影響開發進度和結果小程序

3:在開發過程當中,本身憑藉直覺和經驗在開發,結果和預期不一樣,閱讀文檔事後才發現和以前經驗積累的寫法不同,會不禁自主的說一句真坑,或者說在不一樣端有的不一樣寫法,但本身沒有作好兼容,就出現了不一樣端效果不一致,當再次閱讀文檔找到問題後也會來一句真坑。

總的來說,此次Uni-app的開發之旅仍是比較通暢的。

踩坑之旅

前言:我只說我碰見過的問題,和一些注意點,以及怎麼去解決,不會講uni-app怎麼用,怎麼用你們仍是去閱讀文檔吧,文檔上寫的更清楚

像素單位

使用upx 而不是 px

修改內容(評論區大佬的訂正): 1px = 2upx是不許確的,upx和rpx是響應式單位,以750px爲基準寬度,根據設備屏幕寬度自動調整

1px = 2upx

引入vuex

常規的引入方式在uniapp中是不行的,須要在 mian.js中,vue原型上掛載一次

路由

uni-app的路由所有配置在page.json這個文件中,問題就在於多人開發的時候,路由沒法拆分,若是處理的很差,常常發生衝突。至於其中的一些配置項,就請見官方文檔。

在頁面中沒有專門的 $route$router對象 僅能在頁面的生命週期裏面接受路由傳參,詳情見文檔。

uniapp.dcloud.io/frame?id=路由…

路由傳參方式
let url = `/pages/shopManagement/sonPage/billDetails?StoreID=${StoreID}`
複製代碼

路由接參方式:

onLoad(route){
	this.getData.StoreID=route.StoreID
	this.getCurryInfo()
},
onLoad接收到一個參數對象
複製代碼

DOM操做

若是你的項目僅是h5,那能夠放心大膽的使用dom操做,但若是要在小程序和app跑,就不要作dom操做了,不生效。

不過ref仍是能夠用的,同樣能夠獲取到這個節點,該幹啥幹啥。

生命週期

說到ref我就要提一下生命週期

具體的生命週期在文檔中能夠看詳情

uniapp.dcloud.io/frame?id=應用…

大體上和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中發送請求只能用他們請求方法,後來同事說也能夠用其餘的。

咱們便引入其餘的庫。

fly.io/

導航欄

導航欄注意的一個問題就是不一樣端的不一樣展現形式,因此須要處理兼容問題。

導航欄,能夠用自定義的,能夠用框架提供的,也有一些插件,都仍是能夠用的,就是注意顯示的區別,若是有多端需求,必定要在不一樣端跑一下看看效果,否則到時候會很煩。

在支付寶小程序中,原生的導航欄是取消不了,因此不能用自定義的插件,就須要在page.json中配置原生的導航欄

隨便找了一個頁面,咱們的頭部導航是條件編譯的:

動態的class style

具體的文檔在這裏:

uniapp.dcloud.io/use

我一開始是沒有注意到這一點,按照個人一些常規習慣寫而且一直在用h5調試,沒有任何問題,後來上真機和小程序開發工具以後才發現所有失效。

打開第三方的網址或app

在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
      }
    })
複製代碼

可是若是在小程序端,不少方法就失效了,由於小程序有一套本身的三方登陸交互策略。

developers.weixin.qq.com/miniprogram…

還記得當時剛在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端受權登陸的插件(是付費插件)詳情:

ext.dcloud.net.cn/plugin?id=6…

canvas

寫成組件在小程序上失效,僅能在index頁面上使用。在h5生效,封裝成組件也能夠,渲染效果也不是太好,app端沒有試過,由於後來看效果很差就暫時擱置這個需求了。

評論區朋友的訂正: canvas在組件中使用時,記得傳遞第二個參數組件實例對象:uni.createCanvasContext(canvasId, this)

我試過了,封裝成組件的狀況下,傳入this,在小程序是生效的.以前是沒有傳入的

注意sdk的配置

我以前從未寫過app和小程序,對一些東西不夠敏感

在我調試地圖,導航等功能的時候用的很順暢,後來打包就失效了,就是由於沒配sdk,原來在咱們調試的時候用的sdk,key等是Uniapp的。

另外須要用到一些權限的時候記得也要去manifest.json中去配置,總的來說,圖形化界面配置仍是比較友好,源碼配置也沒有那麼複雜,基本上都能查到

原生子窗體(nvue)

原生子窗體:不支持upx ,不支持百分比,不支持background-image 若是放image的話必需要寬高,這都是weex的標準,因此在用東西以前仍是要仔細讀一下文檔,不要就是什麼都不讀,憑着感受在寫。

2019 8.20 更新:

評論區朋友補充: nvue要支持upx,須要使用uni-app編譯模式,而不是weex編譯模式

開屏引導

uni-app沒得開屏這個配置項,只能用一些策略來作。

ext.dcloud.net.cn/plugin?id=1…

實質上是是用swiper組件+本地緩存作的模擬開屏引導,注意的是,若是產品一開始就定位了要作引導頁,那就考慮好index的怎麼寫,咱們是後期纔打算加的,若是要把index改掉成本有點大,因此用了另外一種策略,但若是在性能很差的手機上會出現尷尬的事情,就不細說怎麼尷尬了,若是用上面的策略,再尷尬也不過是白屏,在上面的dome中,index僅是一箇中轉頁面,什麼都沒有寫。因此我的建議仍是用以上的策略。

路徑別名

至今我沒有我沒有找到如何配置路徑別名的文件或者方法。

在uniapp中 @ 是表示根路徑,不過整個文件結構仍是很清晰的,沒有那麼多的配置文件,整個根文件很像常規的src目錄,用@基本上也很舒服。

插件市場和生態

總的來說,Uniapp的插件市場仍是不錯的,大多數能用到的插件均可以找到,找不到的也能夠從個別類似的插件中找到靈感,本身再魔改一下,論壇也還行,基本上本身遇到的問題都能找到答案,可是也有找不到的或者有人提出卻無人回答的,官方qq羣也仍是比較熱鬧,有些東西本身沒碰見的看看別人的問題和解決方案也算是一種成長,本身碰見過的給別人解答,換來一聲謝謝也是很開心的。

壓縮圖片

2019 8.16更新

文檔:

uniapp.dcloud.io/api/media/i…

我不知道爲何 uni.compressImage(OBJECT) 這個接口在app端失效微信小程序生效,報錯信息也很簡單,就是說壓縮失敗,沒有其餘的提示,我在官方羣問了一圈沒人給我回答,看了下社區也沒有太有價值的回答。

後來本身慢慢琢磨了一下,也參考了這位老哥的文章(文章中也包含了轉換base64的方法),簡單的封裝了個函數。

參考文章:

github.com/SilurianYan…

/* 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越作越好,各方面愈來愈完善,爲我這種搬磚碼農增長一份生存的籌碼。

這是開發出來的微信小程序,有興趣的朋友能夠掃碼從註冊到登陸試一下

相關文章
相關標籤/搜索