UniAPP 前端開發框架學習
一、UniAPP 介紹
(1)什么是 UniAPP ?
uni-app 是一個使用 Vue.js 開發所有前端應用的框架,開發者編寫一套代碼,可發布到 iOS,Android,H5,以及各種小程序(微信/支付寶/百度/頭條/ QQ /釘釘)等多個平台。
uni-app在手,做啥都不愁。甚至不跨端,也是更好 uni-app 的小程序開發框架,更好的 App 跨平台框架,更方便的 H5 開發框架。
你都可以快速交付,不需要轉換開發思維,不需要更改開發習慣。
(2)為什么要選擇 UniAPP ?
- 開發者/案例數量更多
幾十萬應用、uni統計月活12億、70+微信/qq群、更高的百度指數跨端完善度更高,真正落地的提高生產力。
- 平台能力不受限
在跨端的同時,通過條件編譯+平台特有API調用,可以優雅的為某平台寫個性化代碼,調用專有能力而不影響其他平台。支持原生代碼混寫和原生sdk集成。
- 性能體驗優秀
加載新頁面速度更快、自動diff更新數據。App端支持原生渲染,可支撐更流暢的用戶體驗。小程序端的性能優於市場其他框架。
- 周邊生態豐富
插件市場數千款插件。支持NPM、支持小程序組件和SDK。微信生態的各種sdk可直接用於跨平台App。
- 學習成本低
基於通用的前端技術棧,采用vue語法+微信小程序api,無額外學習成本。
- 開發成本低
不止開發成本,招聘、管理、測試各方面成本都大幅下降。
(3)UniAPP 功能框架
(4)UniAPP 開發環境搭建
下載開發工具,HBuilderX:
HBuilderX是通用的前端開發工具,但為
uni-app
做了特別強化。下載App開發版,可開箱即用;如下載標准版,在運行或發行
uni-app
時,會提示安裝uni-app
插件,插件下載完成后方可使用。創建 uni-app 項目
選擇
uni-app
類型,輸入工程名,選擇模板,點擊創建,即可成功創建。uni-app自帶的模板有 Hello uni-app ,是官方的組件和API示例。還有一個重要模板是 uni ui項目模板,日常開發推薦使用該模板,已內置大量常用組件。
運行 uni-app
主要包括:瀏覽器運行、真機運行、小程序運行等
發布 uni-app
主要包括:雲端原生 APP 、離線原生 APP、H5、各種小程序
(5)UniAPP 框架簡介
開發規范約定
- 頁面文件向導Vue單文件組件(SFC)規范
- 組件標簽靠近小程序規范,詳見uni-app組件規范
- 互連能力(JS API)靠近微信小程序規范,但需要將替換替換 wx 為 uni ,詳見uni-app接口規范
- 數據綁定及事件處理同 Vue.js 規范,同時補充了 App 和頁面的生命周期
- 為兼容多端運行,建議使用 flex 布局進行開發
資源路徑說明
template內約會靜態資源,如image,video等標簽的src屬性時,可以使用相對路徑或絕對路徑,形式如下
<!-- 絕對路徑,/static指根目錄下的static目錄,在cli項目中/static指src目錄下的static目錄 -->
<image class="logo" src="/static/logo.png"></image>
<image class="logo" src="@/static/logo.png"></image>
<!-- 相對路徑 -->
<image class="logo" src="../../static/logo.png"></image>
注意
- @初始的絕對路徑以及相對路徑會通過base64轉換規則校驗
- 約會的靜態資源在非h5平台,均不轉為base64。
- H5平台,小於4kb的資源會被轉換成base64,其余不轉。
js文件或script標簽內(包括renderjs等)日期js文件時,可以使用相對路徑和絕對路徑,形式如下
// 絕對路徑,@指向項目根目錄,在cli項目中@指向src目錄
import add from '@/common/add.js'
// 相對路徑
import add from '../../common/add.js'
css文件或style標簽內約會css文件時(scss,less文件同理),可以使用相對路徑和絕對路徑,形式如下
/* 絕對路徑 */
@import url('/common/uni.css');
@import url('@/common/uni.css');
/* 相對路徑 */
@import url('../../common/uni.css');
css文件或style標簽內引用的圖片路徑,可以使用相對路徑也可以使用絕對路徑,形式如下
/* 絕對路徑 */
background-image: url(/static/logo.png);
background-image: url(@/static/logo.png);
/* 相對路徑 */
background-image: url(../../static/logo.png);
二、UniAPP 初始化相關配置
(1)工程目錄結構
┌─components uni-app組件目錄
│ └─comp-a.vue 可復用的a組件
├─hybrid 存放本地網頁的目錄
├─platforms 存放各平台專用頁面的目錄
├─pages 業務頁面文件存放的目錄
│ ├─index
│ │ └─index.vue index頁面
│ └─list
│ └─list.vue list頁面
├─static 存放應用引用靜態資源(如圖片、視頻等)的目錄,注意:靜態資源只能存放於此
├─wxcomponents 存放小程序組件的目錄
├─common 公共資源(自建)
├─api 請求封裝(自建)
├─store 狀態管理(自建)
├─main.js Vue初始化入口文件
├─App.vue 應用配置,用來配置App全局樣式以及監聽 應用生命周期
├─manifest.json 配置應用名稱、appid、logo、版本等打包信息
└─pages.json 配置頁面路由、導航條、選項卡等頁面類信息
提示
- static下目錄的js文件不會被compile-,里面如果有es6的代碼,不經過轉換直接運行,在手機設備上會報錯。
- css,less/scss等資源同樣不要放在static目錄下,建議這些公共的資源放在common目錄下。
(2)全局配置 page.json
pages.json
文件用來對 uni-app 進行全局配置,決定頁面文件的路徑、窗口樣式、原生的導航欄、底部的原生tabbar 等。它類似微信小程序中app.json
的頁面管理部分。
屬性 | 類型 | 必填 | 描述 |
---|---|---|---|
globalStyle | Object | 否 | 設置默認頁面的窗口表現 |
pages | Object Array | 是 | 設置頁面路徑及窗口表現 |
easycom | Object | 否 | 組件自動引入規則 |
tabBar | Object | 否 | 設置底部 tab 的表現 |
condition | Object | 否 | 啟動模式配置 |
subPackages | Object Array | 否 | 分包加載配置 |
preloadRule | Object | 否 | 分包預下載規則 |
(3)應用配置 manifest.json
manifest.json
文件是應用的配置文件,用於指定應用的名稱、圖標、權限等。
(4)編譯配置 vue.config.js
vue.config.js 是一個可選的配置文件,如果項目的根目錄中存在這個文件,那么它會被自動加載,一般用於配置 webpack 等編譯選項。官方文檔
(5)全局樣式 uni.scss
uni.scss
文件的用途是為了方便整體控制應用的風格。比如按鈕顏色、邊框風格,uni.scss
文件里預置了一批scss變量預置。官方文檔
uni-app
官方擴展插件(uni ui)及 插件市場 上很多三方插件均使用了這些樣式變量,如果你是插件開發者,建議你使用 scss 預處理,並在插件代碼中直接使用這些變量(無需 import 這個文件),方便用戶通過搭積木的方式開發整體風格一致的App。
uni.scss
是一個特殊文件,在代碼中無需 import 這個文件即可在scss代碼中使用這里的樣式變量。uni-app的編譯器在webpack配置中特殊處理了這個 uni.scss,使得每個 scss 文件都被注入這個uni.scss,達到全局可用的效果。如果開發者想要less、stylus的全局使用,需要在vue.config.js中自行配置webpack策略。
(6)主組件 App.vue
App.vue
是uni-app的主組件,所有頁面都是在App.vue
下進行切換的,是頁面入口文件。但App.vue
本身不是頁面,這里不能編寫視圖元素。這個文件的作用包括:調用應用生命周期函數、配置全局樣式、配置全局的存儲globalData
應用生命周期僅可在
App.vue
中監聽,在頁面監聽無效。
(7)入口文件 main.js
main.js
是uni-app的入口文件,主要作用是初始化vue
實例、定義全局組件、使用需要的插件如vuex。
三、UniAPP 生命周期
學習一個工具的目的核心是什么?是為了解決核心業務邏輯問題,業務邏輯很多時候簡單的解釋一句話:“在合適的時機干合適的事情”,OK!什么是合適的時機呢?簡單的說,頁面運行過程中,各個階段的回調函數就是頁面中的時機,我們也叫這個為“生命周期鈎子函數”,當然,業務中我們也會寫到很多「回調」的邏輯,這些回調其實也是咱們自定義的時機,UniAPP 的生命周期鈎子函數回調函數有哪些呢?我們來理解一下!
(1)應用生命周期
函數名 | 說明 |
---|---|
onLaunch | 當uni-app 初始化完成時觸發(全局只觸發一次) |
onShow | 當 uni-app 啟動,或從后台進入前台顯示 |
onHide | 當 uni-app 從前台進入后台 |
onError | 當 uni-app 報錯時觸發 |
onUniNViewMessage | 對 nvue 頁面發送的數據進行監聽,可參考 nvue 向 vue 通訊 |
onUnhandledRejection | 對未處理的 Promise 拒絕事件監聽函數(2.8.1+) |
onPageNotFound | 頁面不存在監聽函數 |
onThemeChange | 監聽系統主題變化 |
(2)頁面生命周期
函數名 | 說明 |
---|---|
onLoad | 監聽頁面加載,其參數為上個頁面傳遞的數據,參數類型為Object(用於頁面傳參),參考示例 |
onShow | 監聽頁面顯示。頁面每次出現在屏幕上都觸發,包括從下級頁面點返回露出當前頁面 |
onReady | 監聽頁面初次渲染完成。注意如果渲染速度快,會在頁面進入動畫完成前觸發 |
onHide | 監聽頁面隱藏 |
onUnload | 監聽頁面卸載 |
onResize | 監聽窗口尺寸變化 |
onPullDownRefresh | 監聽用戶下拉動作,一般用於下拉刷新,參考示例 |
onReachBottom | 頁面滾動到底部的事件(不是scroll-view滾到底),常用於下拉下一頁數據。具體見下方注意事項 |
onTabItemTap | 點擊 tab 時觸發,參數為Object,具體見下方注意事項 |
onShareAppMessage | 用戶點擊右上角分享 |
onPageScroll | 監聽頁面滾動,參數為Object |
onNavigationBarButtonTap | 監聽原生標題欄按鈕點擊事件,參數為Object |
onBackPress | 監聽頁面返回 |
onNavigationBarSearchInputChanged | 監聽原生標題欄搜索輸入框輸入內容變化事件 |
onNavigationBarSearchInputConfirmed | 監聽原生標題欄搜索輸入框搜索事件,用戶點擊軟鍵盤上的“搜索”按鈕時觸發。 |
onNavigationBarSearchInputClicked | 監聽原生標題欄搜索輸入框點擊事件 |
onShareTimeline | 監聽用戶點擊右上角轉發到朋友圈 |
onAddToFavorites | 監聽用戶點擊右上角收藏 |
四、UniAPP 路由配置及頁面跳轉
(1)路由配置
uni-app 頁面路由全部交給框架統一管理,開發者需要在pages.json里配置每個路由頁面的路徑及頁面樣式(類似小程序在app.json中配置頁面路由)。
"pages": [
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "金迅教育 · 路由配置",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF",
"enablePullDownRefresh": true
}
},
{
"path": "pages/user",
"style": {
"navigationBarTitleText": "金迅教育 · 路由配置",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF",
"enablePullDownRefresh": true
}
}
]
(2)路由跳轉
uni-app
有兩種頁面路由跳轉方式:使用navigator組件跳轉(標簽式導航)、調用API跳轉(編程式導航)框架以棧的形式管理當前所有頁面, 當發生路由切換的時候,頁面棧的表現如下:
路由方式 | 頁面棧表現 | 觸發時機 |
---|---|---|
初始化 | 新頁面入棧 | uni-app 打開的第一個頁面 |
打開新頁面 | 新頁面入棧 | 調用 API uni.navigateTo 、使用組件 <navigator open-type="navigate" /> |
頁面重定向 | 當前頁面出棧,新頁面入棧 | 調用 API uni.redirectTo 、 使用組件 |
頁面返回 | 頁面不斷出棧,直到目標返回頁 | 調用 API uni.navigateBack 、 使用組件 、 用戶按左上角返回按鈕、安卓用戶點擊物理back按鍵 |
Tab 切換 | 頁面全部出棧,只留下新的 Tab 頁面 | 調用 API uni.switchTab 、 使用組件 、 用戶切換 Tab |
重加載 | 頁面全部出棧,只留下新的頁面 | 調用 API uni.reLaunch 、 使用組件 |
(3)獲取當前頁面棧
getCurrentPages() 函數用於獲取當前頁面棧的實例,以數組形式按棧的順序給出,第一個元素為首頁,最后一個元素為當前頁面。
注意
: getCurrentPages() 僅用於展示頁面棧的情況,請勿修改頁面棧,以免造成頁面狀態錯誤。
每個頁面實例的方法屬性列表如下:
方法 | 描述 | 平台說明 |
---|---|---|
page.$getAppWebview() | 獲取當前頁面的webview對象實例 | 5+App |
page.route | 獲取當前頁面的路由 | - |
uni-app
在 getCurrentPages()
獲得的頁面里內置了一個方法 $getAppWebview()
可以獲取當前頁面的webview對象實例,從而獲得 webview 的 style、id等屬性,也可設置 webview 的 style。
(4)路由傳參與接收
說明:頁面生命周期的onLoad()監聽頁面加載,其參數為上個頁面傳遞的數據,參數類型為Object(用於頁面傳參)。如:
- 頁面 1 傳遞參數
//頁面跳轉並傳遞參數
uni.navigateTo({
url: 'page2?name=liy&message=Hello'
});
url為將要跳轉的頁面路徑 ,路徑后可以帶參數。參數與路徑之間使用
?
分隔,參數鍵與參數值用=
相連,不同參數用&
分隔。如 'path?key1=value2&key2=value2',path為下一個頁面的路徑,下一個頁面的onLoad函數可得到傳遞的參數。
- 頁面 2 接收參數
onLoad: function (option) { //option為object類型,會序列化上個頁面傳遞的參數
console.log(option.name); //打印出上個頁面傳遞的參數。
console.log(option.message); //打印出上個頁面傳遞的參數。
}
注意
:url有長度限制,太長的字符串會傳遞失敗,可使用窗體通信、全局變量,或encodeURIComponent
等多種方式解決。
(5)小程序路由分包配置
因小程序有體積和資源加載限制,各家小程序平台提供了分包方式,優化小程序的下載和啟動速度。
所謂的主包,即放置默認啟動頁面/TabBar 頁面,以及一些所有分包都需用到公共資源/JS 腳本;而分包則是根據pages.json的配置進行划分。
在小程序啟動時,默認會下載主包並啟動主包內頁面,當用戶進入分包內某個頁面時,會把對應分包自動下載下來,下載完成后再進行展示。此時終端界面會有等待提示。
"subPackages": [
{
"root": "news",
"pages": [{
"path": "index",
"style": {
"navigationBarTitleText": "金迅教育 · 新聞中心",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF"
}
}
]
},
{
"root": "activities",
"pages": [{
"path": "index",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "userList",
"style": {
"navigationBarTitleText": "金迅教育 · 活動報名",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF",
"enablePullDownRefresh": true
}
}
]
}
],
// 預下載分包設置
"preloadRule": {
"pages/index": {
"network": "all",
"packages": ["activities"]
}
}
五、運行環境判斷與跨端兼容
(1)開發環境和生產環境
uni-app
可通過process.env.NODE_ENV
判斷當前環境是開發環境還是生產環境。一般用於連接測試服務器或生產服務器的動態切換。
- 在HBuilderX 中,點擊“運行”編譯出來的代碼是開發環境,點擊“發行”編譯出來的代碼是生產環境
if(process.env.NODE_ENV === 'development'){
console.log('開發環境')
}else{
console.log('生產環境')
}
(2)判斷平台
平台判斷有2種場景,一種是在編譯期判斷,一種是在運行期判斷。
- 編譯期判斷 編譯期判斷,即條件編譯,不同平台在編譯出包后已經是不同的代碼。詳見:條件編譯
// #ifdef H5
alert("只有h5平台才有alert方法")
// #endif
// 如上代碼只會編譯到H5的發行包里,其他平台的包不會包含如上代碼。
- 運行期判斷 運行期判斷是指代碼已經打入包中,仍然需要在運行期判斷平台,此時可使用
uni.getSystemInfoSync().platform
判斷客戶端環境是 Android、iOS 還是小程序開發工具(在百度小程序開發工具、微信小程序開發工具、支付寶小程序開發工具中使用uni.getSystemInfoSync().platform
返回值均為 devtools)。
switch(uni.getSystemInfoSync().platform){
case 'android':
console.log('運行Android上')
break;
case 'ios':
console.log('運行iOS上')
break;
default:
console.log('運行在開發者工具上')
break;
}
(3)跨端兼容
uni-app 已將常用的組件、JS API 封裝到框架中,開發者按照 uni-app 規范開發即可保證多平台兼容,大部分業務均可直接滿足。但每個平台有自己的一些特性,因此會存在一些無法跨平台的情況。
- 大量寫 if else,會造成代碼執行性能低下和管理混亂。
- 編譯到不同的工程后二次修改,會讓后續升級變的很麻煩。
在 C 語言中,通過 #ifdef、#ifndef 的方式,為 windows、mac 等不同 os 編譯不同的代碼。
uni-app
參考這個思路,為uni-app
提供了條件編譯手段,在一個工程里優雅的完成了平台個性化實現。
條件編譯是用特殊的注釋作為標記,在編譯時根據這些特殊的注釋,將注釋里面的代碼編譯到不同平台。
寫法:以 #ifdef 或 #ifndef 加 %PLATFORM% 開頭,以 #endif 結尾。
- #ifdef:if defined 僅在某平台存在
- #ifndef:if not defined 除了某平台均存在
- %PLATFORM%:平台名稱
條件編譯寫法 | 說明 |
---|---|
#ifdef APP-PLUS 需條件編譯的代碼 #endif | 僅出現在 App 平台下的代碼 |
#ifndef H5 需條件編譯的代碼 #endif | 除了 H5 平台,其它平台均存在的代碼 |
#ifdef H5 || MP-WEIXIN 需條件編譯的代碼 #endif | 在 H5 平台或微信小程序平台存在的代碼(這里只有||,不可能出現&&,因為沒有交集) |
%PLATFORM% 可取值如下:
值 | 平台 |
---|---|
APP-PLUS | App |
APP-PLUS-NVUE | App nvue |
H5 | H5 |
MP-WEIXIN | 微信小程序 |
MP-ALIPAY | 支付寶小程序 |
MP-BAIDU | 百度小程序 |
MP-TOUTIAO | 字節跳動小程序 |
MP-QQ | QQ小程序 |
MP-360 | 360小程序 |
MP | 微信小程序/支付寶小程序/百度小程序/字節跳動小程序/QQ小程序/360小程序 |
QUICKAPP-WEBVIEW | 快應用通用(包含聯盟、華為) |
QUICKAPP-WEBVIEW-UNION | 快應用聯盟 |
QUICKAPP-WEBVIEW-HUAWEI | 快應用華為 |
六、UniAPP 常用組件
uni-app 為開發者提供了一系列基礎組件,類似 HTML 里的基礎標簽元素。
但 uni-app 的組件與 HTML 不同,而是與小程序相同,更適合手機端使用。
雖然不推薦使用 HTML 標簽,但實際上如果開發者寫了
div
等標簽,在編譯到非H5平台時也會被編譯器轉換為view
標簽,類似的還有span
轉text
、a
轉navigator
等,包括css里的元素選擇器也會轉。但為了管理方便、策略統一,新寫代碼時仍然建議使用view等組件。開發者可以通過組合這些基礎組件進行快速開發。 基於內置的基礎組件,可以開發各種擴展組件,組件規范與vue組件相同。
案例准備:知心姐姐聊天系統 - 使用組件完成基礎布局功能
七、UniAPP 常用 API
uni-app
的 js API 由標准 ECMAScript 的 js API 和 uni 擴展 API 這兩部分組成。標准 ecmascript 的 API 非常多,比如:console、settimeout等等。
uni-app
的 js 代碼,h5 端運行於瀏覽器中。非 h5 端,Android 平台運行在 v8 引擎中,iOS 平台運行在 iOS 自帶的 jscore 引擎中。非 H5 端,雖然不支持 window、document、navigator 等瀏覽器的 js API,但也支持標准 ECMAScript。
開發者不要把瀏覽器里的 js 等價於標准 js。
ECMAScript 由 Ecma 國際管理,是基礎 js 語法。瀏覽器基於標准 js 擴充了window、document 等 js API;Node.js 基於標准 js 擴充了 fs 等模塊;小程序也基於標准 js 擴展了各種 wx.xx、my.xx、swan.xx 的 API。
所以 uni-app 的非 H5 端,一樣支持標准 js,支持 if、for 等語法,支持字符串、數組、時間等變量及各種處理方法,僅僅是不支持瀏覽器專用對象。
案例准備:知心姐姐聊天系統 - 錄音發送、圖片發送及預覽,AI 接口請求反饋功能實現
八、UniAPP 自定義組件與通信
自定義組件的概念,一般放在 components 中
props 父組件向子組件傳遞數據
emit 子組件向父組件傳遞數據
slot 父組件向子組件傳遞文檔結構
v-slot 子組件向父組件傳遞作用域插槽數據
uni 全局事件數據通信
案例准備:老父親和兩個兒子之間的故事
九、uniapp-vuex 狀態管理
概念:Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
應用場景:Vue多個組件之間需要共享數據或狀態。
Vuex有幾個核心概念:State、Getter、Mutation、Action、Module。
- State:存儲狀態數據
- Getter:從狀態數據派生數據,相當於State的計算屬性。
- Mutation:存儲用於同步更改狀態數據的方法,默認傳入的參數為state。
- Action:存儲用於異步更改狀態數據,但不是直接更改,而是通過觸發Mutation方法實現,默認參數為context。
- Module:Vuex模塊化。
它們之間的交互關系如下圖:
案例准備:用戶登錄、退出態狀態管理
十、UniAPP 插件市場及 uView UI 插件庫
uniapp 為開發者提供了相當完善的插件市場以方便用戶使用,其中具有代表性的就是:uView UI。
uView UI 是 uni-app 生態最優秀的 UI 框架,全面的組件和便捷的工具會讓您信手拈來,如魚得水,下載地址 - https://ext.dcloud.net.cn/plugin?id=1593,具體的安裝使用步驟如下:
main.js
引入uView庫/ main.js import uView from 'uview-ui'; Vue.use(uView);
App.vue
引入基礎樣式(注意style標簽需聲明scss屬性支持)/* App.vue */ <style lang="scss"> @import "uview-ui/index.scss"; </style>
uni.scss
引入全局scss變量文件/* uni.scss */ @import "uview-ui/theme.scss";
pages.json
配置easycom規則(按需引入)// pages.json { "easycom": { // 下載安裝的方式需要前面的"@/",npm安裝的方式無需"@/" // 下載安裝方式 "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" // npm安裝方式 // "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" }, // 此為本身已有的內容 "pages": [ // ...... ] }
基礎體驗:使用 Skeleton 骨架屏組件預顯示占位