一. 初始uni-app
是使用 Vue.js 開發所有前端應用的框架,開發者編寫一套代碼,可發佈到iOS、Android、H5、以及各種小程序(微信/支付寶/百度/頭條/QQ/釘釘)等多個平臺。
1. 開發環境搭建,nodejs,hbuilderx
2. 應用開發流程
2.1 DCloud開發者中心註冊賬號並創建應用,獲取AppID,去註冊
2.2 創建uniapp項目
2.3 按照規範編寫源代碼
├── api # 所有請求
├── assets # 主題 字體等靜態資源
├── common # 全局通用工具類
├── components # 全局公用組件
├── language # 國際化 language
├── store # 全局 store管理
├── pages # views 所有頁面
├── ├── index # 視圖模塊名
├── ├── ├── index.vue # 模塊入口頁面
├── static # 存放應用引用靜態資源(如圖片、視頻等)的目錄
├── wxcomponents # 小程序組件的目錄
├── App.vue # 入口頁面,應用配置,配置App全局樣式以及監聽
├── main.js # 入口文件 加載組件 初始化等
├── package.json # package.json
├── manifest.json # 配置應用名稱、appid、logo、版本等打包信息
└── pages.json # 配置頁面路由、導航條、選項卡等頁面類信息
2.4 應用調試運行
2.5 應用發佈
- 雲打包
- IOS離線打包:https://ask.dcloud.net.cn/article/41
- Android離線打包:https://ask.dcloud.net.cn/article/508
二. 知識點梳理
1. 應用生命週期
<script>
export default {
// 當uniapp初始化完成時進行觸發,全局只觸發一次
onLaunch: function() {
console.log('App Launch')
},
// 當uniapp啓動或者從後臺進入前臺顯示
onShow: function() {
console.log('App Show')
},
// 當uniapp從前臺進入後臺
onHide: function() {
console.log('App Hide')
}
}
</script>
2. 頁面生命週期
<script>
export default {
onLoad(option) {}, // 監聽頁面加載,option爲上個頁面傳遞的數據,參數類型爲Object
onReady() {}, // 監聽頁面初次渲染完成
onShow() {}, // 監聽頁面顯示。頁面每次出現在屏幕上都觸發
onHide() {}, // 監聽頁面隱藏
onUnload() {}, // 監聽頁面卸載
onResize() {}, // 監聽窗口尺寸變化
onPullDownRefresh() {},
onReachBottom() {},
onTabItemTap() {}
}
</script>
注意:
(1)不要在選項屬性或回調上使用箭頭函數,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因爲箭頭函數是和父級上下文綁定在一起的,this 不會是如你做預期的 Vue 實例,且 this.a 或 this.myMethod 也會是未定義的。
(2)建議使用 uni-app 的 onReady代替 vue 的 mounted。
(3)建議使用 uni-app 的 onLoad 代替 vue 的 created。
3. 頁面路由配置及跳轉
需要在pages.json裏配置每個路由頁面的路徑及頁面樣式,類似小程序在app.json中配置頁面路由一樣。
{
"pages": [ //pages數組中第一項表示應用啓動頁
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首頁", // 導航標題
"navigationBarBackgroundColor": "#F8F8F8", // 導航背景顏色
"navigationBarTextStyle": "black", // 導航字體顏色
"enablePullDownRefresh": true, // 下拉刷新
"app-plus": { // App節點配置項
"titleNView": {},
"animationType": "fade-in",
"animationDuration": 300
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black", // 導航字體顏色
"navigationBarTitleText": "uni-app", // 導航標題
"navigationBarBackgroundColor": "#F8F8F8", // 導航背景顏色
"backgroundColor": "#F8F8F8" // 頁面背景顏色
},
"tabBar": {
"color": "#333333",
"borderStyle": "black",
"backgroundColor": "#FFFFFF",
"selectedColor": "#333333",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "",
"selectedIconPath": "",
"text": "首頁"
},
{
"pagePath": "pages/my/my",
"iconPath": "",
"selectedIconPath": "",
"text": "我的"
}
]
}
}
1、初始化
2、打開新頁面
uni.navigateTo 、 <navigator open-type="navigate"/>
3、頁面重定向
uni.redirectTo 、 <navigator open-type="redirectTo"/>
4、頁面返回
uni.navigateBack 、<navigator open-type="navigateBack"/> 、用戶按左上角返回按鈕、安卓用戶點擊物理back按鍵
5、Tab 切換
uni.switchTab 、 <navigator open-type="switchTab"/> 、用戶切換 Tab
6、重加載
uni.reLaunch 、<navigator open-type="reLaunch"/>
注意:
(1)navigateTo, redirectTo 只能打開非 tabBar 頁面。
(2)switchTab 只能打開 tabBar 頁面。
(3)reLaunch 可以打開任意頁面。
(4)頁面底部的 tabBar 由頁面配置決定,即只要是定義爲 tabBar 的頁面,底部都有 tabBar。
(5)不能在 App.vue 裏面進行頁面跳轉。
4. 頁面佈局
爲支持跨平臺,框架建議使用Flex佈局
Flex 佈局教程:語法篇
Flex 佈局教程:實例篇
5. 字體圖標
uni-app 支持使用字體圖標,使用方式與普通 web 項目相同,需要注意以下幾點:
- 支持 base64 格式字體圖標。
- 支持網絡路徑字體圖標。
- 網絡路徑必須加協議頭 https。
- 從 http://www.iconfont.cn 上拷貝的代碼,默認是沒加協議頭的。
@font-face {
font-family: test1-icon;
src: url('~@/static/iconfont.ttf');
}
6. 基礎組件
- 視圖容器:view,scroll-view,swiper
- 基礎內容:icon,text,rich-text,progress
- 表單組件:button,check-box,form,input,textarea,picker,radio,switch
- 導航:navigator
- 媒體組件:audio,camera,image,video
- 地圖:map
- 畫布:canvas
- webview:web-view
- 廣告:ad
- 開放能力組件:
- App nvue 專用組件:list,recycle-list
- 擴展組件:uni-ui
7. 應用配置
manifest.json 文件是應用的配置文件,用於指定應用的名稱、圖標、權限等。
三. 進階知識點
1. 條件編譯
條件編譯是裏用特殊的註釋作爲標記,在編譯時根據這些特殊的註釋,將註釋裏面的代碼編譯到不同平臺。
- API 的條件編譯
// #ifdef %PLATFORM%
平臺特有的API實現
// #endif
說明:
以 #ifdef 或 #ifndef 加** %PLATFORM%** 開頭,以 #endif 結尾。
%PLATFORM%:APP-PLUS,APP-PLUS-NVUE,H5,MP-WEIXIN...
- 組件的條件編譯
<template>
<view class="content">
// #ifdef MP-WEIXIN
<page-loading></page-loading>
// #endif
</view>
</template>
- 樣式的條件編譯
<style lang="scss">
/* #ifdef MP-WEIXIN */
.wx-bg-login {
background-color:#11ff11;
}
/* #endif */
</style>
- pages.json 的條件編譯
// #ifdef MP-WEIXIN
{
"path": "pages/speech/speech",
"style": {
"navigationBarTitleText": "語音識別"
}
}
// #endif
- static 目錄的條件編譯
┌─static
│ ├─mp-weixin
│ │ └─a.png
│ └─b.png
├─main.js
├─App.vue
├─manifest.json
└─pages.json
2. vuex使用
import Vue from 'vue'
import Vuex from 'vuex'
import api from '@/api'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
language: uni.getStorageSync('language') || 0,
isLogin: !!uni.getStorageSync('isLogin'),
loginInfo: {},
userInfo: {}
},
mutations: {
// 語言信息
SET_LANGUAGE: (state, value) => {
state.language = value
},
// 用戶登錄
SET_LOGIN: (state, value) => {
state.isLogin = value
},
// 用戶登錄信息
SET_LOGININFO: (state, value) => {
state.loginInfo = value
},
// 用戶信息
SET_USERINFO: (state, value) => {
state.userInfo = value
}
},
actions: {
// 設置語言信息
SetLanguage({
dispatch,
commit
}, value) {
uni.setStorageSync('language', value);
commit('SET_LANGUAGE', value);
dispatch('SetLang', value);
},
// 用戶登錄
Login({
dispatch,
commit
}, data) {
return new Promise((resolve, reject) => {
api.login(data).then(response => {
if (response.status === 1) {
uni.setStorageSync('loginInfo', response.data);
uni.setStorageSync('isLogin', true);
dispatch('ParseLoginInfo');
}
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// 獲取用戶信息
GetUserInfo({
dispatch,
commit
}) {
return new Promise((resolve, reject) => {
api.getUserInfo(this.state.loginInfo.mobile).then(response => {
if (response.status === 1) {
uni.setStorageSync('userInfo', response.data);
dispatch('ParseUserInfo');
}
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// 解析登錄信息
ParseLoginInfo({
dispatch,
commit
}) {
const loginInfo = uni.getStorageSync('loginInfo') || {};
commit('SET_LOGININFO', loginInfo);
commit('SET_LOGIN', Object.keys(loginInfo).length > 0);
dispatch('ParseUserInfo');
},
// 解析用戶信息
ParseUserInfo({
dispatch,
commit
}) {
const userInfo = uni.getStorageSync('userInfo') || {};
commit('SET_USERINFO', userInfo);
},
// 退出登錄
Logout({
dispatch,
commit
}) {
uni.clearStorageSync();
}
}
})
export default store
3. npm支持
uni-app支持使用npm安裝第三方包。
4. 小程序組件支持
uni-app 支持在 App 和 小程序 中使用小程序自定義組件,從HBuilderX2.4.7起,H5端也可以運行微信小程序組件。
平臺 | 支持情況 | 小程序組件存放目錄 |
---|---|---|
H5 | 支持微信小程序組件(2.4.7+) | wxcomponents |
App(不含nvue | 支持微信小程序組件 | wxcomponents |
微信小程序 | 支持微信小程序組件 | wxcomponents |
支付寶小程序 | 支持支付寶小程序組件 | mycomponents |
百度小程序 | 支持百度小程序組件 | swancomponents |
頭條小程序 | 支持頭條小程序組件 | ttcomponents |
QQ小程序 | 支持QQ小程序組件 | wxcomponents |
┌─wxcomponents 微信小程序自定義組件存放目錄
│ └──custom 微信小程序自定義組件
│ ├─index.js
│ ├─index.wxml
│ ├─index.json
│ └─index.wxss
├─mycomponents 支付寶小程序自定義組件存放目錄
│ └──custom 支付寶小程序自定義組件
│ ├─index.js
│ ├─index.axml
│ ├─index.json
│ └─index.wxss
├─swancomponents 百度小程序自定義組件存放目錄
│ └──custom 百度小程序自定義組件
│ ├─index.js
│ ├─index.swan
│ ├─index.json
│ └─index.wxss
├─pages
│ └─index
│ └─index.vue
│
├─static
├─main.js
├─App.vue
├─manifest.json
└─pages.json
在 pages.json 對應頁面的 style -> usingComponents 引入組件:
{
"pages": [
{
"path": "index/index",
"style": {
"usingComponents": {
// #ifdef APP-PLUS || MP-WEIXIN || MP-QQ
"custom": "/wxcomponents/custom/index"
// #endif
// #ifdef MP-BAIDU
"custom": "/swancomponents/custom/index"
// #endif
// #ifdef MP-ALIPAY
"custom": "/mycomponents/custom/index"
// #endif
}
}
}
]
}
5. 使用nvue
uni-app在App端,支持vue頁面和nvue頁面混搭、互相跳轉。也支持純nvue項目。
四. 注意事項
1. data 屬性
data 必須聲明爲返回一個初始數據對象的函數;否則頁面關閉時,數據不會自動銷燬,再次打開該頁面時,會顯示上次數據。
//正確用法,使用函數返回對象
data() {
return {
title: 'Hello'
}
}
//錯誤寫法,會導致再次打開頁面時,顯示上次數據
data: {
title: 'Hello'
}
2. 全局變量
- 公用模塊封裝
- globalData
小程序中有個globalData概念,可以在 App 上聲明全局變量。 Vue 之前是沒有這類概念的,但 uni-app 引入了globalData概念,並且在包括H5、App等平臺都實現了。
在 App.vue 可以定義 globalData ,也可以使用 API 讀寫這個值。
globalData支持vue和nvue共享數據。
globalData是一種比較簡單的全局變量使用方式。
<script>
export default {
globalData: {
text: 'text'
},
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每個頁面公共css */
</style>
js中操作globalData的方式如下:
賦值:getApp().globalData.text = ‘test’
取值:console.log(getApp().globalData.text)
如果需要把globalData的數據綁定到頁面上,可在頁面的onshow聲明週期裏進行變量重賦值。HBuilderX 2.0.3起,nvue頁面在uni-app編譯模式下,也支持onshow。
- Vuex
3. Class 與 Style 綁定
- class 支持的語法:
<view :class="{ active: isActive }">111</view>
<view class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }">222</view>
<view class="static" :class="[activeClass, errorClass]">333</view>
<view class="static" v-bind:class="[isActive ? activeClass : '', errorClass]">444</view>
<view class="static" v-bind:class="[{ active: isActive }, errorClass]">555</view>
- style 支持的語法:
<view v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">666</view>
<view v-bind:style="[{ color: activeColor, fontSize: fontSize + 'px' }]">777</view>
非H5端不支持 Vue官方文檔:Class 與 Style 綁定 中的 classObject 和 styleObject 語法。
<template>
<view :class="[activeClass]" :style="[baseStyles,overridingStyles]"></view>
</template>
<script>
export default {
data() {
return {
activeClass: {
'active': true,
'text-danger': false
},
baseStyles: {
color: 'green',
fontSize: '30px'
},
overridingStyles: {
'font-weight': 'bold'
}
}
}
}
</script>
注意:以:style=""這樣的方式設置px像素值,其值爲實際像素,不會被編譯器轉換。
此外還可以用 computed 方法生成 class 或者 style 字符串,插入到頁面中,舉例說明:
<template>
<!-- 支持 -->
<view class="container" :class="computedClassStr"></view>
<view class="container" :class="{active: isActive}"></view>
<!-- 不支持 -->
<view class="container" :class="computedClassObject"></view>
</template>
<script>
export default {
data () {
return {
isActive: true
}
},
computed: {
computedClassStr () {
return this.isActive ? 'active' : ''
},
computedClassObject () {
return { active: this.isActive }
}
}
}
</script>
用在組件上
非H5端暫不支持在自定義組件上使用 Class 與 Style 綁定
4. 列表循環
在H5平臺 使用 v-for 循環整數時和其他平臺存在差異,
- 如 v-for="(item, index) in 10" 中,在H5平臺 item 從 1 開始,其他平臺 item 從 0 開始,可使用第二個參數 index 來保持一致。
- 在非H5平臺 循環對象時不支持第三個參數,如 v-for="(value, name, index) in object" 中,index 參數是不支持的。
5. 事件處理器
// 常用事件映射表,左側爲 WEB 事件,右側爲 ``uni-app`` 對應事件
{
click: 'tap',
touchstart: 'touchstart',
touchmove: 'touchmove',
touchcancel: 'touchcancel',
touchend: 'touchend',
tap: 'tap',
longtap: 'longtap', //推薦使用longpress代替
input: 'input',
change: 'change',
submit: 'submit',
blur: 'blur',
focus: 'focus',
reset: 'reset',
confirm: 'confirm',
scroll: 'scroll'
}
- 爲兼容各端,事件需使用 v-on 或 @ 的方式綁定,請勿使用小程序端的bind 和 catch 進行事件綁定。
- 若需要禁止蒙版下的頁面滾動,可使用
@touchmove.stop.prevent="moveHandle"
,moveHandle 可以用來處理 touchmove 的事件,也可以是一個空函數。
-<view class="mask" @touchmove.stop.prevent="moveHandle"></view>
- v-html指令
App端(vue頁面V3編譯模式)和H5端支持v-html,其他端不支持v-html。
跨端的富文本處理方案詳見:https://ask.dcloud.net.cn/article/35772
五. 消息推送-UniPush
UniPush是DCloud聯合個推公司推出的集成型統一推送服務,內建了蘋果、華爲、小米、OPPO、VIVO、魅族等手機廠商的系統級推送和個推等第三方推送。
1. 推送平臺開通
2. 模塊權限配置
3. 廠商推送設置
4. 主要代碼
// 初始化推送
initPush() {
// #ifdef APP-PLUS
let _self = this;
// 點擊狀態欄消息
plus.push.addEventListener('click', function(msg) {
// 收到消息點擊邏輯處理,跳轉頁面
}, false);
// receive事件
plus.push.addEventListener('receive', function(msg) {
_self.createLocalPushMsg(msg); //創建本地消息
}, false);
// #endif
},
//創建本地消息
createLocalPushMsg(msg) {
if (msg.payload === 'LocalMSG') {
return;
}
let options = {
cover: false
};
plus.push.createMessage(msg.content, 'LocalMSG', options);
},
4. 獲取clidentid
plus.push.getClientInfo().clientid
六. 開放生態
- uni-app插件市場,有數千款插件,支持前端組件、js sdk、頁面模板、項目模板、原生插件等多種類型
- 兼容微信小程序 JS SDK,豐富的小程序生態內容可直接引入uni-app,並且在App通用
- 兼容微信小程序自定義組件,並且App通用
- 支持 mpvue 項目及組件,全端通用
- 支持 NPM 包管理系統
- 圖表uCharts
- 豐富樣式庫ColorUI
- 官方UI組件庫uni-ui