uniapp详解
一、介绍
友情提示,样式引用最后加分号(;)
1、什么是uni-app?
uni-app 是一个使用 Vue.js (opens new window)开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
二、uniapp 初始化相关配置
1、工程目录结构

注意:
- static 下目录的 js 文件不会被 webpack 编译,里面如果存在 es6 的代码不经过转化直接运行,在手机设备上会出现报错
- 所有的 less,scss 等资源同样不要放在 static 目录下,建议这些公共的资料放在 common 目录下
2、应用配置 manifest.json
应用的配置文件,用于指定应用的名称,图标,权限等,我们可以在这里为 Vue 为 H5 设置跨域拦截处理器
3、编译配置 vue.config.js
是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被自动加载,一般用于配置 webpack 等编译选项
4、全局配置 pages.json
注意:结束的那个对象,不能加逗号(,)结束,会出现报错
对 uni-app 进行全局配置,决定页面文件的路径,窗口样式,原生的导航栏,底部的原生 tabbar 等,它类似微信小程序中的 app.json 的页面管理部分

5、全局样式 uni.scss
- 为了方便整体控制应用的风格。比如按键,边框风格,里面预置了一批scss变量预置。
uni-app官方扩展插件(uni ui)及插件市场上很多三方插件均使用了这些样式变量,如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import这个文件),方便用户通过搭积木的方式开发整体风格一致的App。
- 是一个特殊的文件,在代码中无需 import 这个文件即可在scss代码中使用这里的样式变量。uniapp的编译器在 webpack配置中特殊处理了这个 uni.scss ,达到全局可用的效果,如果开发者想要less,stylus的全局使用,需要在 Vue.config.js 中自行配置 webpack 策略
6、condition 启动模式配置
7、uniapp 开发规范及资源路径
1.开发规范约定
-
页面文件向导Vue单文件组件(SFC)规范
-
组件标签靠近小程序规范,详见uni-app 组件规范
-
互连能力(J5 API)靠近微信小程序规范,但需要将替换替换wx为uni详见uni-app接口规范
-
数据绑定及事件处理同Vue.js规范,同时补充了App 和页面的生命周期
-
为兼容多端运行,建议使用 flex 布局进行开发
三、uniapp 生命周期
uniapp 完全支持 Vue 实例的生命周期,同时还新增 应用生命周期 及 页面生命周期
1、应用生命周期
主要在 app.vue运行
| 函数名 | 说明 |
| onLaunch | 当 uni-app 初始化完成时触发 (全局只触发一次) |
| onShow | 当 uni-app 启动,或从后台进入前台显示 |
| onHide | 当 uni-app 从前台进入后台 |
| onError | 当 uni-app 报错时触发 |
| onUniNViewMessage | 当 nvue 页面发送的数据进行监听,可参考 nvue 向 Vue通讯 |
| onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数 |
| onPageNotFound | 页面不存在监听函数(常用) |
| onThemeChange | 监听系统主体变化 |
2、页面生命周期
| 函数名 | 说明 |
| onLoad |
监听页面加载,其参数为上个页面传递的数据,参数类型为0bject〔用于页面传参),参考示例 |
| onShow |
监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 |
| onReady |
监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发 |
| onHide | 监听页面隐藏 |
| onUnload | 监听页面卸载 |
| onResize | 监听窗口尺寸变化 |
| onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新, |
| onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据 |
| onTabItemTap |
点击底部导航栏切换页面(tab) 时触发,参数为0bject,具体见下方注意事项 |
| onShareAppMessage |
用户点击右上角分享,在右上角3个点里面 |
| onPageScroll |
监听页面滚动,参数为0bject |
| onNavigationBarButtonTap |
监听原生标题栏按钮点击事件,参数为Object |
| onBackPress | 监听页面返回 |
| onNavigationBarSearchInputChanged | 监听原生标题栏搜索输入框输入内容变化事件 |
| onNavigationBarSearchInputConfirmed |
监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索"按钮时触发。 |
| onNavigationBarSearchInputClicked |
监听原生标题栏搜索输入框点击事件 |
| onShareTimeIine |
监听用户点击右上角转发到朋友圈 |
| onAddToFavorites |
监听用户点击右上角收藏 |
四、uniapp 路由配置及页面跳转
1、路由的配置
"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、路由的跳转
普通跳转: // 路径:/pages/search/search <navigator url="/pages/search/search"> </navigator> 二级跳转:带参数 // 路径:pages/search/wz/wz <navigator :url="'wz/wz?ids='+e.id"> </navigator>
| 页面栈表现 | 触发时机 | |
|---|---|---|
| 初始化 | 新页面入栈 | uni-app 打开的第一个页面 |
| 打开新页面 | 新页面入栈 | 调用 API uni.navigateTo、 使用组件 <navigator open-type="navigate" /> |
| 页面重定向 | 当前页面出栈,新页面入栈 | 调用 API |
| 页面返回 | 页面不断出栈,直到目标返回页 | 调用 API |
| Tab 切换 | 页面全部出栈,只留下新的 Tab 页面 | 调用 API |
| 重加载 | 页面全部出栈,只留下新的页面 | 调用 API |
3、获取当前页面栈
注意: getCurrentPages() 仅用于展示页面栈的情况,请勿修改页面栈,以免造成页面状态错误。
4、路由传参与接收
说明:页面生命周期的 onLoad()监听页面加载,其参数为上个页面传递的数据,如:
//页面 1 跳转并传递参数 uni.navigateTo({ url: 'page2?name=liy&message=Hello' });
下一个页面的onLoad函数可得到传递的参数。
// 页面 2 接收参数 onLoad: function (option) { //option为object类型,会序列化上个页面传递的参数 console.log(option.name); //打印出上个页面传递的参数。 console.log(option.message); //打印出上个页面传递的参数。 }
5、小程序路由分包配置
所谓的主包,即放置默认启动页面及 TabBar 页面,而分包则是根据 pages.json 的配置进行划分。
// pages:主包 "pages": [{ "path": "pages/index/index", "style": { "navigationBarTitleText": "uni-app", "enablePullDownRefresh": true //允许顶部下拉刷新 } }], // subPackages:分包
根目录新建 subpages 目录存放分包 "subPackages": [ { "root": "news", // 根目录下的文件夹名 "pages": [{ "path": "index", "style": { "navigationBarTitleText": "新闻中心", "navigationBarBackgroundColor": "#FFFFFF", "navigationBarTextStyle": "black", "backgroundColor": "#FFFFFF" } } ] } ... ], // 预下载分包设置 "preloadRule": { "pages/index": { "network": "all", "packages": ["activities"] } }
五、uniapp 常用组件简介
虽然不推荐使用 HTML 标签,但实际上如果开发者写了
div等标签,在编译到非H5平台时也会被编译器转换为view标签,类似的还有span转text、a转navigator等,包括 css 里的元素选择器也会转,但为了管理方便、策略统一,新写代码时仍然建议使用view等组件。
开发者可以通过组合这些基础组件进行快速开发, 基于内置的基础组件,可以开发各种扩展组件,组件规范与vue组件相同。
六、uniapp 常用 API 简介
uni-app的 js 代码,h5 端运行于浏览器中,非 h5 端 Android 平台运行在 v8 引擎中,iOS 平台运行在 iOS 自带的 jscore 引擎中。所以,uni-app
ECMAScript 由 Ecma 国际管理,是基础 js 语法。浏览器基于标准 js 扩充了window、document 等 js API;Node.js 基于标准 js 扩充了 fs 等模块;小程序也基于标准 js 扩展了各种 wx.xx、my.xx、swan.xx 的 API。
标准 ecmascript 的 API 非常多,比如:console、settimeout等等。
非 H5 端,虽然不支持 window、document、navigator 等浏览器的 js API,但也支持标准 ECMAScript。
开发者不要把浏览器里的 js 等价于标准 js。
所以 uni-app 的非 H5 端,一样支持标准 js,支持 if、for 等语法,支持字符串、数组、时间等变量及各种处理方法,仅仅是不支持浏览器专用对象。
1、图片的上传,
uni.chooseImage(): 从本地相册选择图片或使用相机拍照上传。
uni.chooseImage({ count: 1, sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], //从相册选择还是相机 success: res => { //返回图片的本地文件路径列表 console.log(res.tempFilePaths[0]);
//在这里不套定时器不生效 setTimeout(()=>{ uni.pageScrollTo({ // 将页面滚动到目标位置 scrollTop:999999, duration:0, // 间隔时间 success() { // console.log('成功'); }, }) }) } })
七、uniapp 自定义组件与通信
1、自定义组件的概念
组件是
vue技术中非常重要的部分,组件使得与ui相关的轮子可以方便的制造和共享,进而使得vue使用者的开发效率大幅提升,在项目的component目录下存放组件,uni-app只支持vue单文件组件(.vue 组件)
组件可以使用「全局注册」和「页面引入」两种方式进行使用,使用分为三步:
导入
import xxx from 'xxx'注册
Vue.use('xx',xx) 或components:{ xxx }
2、父子组件通信
- 父传子。父组件通过自定义属性向子组件传递数据,子组件通过
props// 父组件 <template> <view class="content"> <chil :msg='title'></chil> </view> </template> <script> export default { data() { return { title: '我是父组件定义的数据信息' } } }, </script> // 子组件 <template> <view class="content"> <view>{{msg}}</view> </view> </template> <script> export default { props:['msg'], data() { return { title: '我是父组件定义的数据信息' } } }, </script>
- 子传父。 父组件通过自定义事件标签向子组件传递事件,子组件通过触发父组件定义事件方式修改父组件数据
// 父组件 <template> <view class="content"> <chil :msg='title' @childEvent="sayHello"></chil> </view> </template> <script> export default { data() { return { title: '我是父组件定义的数据信息' } }, methods: { sayHello(txt){ // 触发事件,把文案,通过自定义事件又传递给子组件 this.title = '子组件跟我通讯了' console.log('获取子组件传递过来的信息',txt); } } }, </script> // 子组件 <template> <view class="content"> <view>{{msg}}</view>
<view>
<button @click="sayHelloToFather">按钮</button>
</view></view> </template> <script> export default { props:['msg'], data() { return { title: '我是父组件定义的数据信息' } }, methods:{ sayHelloToFather(){
// 触发自定义事件 this.$emit('childEvent','我是子组件的数据') } } }, </script>
3、全局事件的定义及通讯 。【uni.$on $ uni.$emit $ uni.$once & uni.$off】
// 【任意组件间通讯】 // 绑定的组件 onLoad() { uni.$on('getInfo',(data)=>{ console.log('任意组件传参',data); }) }, // 触发的组件 methods:{ sayHelloToFather(){ uni.$emit('getInfo','宋') } }
八、Vuex 状态管理
跟 vue 一样
Getter:从状态数据派生数据,相当于 State 的计算属性
Mutation:存储用于同步更改状态数据的方法,默认传入的参数为 state
Action:存储用于异步更改状态数据,但不是直接更改,而是通过触发 Mutation 方法实现,默认参数为context
1、交互关系图

2、模拟用户登入逻辑案例
状态管理(仓库vuex)代码:
// 引入 Vue import Vue from 'vue' // 引入 Vuex import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ actions:{ login(context,userName){ uni.setStorageSync('userName',userName) context.commit('MLOGIN',userName) }, logout(context){ // 清空所有存储的数据 uni.clearStorageSync() context.commit('MLOGOUT') } }, mutations:{ MLOGIN(state, userName){ state.userName = userName }, MLOGOUT(state){ state.userName = '退出状态用户' } }, state:{ //实现固化存储 userName: uni.getStorageSync('userName') ? uni.getStorageSync('userName'):'未登录用户' } })
//在main.js 中注册
// 调用 store vuex 状态管理
import store from '@/store/index.js'
const app = new Vue({
...App,
store
})
组件中代码:
<template>
<view>
<text>通讯录</text>
<view class="">{{userName}}</view>
<view class="">
<button @click="login('宋')">登陆</button>
<button @click="logout">退出</button>
</view>
</view>
</template>
<script>
import {mapState,mapActions} from 'vuex'
export default {
data() {
return {
}
},
computed:{
...mapState(['userName'])
},
methods: {
// ...mapActions(['login']),
...mapActions(['login','logout'])
}
}
</script>
九、运行环境判断与跨端兼容
1、判断是开发环境还是生成环境
在HBuilderX 中,点击「运行」编译出来的代码是开发环境,点击「发行」编译出来的代码是生产环境
// 可以写在任何地方 if(process.env.NODE_ENV === 'development'){ console.log('开发环境') }else{ console.log('生产环境') }
2、判断平台:编译期判断 & 运行期判断两种
- 编译期判断,即条件判断,不同平台在编译出包后已经是不同的代码。了解详情
// #ifdef H5 alert('只有h5平台才有alert方法') // #endif console.log('条件判断');
- 运行期判断是指代码已经打入包中,
switch(uni.getSystemInfoSync().platform){ case 'android': console.log('运行Android上') break; case 'ios': console.log('运行iOS上') break; default: console.log('运行在开发者工具上') break; }
3、跨端兼容
大量写 if else,会造成代码执行性能低下和管理混乱。
编译到不同的工程后二次修改,会让后续升级变的很麻烦。
在 C 语言中,通过 #ifdef、#ifndef 的方式,为 windows、mac 等不同 os 编译不同的代码。
uni-app参考这个思路,为uni-app
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
// 写法:以 #ifdef 或 #ifndef 加%PLATFORM%开头,以#endif 结尾。 // #ifdef H5 alert('你好') // #endif console.log('条件判断');
写法:以 #ifdef 或 #ifndef 加%PLATFORM%开头,以#endif 结尾。
- // #ifdef %PLATFORM%
- // #endif
- %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 | 快应用华为 |
案例:
组件的条件注释:
<!-- #ifdef H5 -->
<view>
h5页面会显示
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view>
微信小程序会显示
</view>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<view>
app会显示
</view>
<!-- #endif -->
api 的条件注释:
onLoad () { //#ifdef MP-WEIXIN console.log('微信小程序') //#endif //#ifdef H5 console.log('h5页面') //#endif }
样式的条件注释:
/* #ifdef H5 */ view{ height: 100px; line-height: 100px; background: red; } /* #endif */ /* #ifdef MP-WEIXIN */ view{ height: 100px; line-height: 100px; background: green; } /* #endif */


浙公网安备 33010602011771号