
玩转 uniapp 全端开发
玩转 uniapp 全端开发
视频链接
https://www.bilibili.com/video/BV1iG4y167ef/
uniapp 介绍
uni-app
是一个使用 Vue.js (opens new window)开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各
种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
是目前全端开发框架的佼佼者
多端体验
uniapp 优势
uniapp 生态介绍
uniapp项目创建
uniapp 项目开发方式分为两种
- vue-cli (只开 h5端 或者 只开发 微信小程序端)
- HBuilderX 可视化 (多端开发首选 只开发 手机APP)
vue-cli
创建项目
-
全局安装vue-cli
npm install -g @vue/cli@4
-
创建项目
my-project
项目名称vue create -p dcloudio/uni-preset-vue my-project
-
选择模版- 选择默认模版
-
成功
运行项目
npm run dev:平台代号
npm run build:平台代号
值 | 平台 |
---|---|
app-plus | app平台生成打包资源(支持npm run build:app-plus,可用于持续集成。不支持run,运行调试仍需在HBuilderX中操作) |
h5 | H5 |
mp-alipay | 支付宝小程序 |
mp-baidu | 百度小程序 |
mp-weixin | 微信小程序 |
mp-toutiao | 字节跳动小程序 |
mp-lark | 飞书小程序 |
mp-qq | qq 小程序 |
mp-360 | 360 小程序 |
mp-kuaishou | 快手小程序 |
mp-jd | 京东小程序 |
mp-xhs | 小红书小程序 |
quickapp-webview | 快应用(webview) |
quickapp-webview-union | 快应用联盟 |
quickapp-webview-huawei | 快应用华为 |
HBuilderX
如果你要使用uiapp开发多端,那么就必须要选择和它配套的编辑工具了 HBuilderX
。考虑到后期要使用更多的 uniapp的功能,建议提前注册一个uniapp的开发账号。 注册
创建项目
-
新建项目
-
选择项目
-
创建成功
-
编辑器中,敲入
u
+代码 即可调出HBuilderX的代码提示
运行项目
第一次运行,可能需要安装插件,等待即可
uniapp 开发环境搭建
uniapp 是全端开发框架,假如我们想要开发全端,那么首先需要搭建好各个端对应的环境。以下拿比较典型的 微信小程序、H5 和 安卓App来演示。 发布环境的讲解在后续
微信小程序
下载开发者工具
下载安装成功后,会在桌面上显示出来一个图标
注册微信小程序开发者账号
另外 想要开发一款微信小程序,必须要注册微信开发者账号,同时获取对应的appid。
获取appid
打开服务端口
在 HBuilderX 中运行项目
H5
如果使用内置的浏览器预览页面,它是自带跨域的。
同时每一个vue页面中的样式,也是默认自己加上
scoped
的。
运行H5比较简单,只需要电脑上安装好浏览器就行,或者使用 HBuilderX自带内置浏览器也可以
App
由于电脑操作系统限制,我们只演示 android
。
分为两种:
- 运行到模拟器
- 运行到真机
运行到模拟器
安卓模拟器可以自由选择,这里我使用的是 Android studio 内置的模拟器
安装 android studio 模拟器步骤如下:
-
-
打开安装包,然后 勾选上 安装虚拟机
-
打开
Android Studio
-
-
选择要安装的手机型号
-
选择安装对应的安卓系统版本 下载过程比较慢,因为系统镜像比较大
-
下载成功了,回到设备列表页面,运行起来
-
开机
-
成功
-
现在可以回到HBuilderX中来运行项目到模拟器里面了
-
HBuilderX会自动检测你电脑上的模拟器或者真实安卓手机
-
成功
-
运行到真实手机
-
准备一台正常的安卓手机,开启开发人员选项和允许USB调试
-
连接数据线到电脑上 ,如果弹出什么菜单全部点击允许
-
这个时候,重新回到 HBuilderX中,点击运行项目到 App上
-
此时你的手机会弹出窗口,提示你安装软件,最后成功显示
App 调试 模拟器调试
-
运行模拟器
-
运行项目
-
打开webview调试 该选项只能调试页面标签和样式,不能调试js
-
点击调试
-
此时会打开一个页面调试工具,开始调试
-
模拟器上也会跟着发生变化
-
此时可以开启 js调试
-
此时会弹出一个新的窗口 我们可以在这里进行调试
App 真机调试
调试方式和 调试模拟器类似。直接操作即可
uniapp 项目结构介绍
https://uniapp.dcloud.net.cn/tutorial/project.html
┌─uniCloud 云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb
│─components 符合vue组件规范的uni-app组件目录
│ └─comp-a.vue 可复用的a组件
├─hybrid App端存放本地html文件的目录
├─platforms 存放各平台专用页面的目录
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─uni_modules 存放[uni_module](/uni_modules)。
├─wxcomponents 存放小程序组件的目录
├─nativeplugins App原生插件 详见
├─unpackage 非工程代码,一般存放运行或发行的编译结果
├─main.js Vue初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json 配置应用名称、appid、logo、版本等打包信息
├─pages.json 配置页面路由、导航条、选项卡等页面类信息
└─uni.scss 这里是uni-app内置的常用样式变量
uniapp 开发规范介绍
为了实现多端兼容,综合考虑编译速度、运行性能等因素,uni-app
约定了如下开发规范
页面和组件文件遵循vue的规范
- 比如 新建页面
goods.vue
- 比如 新建组件
it-item.vue
内置标签使用小程序的规范
<view>小程序中的块级标签</view>
数据绑定和事件处理使用vue的规范
<template>
<view>
<view class="item" v-for="item in list" :key="item" @click="handleClick(item)">{{item}}</view>
</view>
</template>
<script>
export default {
data(){
return {
list:['a','b','c']
}
},
methods:{
handleClick(letter){
console.log(letter)
}
}
}
</script>
能力接口API 使用 微信小程序的规范
比如弹出显示框,发送网络请求等
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
wx.request({
url: 'example.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
console.log(res.data)
}
})
考虑到跨端,我们将会使用 uniapp
统一封装的API。简称 uni api
uniapp 生命周期
uniapp中,生命周期分类三大类
- 应用生命周期 小程序规范
- 页面生命周期 小程序规范
- 组件生命周期 vue规范
应用生命周期 App.vue
函数名 | 说明 |
---|---|
onLaunch | 当uni-app 初始化完成时触发(全局只触发一次) |
onShow | 当 uni-app 启动,或从后台进入前台显示 |
onHide | 当 uni-app 从前台进入后台 |
onError | 当 uni-app 报错时触发 |
onUniNViewMessage | 对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯(opens new window) |
onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数(2.8.1+) |
onPageNotFound | 页面不存在监听函数 |
onThemeChange | 监听系统主题变化 |
页面生命周期
函数名 | 说明 | 平台差异说明 | 最低版本 |
---|---|---|---|
onInit | 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad | 百度小程序 | 3.1.0+ |
onLoad | 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例 | ||
onShow | 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 | ||
onReady | 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发 | ||
onHide | 监听页面隐藏 | ||
onUnload | 监听页面卸载 | ||
onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 | |
onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例 | ||
onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项 | ||
onTabItemTap | 点击 tab 时触发,参数为Object,具体见下方注意事项 | 微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序 | |
onShareAppMessage | 用户点击右上角分享 | 微信小程序、QQ小程序、支付宝小程序、字节小程序、飞书小程序、快手小程序、京东小程序 | |
onPageScroll | 监听页面滚动,参数为Object | nvue暂不支持 | |
onNavigationBarButtonTap | 监听原生标题栏按钮点击事件,参数为Object | App、H5 | |
onBackPress | 监听页面返回,返回 event = {from:backbutton、 navigateBack} ,backbutton 表示来源是左上角返回按钮或 android 返回键;navigateBack表示来源是 uni.navigateBack ;详细说明及使用:onBackPress 详解 (opens new window)。支付宝小程序只有真机能触发,只能监听非navigateBack引起的返回,不可阻止默认行为。 | app、H5、支付宝小程序 | |
onNavigationBarSearchInputChanged | 监听原生标题栏搜索输入框输入内容变化事件 | App、H5 | 1.6.0 |
onNavigationBarSearchInputConfirmed | 监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。 | App、H5 | 1.6.0 |
onNavigationBarSearchInputClicked | 监听原生标题栏搜索输入框点击事件(pages.json 中的 searchInput 配置 disabled 为 true 时才会触发) | App、H5 | 1.6.0 |
onShareTimeline | 监听用户点击右上角转发到朋友圈 | 微信小程序 | 2.8.1+ |
onAddToFavorites | 监听用户点击右上角收藏 | 微信小程序 | 2.8.1+ |
组件生命周期
函数名 | 说明 | 平台差异说明 | 最低版本 |
beforeCreate | 在实例初始化之前被调用。详见(opens new window) | ||
created | 在实例创建完成后被立即调用。详见(opens new window) | ||
beforeMount | 在挂载开始之前被调用。详见(opens new window) | ||
mounted | 挂载到实例上去之后调用。详见 (opens new window)注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTick Vue官方文档(opens new window) |
||
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。详见(opens new window) | 仅H5平台支持 | |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见(opens new window) | 仅H5平台支持 | |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。详见(opens new window) | ||
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见(opens new window) |
响应式单位 rpx
https://uniapp.dcloud.net.cn/tutorial/syntax-css.html#尺寸单位
相对长度单位,功能类似于web端的 rem 和 vw,小程序首先推出,uniapp也是直接支持。一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。
其中uniapp做了以下设置,
- 默认的设计稿宽度为
375px
因此存在1px = 2rpx
- 默认 rpx支持最大宽度为
960px
,超出则 按照 设计稿宽度375px
来设置
scoped
- vue开发的h5,单页面应用程序,每一个vue文件如果直接使用 class,多个文件的样式 冲突
- 微信小程序 真正 多页面应用程序 物理隔离,页面中使用 class,不会相互影响
- uniapp做了一个设置,写vue代码,不需要主动加上
scoped
,打包成h5端的时候自动添加上去,打包成 微信小程序端 不需要添加 scoped。
uniapp 多端开发
条件编译
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
写法:以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。
- #ifdef:if defined 仅在某平台存在
- #ifndef:if not defined 除了某平台均存在
- %PLATFORM%:平台名称
标签中
<!-- #ifdef %PLATFORM% -->
平台特有的组件
<!-- #endif -->
js中
// #ifdef %PLATFORM%
平台特有的API实现
// #endif
css中
/* #ifdef %PLATFORM% */
平台特有样式
/* #endif */
条件编译写法 | 说明 |
---|---|
#ifdef APP-PLUS 需条件编译的代码 #endif | 仅出现在 App 平台下的代码 |
#ifndef H5 需条件编译的代码 <br />#endif | 除了 H5 平台,其它平台均存在的代码 |
#ifdef H5 || MP-WEIXIN 需条件编译的代码 #endif | 在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集) |
%PLATFORM% 可取值如下:
值 | 生效条件 |
---|---|
VUE3 | HBuilderX 3.2.0+ 详情(opens new window) |
APP-PLUS-NVUE或APP-NVUE | App nvue |
MP-WEIXIN | 微信小程序 |
MP-ALIPAY | 支付宝小程序 |
MP-BAIDU | 百度小程序 |
MP-TOUTIAO | 字节跳动小程序 |
MP-LARK | 飞书小程序 |
MP-QQ | QQ小程序 |
MP-KUAISHOU | 快手小程序 |
MP-JD | 京东小程序 |
MP-360 | 360小程序 |
MP | 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/飞书小程序/QQ小程序/360小程序 |
QUICKAPP-WEBVIEW | 快应用通用(包含联盟、华为) |
QUICKAPP-WEBVIEW-UNION | 快应用联盟 |
QUICKAPP-WEBVIEW-HUAWEI | 快应用华为 |
支持的文件
- .vue
- .js
- .css
- pages.json
- 各预编译语言文件,如:.scss、.less、.stylus、.ts、.pug
static 目录的条件编译
在不同平台,引用的静态资源可能也存在差异,通过 static 的的条件编译可以解决此问题,static 目录下新建不同平台的专有目录(目录名称同 %PLATFORM%
值域,但字母均为小写),专有目录下的静态资源只有在特定平台才会编译进去。
如以下目录结构,a.png
只有在微信小程序平台才会编译进去,b.png
在所有平台都会被编译。
┌─static
│ ├─mp-weixin
│ │ └─a.png
│ └─b.png
├─main.js
├─App.vue
├─manifest.json
└─pages.json
整体目录条件编译
如果想把各平台的页面文件更彻底的分开,也可以在uni-app项目根目录创建platforms
目录,然后在下面进一步创建app-plus
、mp-weixin
等子目录,存放不同平台的文件。
注意
platforms
目录下只支持放置页面文件(即页面vue文件),如果需要对其他资源条件编译建议使用static 目录的条件编译(opens new window)
flex布局
尽量使用flex布局,因为全平台都支持
尺寸单位
- uniapp通用单位
px
,rpx
- vue页面中支持
rem
、vh
、vw
- nvue 不支持
百分比单位
css变量
CSS 变量 | 描述 | App | 小程序 | H5 |
---|---|---|---|---|
--status-bar-height | 系统状态栏高度 | 系统状态栏高度 (opens new window)、nvue 注意见下 | 25px | 0 |
--window-top | 内容区域距离顶部的距离 | 0 | 0 | NavigationBar 的高度 |
--window-bottom | 内容区域距离底部的距离 | 0 | 0 | TabBar 的高度 |
背景图片
-
支持 base64 格式图片。
-
支持网络路径图片。
-
小程序不支持在 css 中使用本地文件。需以 base64 方式方可使用。
-
使用本地路径背景图片需注意:
- 为方便开发者,在背景图片小于 40kb 时,
uni-app
编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; - 本地背景图片的引用路径推荐使用以
~@
开头的绝对路径。
.test2 { background-image: url('~@/static/logo.png'); }
- 为方便开发者,在背景图片小于 40kb 时,
uview & uni ui
uview
和 uni ui
都是 和uniapp配套的全端UI框架,可以单独使用,也可以共同使用
uview ui
由于目前 uview 2.x 版本的坑不少,因此我们拿比较稳定的 uview 1.8.6 来演示
另外,uview ui 的引入方式分为两种,主要是取决于你的项目是如何创建的:
- vue-cli
- HBuilderX
uview ui + vue-cli
-
安装依赖
npm i uview-ui@1.8.4 sass
-
在
src/main.js
文件中 全局引入 js库import uView from "uview-ui"; Vue.use(uView);
-
在 uni.scss 中 引入 uview 的 sass 主题库
@import "uview-ui/theme.scss";
-
在 App.vue 中 引入 uview 的 sass 主题库
<style lang="scss"> @import "uview-ui/index.scss"; </style>
-
pages.json 中 配置 easycom
{ "easycom": { "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" }, // 此为本身已有的内容 "pages": [ // ...... ] }
-
在 页面中 使用 uview的按钮
<u-button >默认按钮</u-button> <u-button type="primary">主要按钮</u-button> <u-button type="success">成功按钮</u-button> <u-button type="info">信息按钮</u-button> <u-button type="warning">警告按钮</u-button> <u-button type="error">危险按钮</u-button>
-
成功
uview ui + HBuilderX
-
点击导入插件
-
导入成功,可以看到目录下多了
components
文件夹 -
接着在
uni.scss
中导入 uview的主题样式文件theme.scss
@import './theme.scss';
-
在页面上添加测试代码
<u-button >默认按钮</u-button> <u-button type="primary">主要按钮</u-button> <u-button type="success">成功按钮</u-button> <u-button type="info">信息按钮</u-button> <u-button type="warning">警告按钮</u-button> <u-button type="error">危险按钮</u-button>
-
点击运行
-
成功
uni ui
uni ui + vue-cli
-
安装相关依赖
如果
node
版本小于 16 ,sass-loader 请使用低于 @11.0.0 的版本如果
node
版本大于 16 ,sass-loader
建议使用v8.x
版本npm i sass sass-loader@10.1.1 @dcloudio/uni-ui
-
配置easycom
在
pages.json
中进行配置{ "easycom": { "autoscan": true, "custom": { // uni-ui 规则如下配置 "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" } }, // 其他内容 pages:[ // ... ] }
-
组件中使用
<uni-title title="上报统计数据"></uni-title> <uni-title type="h1" title="h1 一级标题 "></uni-title> <uni-title type="h1" title="h1 一级标题" color="#027fff"></uni-title> <uni-title type="h2" title="h2 居中" align="center"></uni-title>
uni ui + HBuilderX
-
使用 HBuilderX 导入插件
-
项目中会多
uni_modules
文件夹 -
页面中导入代码
<uni-title title="上报统计数据"></uni-title> <uni-title type="h1" title="h1 一级标题 "></uni-title> <uni-title type="h1" title="h1 一级标题" color="#027fff"></uni-title> <uni-title type="h2" title="h2 居中" align="center"></uni-title>
-
观察效果
uniapp 发布到多端
H5
普通发布
项目开发完成后,可以在 HBuilderX中来 打包成 H5项目
-
打包成H5
-
填写信息
-
此时,生成的h5项目会放在
unpackage\dist\build\h5
发布到uniapp的云环境
需要提前开通 uniCloud 的云服务
微信小程序
在HBuilderX中,想要发布微信小程序,有两种方式
普通发布
-
点击发行微信小程序
-
填写 appid
-
此时会自动打开 微信开发者工具,然后点击上传即可
-
然后填写 版本信息即可
-
成功后,回到微信开发者后台,打开 管理 版本管理 手动点击 提交审核。等待审核
HBuilderX 发布
其实还可以利用 HBuilderX 直接发布,不用打开微信开发者工具
-
首先登录你的微信开发者后台
-
打开 开发管理 小程序代码上传密钥 重置
-
下载 小程序代码上传密钥
-
在企业开发中,记得要开启 IP白名单,降低风险
-
选择上传密钥
-
上传成功
App
在HBuilderX中发布App的方式分为两种
- 本地离线打包
- 云打包
云打包
云打包的意思是利用 dcloud提供的能力,将你本地代码上传到 dcloud 服务器上,在云上打包完成再下载回本地。
-
打开
mainifest.json
设置 uniapp 应用标识AppID
这个是uniapp应用的id,不是微信小程序的id -
设置 App 支持CPU类型
App常用其他设置 支持CPU类型
-
设置使用原生隐私正则提示框
-
发行 - 原生App - 云打包
-
填写相关信息
-
打包成功
uniapp 其他资源
-
uniapp优秀案例源码地址
-
uniapp 官方交流QQ群
玩转 uniapp 全端开发
视频链接
https://www.bilibili.com/video/BV1iG4y167ef/
uniapp 介绍
uni-app
是一个使用 Vue.js (opens new window)开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各
种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
是目前全端开发框架的佼佼者
多端体验
uniapp 优势
uniapp 生态介绍
uniapp项目创建
uniapp 项目开发方式分为两种
- vue-cli (只开 h5端 或者 只开发 微信小程序端)
- HBuilderX 可视化 (多端开发首选 只开发 手机APP)
vue-cli
创建项目
-
全局安装vue-cli
npm install -g @vue/cli@4
-
创建项目
my-project
项目名称vue create -p dcloudio/uni-preset-vue my-project
-
选择模版- 选择默认模版
-
成功
运行项目
npm run dev:平台代号
npm run build:平台代号
值 | 平台 |
---|---|
app-plus | app平台生成打包资源(支持npm run build:app-plus,可用于持续集成。不支持run,运行调试仍需在HBuilderX中操作) |
h5 | H5 |
mp-alipay | 支付宝小程序 |
mp-baidu | 百度小程序 |
mp-weixin | 微信小程序 |
mp-toutiao | 字节跳动小程序 |
mp-lark | 飞书小程序 |
mp-qq | qq 小程序 |
mp-360 | 360 小程序 |
mp-kuaishou | 快手小程序 |
mp-jd | 京东小程序 |
mp-xhs | 小红书小程序 |
quickapp-webview | 快应用(webview) |
quickapp-webview-union | 快应用联盟 |
quickapp-webview-huawei | 快应用华为 |
HBuilderX
如果你要使用uiapp开发多端,那么就必须要选择和它配套的编辑工具了 HBuilderX
。考虑到后期要使用更多的 uniapp的功能,建议提前注册一个uniapp的开发账号。 注册
创建项目
-
新建项目
-
选择项目
-
创建成功
-
编辑器中,敲入
u
+代码 即可调出HBuilderX的代码提示
运行项目
第一次运行,可能需要安装插件,等待即可
uniapp 开发环境搭建
uniapp 是全端开发框架,假如我们想要开发全端,那么首先需要搭建好各个端对应的环境。以下拿比较典型的 微信小程序、H5 和 安卓App来演示。 发布环境的讲解在后续
微信小程序
下载开发者工具
下载安装成功后,会在桌面上显示出来一个图标
注册微信小程序开发者账号
另外 想要开发一款微信小程序,必须要注册微信开发者账号,同时获取对应的appid。
获取appid
打开服务端口
在 HBuilderX 中运行项目
H5
如果使用内置的浏览器预览页面,它是自带跨域的。
同时每一个vue页面中的样式,也是默认自己加上
scoped
的。
运行H5比较简单,只需要电脑上安装好浏览器就行,或者使用 HBuilderX自带内置浏览器也可以
App
由于电脑操作系统限制,我们只演示 android
。
分为两种:
- 运行到模拟器
- 运行到真机
运行到模拟器
安卓模拟器可以自由选择,这里我使用的是 Android studio 内置的模拟器
安装 android studio 模拟器步骤如下:
-
-
打开安装包,然后 勾选上 安装虚拟机
-
打开
Android Studio
-
-
选择要安装的手机型号
-
选择安装对应的安卓系统版本 下载过程比较慢,因为系统镜像比较大
-
下载成功了,回到设备列表页面,运行起来
-
开机
-
成功
-
现在可以回到HBuilderX中来运行项目到模拟器里面了
-
HBuilderX会自动检测你电脑上的模拟器或者真实安卓手机
-
成功
-
运行到真实手机
-
准备一台正常的安卓手机,开启开发人员选项和允许USB调试
-
连接数据线到电脑上 ,如果弹出什么菜单全部点击允许
-
这个时候,重新回到 HBuilderX中,点击运行项目到 App上
-
此时你的手机会弹出窗口,提示你安装软件,最后成功显示
App 调试 模拟器调试
-
运行模拟器
-
运行项目
-
打开webview调试 该选项只能调试页面标签和样式,不能调试js
-
点击调试
-
此时会打开一个页面调试工具,开始调试
-
模拟器上也会跟着发生变化
-
此时可以开启 js调试
-
此时会弹出一个新的窗口 我们可以在这里进行调试
App 真机调试
调试方式和 调试模拟器类似。直接操作即可
uniapp 项目结构介绍
https://uniapp.dcloud.net.cn/tutorial/project.html
┌─uniCloud 云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb
│─components 符合vue组件规范的uni-app组件目录
│ └─comp-a.vue 可复用的a组件
├─hybrid App端存放本地html文件的目录
├─platforms 存放各平台专用页面的目录
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─uni_modules 存放[uni_module](/uni_modules)。
├─wxcomponents 存放小程序组件的目录
├─nativeplugins App原生插件 详见
├─unpackage 非工程代码,一般存放运行或发行的编译结果
├─main.js Vue初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json 配置应用名称、appid、logo、版本等打包信息
├─pages.json 配置页面路由、导航条、选项卡等页面类信息
└─uni.scss 这里是uni-app内置的常用样式变量
uniapp 开发规范介绍
为了实现多端兼容,综合考虑编译速度、运行性能等因素,uni-app
约定了如下开发规范
页面和组件文件遵循vue的规范
- 比如 新建页面
goods.vue
- 比如 新建组件
it-item.vue
内置标签使用小程序的规范
<view>小程序中的块级标签</view>
数据绑定和事件处理使用vue的规范
<template>
<view>
<view class="item" v-for="item in list" :key="item" @click="handleClick(item)">{{item}}</view>
</view>
</template>
<script>
export default {
data(){
return {
list:['a','b','c']
}
},
methods:{
handleClick(letter){
console.log(letter)
}
}
}
</script>
能力接口API 使用 微信小程序的规范
比如弹出显示框,发送网络请求等
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000
})
wx.request({
url: 'example.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
console.log(res.data)
}
})
考虑到跨端,我们将会使用 uniapp
统一封装的API。简称 uni api
uniapp 生命周期
uniapp中,生命周期分类三大类
- 应用生命周期 小程序规范
- 页面生命周期 小程序规范
- 组件生命周期 vue规范
应用生命周期 App.vue
函数名 | 说明 |
---|---|
onLaunch | 当uni-app 初始化完成时触发(全局只触发一次) |
onShow | 当 uni-app 启动,或从后台进入前台显示 |
onHide | 当 uni-app 从前台进入后台 |
onError | 当 uni-app 报错时触发 |
onUniNViewMessage | 对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯(opens new window) |
onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数(2.8.1+) |
onPageNotFound | 页面不存在监听函数 |
onThemeChange | 监听系统主题变化 |
页面生命周期
函数名 | 说明 | 平台差异说明 | 最低版本 |
---|---|---|---|
onInit | 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad | 百度小程序 | 3.1.0+ |
onLoad | 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例 | ||
onShow | 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 | ||
onReady | 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发 | ||
onHide | 监听页面隐藏 | ||
onUnload | 监听页面卸载 | ||
onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 | |
onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例 | ||
onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项 | ||
onTabItemTap | 点击 tab 时触发,参数为Object,具体见下方注意事项 | 微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序 | |
onShareAppMessage | 用户点击右上角分享 | 微信小程序、QQ小程序、支付宝小程序、字节小程序、飞书小程序、快手小程序、京东小程序 | |
onPageScroll | 监听页面滚动,参数为Object | nvue暂不支持 | |
onNavigationBarButtonTap | 监听原生标题栏按钮点击事件,参数为Object | App、H5 | |
onBackPress | 监听页面返回,返回 event = {from:backbutton、 navigateBack} ,backbutton 表示来源是左上角返回按钮或 android 返回键;navigateBack表示来源是 uni.navigateBack ;详细说明及使用:onBackPress 详解 (opens new window)。支付宝小程序只有真机能触发,只能监听非navigateBack引起的返回,不可阻止默认行为。 | app、H5、支付宝小程序 | |
onNavigationBarSearchInputChanged | 监听原生标题栏搜索输入框输入内容变化事件 | App、H5 | 1.6.0 |
onNavigationBarSearchInputConfirmed | 监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。 | App、H5 | 1.6.0 |
onNavigationBarSearchInputClicked | 监听原生标题栏搜索输入框点击事件(pages.json 中的 searchInput 配置 disabled 为 true 时才会触发) | App、H5 | 1.6.0 |
onShareTimeline | 监听用户点击右上角转发到朋友圈 | 微信小程序 | 2.8.1+ |
onAddToFavorites | 监听用户点击右上角收藏 | 微信小程序 | 2.8.1+ |
组件生命周期
函数名 | 说明 | 平台差异说明 | 最低版本 |
beforeCreate | 在实例初始化之前被调用。详见(opens new window) | ||
created | 在实例创建完成后被立即调用。详见(opens new window) | ||
beforeMount | 在挂载开始之前被调用。详见(opens new window) | ||
mounted | 挂载到实例上去之后调用。详见 (opens new window)注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTick Vue官方文档(opens new window) |
||
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。详见(opens new window) | 仅H5平台支持 | |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见(opens new window) | 仅H5平台支持 | |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。详见(opens new window) | ||
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见(opens new window) |
响应式单位 rpx
https://uniapp.dcloud.net.cn/tutorial/syntax-css.html#尺寸单位
相对长度单位,功能类似于web端的 rem 和 vw,小程序首先推出,uniapp也是直接支持。一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。
其中uniapp做了以下设置,
- 默认的设计稿宽度为
375px
因此存在1px = 2rpx
- 默认 rpx支持最大宽度为
960px
,超出则 按照 设计稿宽度375px
来设置
scoped
- vue开发的h5,单页面应用程序,每一个vue文件如果直接使用 class,多个文件的样式 冲突
- 微信小程序 真正 多页面应用程序 物理隔离,页面中使用 class,不会相互影响
- uniapp做了一个设置,写vue代码,不需要主动加上
scoped
,打包成h5端的时候自动添加上去,打包成 微信小程序端 不需要添加 scoped。
uniapp 多端开发
条件编译
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
写法:以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。
- #ifdef:if defined 仅在某平台存在
- #ifndef:if not defined 除了某平台均存在
- %PLATFORM%:平台名称
标签中
<!-- #ifdef %PLATFORM% -->
平台特有的组件
<!-- #endif -->
js中
// #ifdef %PLATFORM%
平台特有的API实现
// #endif
css中
/* #ifdef %PLATFORM% */
平台特有样式
/* #endif */
条件编译写法 | 说明 |
---|---|
#ifdef APP-PLUS 需条件编译的代码 #endif | 仅出现在 App 平台下的代码 |
#ifndef H5 需条件编译的代码 <br />#endif | 除了 H5 平台,其它平台均存在的代码 |
#ifdef H5 || MP-WEIXIN 需条件编译的代码 #endif | 在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集) |
%PLATFORM% 可取值如下:
值 | 生效条件 |
---|---|
VUE3 | HBuilderX 3.2.0+ 详情(opens new window) |
APP-PLUS-NVUE或APP-NVUE | App nvue |
MP-WEIXIN | 微信小程序 |
MP-ALIPAY | 支付宝小程序 |
MP-BAIDU | 百度小程序 |
MP-TOUTIAO | 字节跳动小程序 |
MP-LARK | 飞书小程序 |
MP-QQ | QQ小程序 |
MP-KUAISHOU | 快手小程序 |
MP-JD | 京东小程序 |
MP-360 | 360小程序 |
MP | 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/飞书小程序/QQ小程序/360小程序 |
QUICKAPP-WEBVIEW | 快应用通用(包含联盟、华为) |
QUICKAPP-WEBVIEW-UNION | 快应用联盟 |
QUICKAPP-WEBVIEW-HUAWEI | 快应用华为 |
支持的文件
- .vue
- .js
- .css
- pages.json
- 各预编译语言文件,如:.scss、.less、.stylus、.ts、.pug
static 目录的条件编译
在不同平台,引用的静态资源可能也存在差异,通过 static 的的条件编译可以解决此问题,static 目录下新建不同平台的专有目录(目录名称同 %PLATFORM%
值域,但字母均为小写),专有目录下的静态资源只有在特定平台才会编译进去。
如以下目录结构,a.png
只有在微信小程序平台才会编译进去,b.png
在所有平台都会被编译。
┌─static
│ ├─mp-weixin
│ │ └─a.png
│ └─b.png
├─main.js
├─App.vue
├─manifest.json
└─pages.json
整体目录条件编译
如果想把各平台的页面文件更彻底的分开,也可以在uni-app项目根目录创建platforms
目录,然后在下面进一步创建app-plus
、mp-weixin
等子目录,存放不同平台的文件。
注意
platforms
目录下只支持放置页面文件(即页面vue文件),如果需要对其他资源条件编译建议使用static 目录的条件编译(opens new window)
flex布局
尽量使用flex布局,因为全平台都支持
尺寸单位
- uniapp通用单位
px
,rpx
- vue页面中支持
rem
、vh
、vw
- nvue 不支持
百分比单位
css变量
CSS 变量 | 描述 | App | 小程序 | H5 |
---|---|---|---|---|
--status-bar-height | 系统状态栏高度 | 系统状态栏高度 (opens new window)、nvue 注意见下 | 25px | 0 |
--window-top | 内容区域距离顶部的距离 | 0 | 0 | NavigationBar 的高度 |
--window-bottom | 内容区域距离底部的距离 | 0 | 0 | TabBar 的高度 |
背景图片
-
支持 base64 格式图片。
-
支持网络路径图片。
-
小程序不支持在 css 中使用本地文件。需以 base64 方式方可使用。
-
使用本地路径背景图片需注意:
- 为方便开发者,在背景图片小于 40kb 时,
uni-app
编译到不支持本地背景图的平台时,会自动将其转化为 base64 格式; - 本地背景图片的引用路径推荐使用以
~@
开头的绝对路径。
.test2 { background-image: url('~@/static/logo.png'); }
- 为方便开发者,在背景图片小于 40kb 时,
uview & uni ui
uview
和 uni ui
都是 和uniapp配套的全端UI框架,可以单独使用,也可以共同使用
uview ui
由于目前 uview 2.x 版本的坑不少,因此我们拿比较稳定的 uview 1.8.6 来演示
另外,uview ui 的引入方式分为两种,主要是取决于你的项目是如何创建的:
- vue-cli
- HBuilderX
uview ui + vue-cli
-
安装依赖
npm i uview-ui@1.8.4 sass
-
在
src/main.js
文件中 全局引入 js库import uView from "uview-ui"; Vue.use(uView);
-
在 uni.scss 中 引入 uview 的 sass 主题库
@import "uview-ui/theme.scss";
-
在 App.vue 中 引入 uview 的 sass 主题库
<style lang="scss"> @import "uview-ui/index.scss"; </style>
-
pages.json 中 配置 easycom
{ "easycom": { "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" }, // 此为本身已有的内容 "pages": [ // ...... ] }
-
在 页面中 使用 uview的按钮
<u-button >默认按钮</u-button> <u-button type="primary">主要按钮</u-button> <u-button type="success">成功按钮</u-button> <u-button type="info">信息按钮</u-button> <u-button type="warning">警告按钮</u-button> <u-button type="error">危险按钮</u-button>
-
成功
uview ui + HBuilderX
-
点击导入插件
-
导入成功,可以看到目录下多了
components
文件夹 -
接着在
uni.scss
中导入 uview的主题样式文件theme.scss
@import './theme.scss';
-
在页面上添加测试代码
<u-button >默认按钮</u-button> <u-button type="primary">主要按钮</u-button> <u-button type="success">成功按钮</u-button> <u-button type="info">信息按钮</u-button> <u-button type="warning">警告按钮</u-button> <u-button type="error">危险按钮</u-button>
-
点击运行
-
成功
uni ui
uni ui + vue-cli
-
安装相关依赖
如果
node
版本小于 16 ,sass-loader 请使用低于 @11.0.0 的版本如果
node
版本大于 16 ,sass-loader
建议使用v8.x
版本npm i sass sass-loader@10.1.1 @dcloudio/uni-ui
-
配置easycom
在
pages.json
中进行配置{ "easycom": { "autoscan": true, "custom": { // uni-ui 规则如下配置 "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" } }, // 其他内容 pages:[ // ... ] }
-
组件中使用
<uni-title title="上报统计数据"></uni-title> <uni-title type="h1" title="h1 一级标题 "></uni-title> <uni-title type="h1" title="h1 一级标题" color="#027fff"></uni-title> <uni-title type="h2" title="h2 居中" align="center"></uni-title>
uni ui + HBuilderX
-
使用 HBuilderX 导入插件
-
项目中会多
uni_modules
文件夹 -
页面中导入代码
<uni-title title="上报统计数据"></uni-title> <uni-title type="h1" title="h1 一级标题 "></uni-title> <uni-title type="h1" title="h1 一级标题" color="#027fff"></uni-title> <uni-title type="h2" title="h2 居中" align="center"></uni-title>
-
观察效果
uniapp 发布到多端
H5
普通发布
项目开发完成后,可以在 HBuilderX中来 打包成 H5项目
-
打包成H5
-
填写信息
-
此时,生成的h5项目会放在
unpackage\dist\build\h5
发布到uniapp的云环境
需要提前开通 uniCloud 的云服务
微信小程序
在HBuilderX中,想要发布微信小程序,有两种方式
普通发布
-
点击发行微信小程序
-
填写 appid
-
此时会自动打开 微信开发者工具,然后点击上传即可
-
然后填写 版本信息即可
-
成功后,回到微信开发者后台,打开 管理 版本管理 手动点击 提交审核。等待审核
HBuilderX 发布
其实还可以利用 HBuilderX 直接发布,不用打开微信开发者工具
-
首先登录你的微信开发者后台
-
打开 开发管理 小程序代码上传密钥 重置
-
下载 小程序代码上传密钥
-
在企业开发中,记得要开启 IP白名单,降低风险
-
选择上传密钥
-
上传成功
App
在HBuilderX中发布App的方式分为两种
- 本地离线打包
- 云打包
云打包
云打包的意思是利用 dcloud提供的能力,将你本地代码上传到 dcloud 服务器上,在云上打包完成再下载回本地。
-
打开
mainifest.json
设置 uniapp 应用标识AppID
这个是uniapp应用的id,不是微信小程序的id -
设置 App 支持CPU类型
App常用其他设置 支持CPU类型
-
设置使用原生隐私正则提示框
-
发行 - 原生App - 云打包
-
填写相关信息
-
打包成功
uniapp 其他资源
-
uniapp优秀案例源码地址
-
uniapp 官方交流QQ群

androidPrivacy message 文字完全看不见
{
"version" : "1",
"prompt" : "template",
"title" : "服务协议和隐私政策",
"message" : "请你务必审慎阅读、充分理解'服务协议'和'隐私政策'各条款,包括但不限于:为了更好的向你提供服务,我们需要访问你的相册、录屏、位置信息等。<br/>你可阅读<a href=\"https://static-13d7-a5f8-a9ad47a0edd4.bspapp.com/h5/user.html\">《服务协议》</a>和<a href=\"https://static-13de18e3f8-a9ad47a0edd4.bspapp.com/h5/provacy.html\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面同意按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"styles" : {
"backgroundColor" : "#ffffff",
"borderRadius" : "5px",
"title" : {
"color" : "#333333"
},
"buttonAccept" : {
"color" : "#333333"
},
"buttonRefuse" : {
"color" : "#9B9AB5"
},
"message":{
"color" : "#333333"
}
}
}
{
"version" : "1",
"prompt" : "template",
"title" : "服务协议和隐私政策",
"message" : "请你务必审慎阅读、充分理解'服务协议'和'隐私政策'各条款,包括但不限于:为了更好的向你提供服务,我们需要访问你的相册、录屏、位置信息等。<br/>你可阅读<a href=\"https://static-13d7-a5f8-a9ad47a0edd4.bspapp.com/h5/user.html\">《服务协议》</a>和<a href=\"https://static-13de18e3f8-a9ad47a0edd4.bspapp.com/h5/provacy.html\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面同意按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"styles" : {
"backgroundColor" : "#ffffff",
"borderRadius" : "5px",
"title" : {
"color" : "#333333"
},
"buttonAccept" : {
"color" : "#333333"
},
"buttonRefuse" : {
"color" : "#9B9AB5"
},
"message":{
"color" : "#333333"
}
}
}

安卓检查升级及安装包下载进度
代码来源
另:极力推荐官方的upgrade-center https://uniapp.dcloud.io/uniCloud/upgrade-center,非常方便
App.vue中的代码,负责检测
<script>
import { serverUrl } from '@/util/http'
export default {
globalData: {
title: '管理系统',
ver: 101,
},
onLaunch: function() {
console.log('App Launch')
this.checkVer()
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
},
methods: {
checkVer: function() {
uni.getSystemInfo({
success: (res) => {
console.log(res.platform);
//检测当前平台,如果是安卓则启动安卓更新
if (res.platform == "android") {
this.AndroidCheckUpdate();
}
}
})
},
AndroidCheckUpdate: function() {
var _this = this;
uni.request({
url: serverUrl + '/check-ver',
method: 'GET',
data: {},
success: res => {
console.log('res', res.data.data)
const data = res.data.data
const ver = data.ver
const downUrl = data.url
if (ver > this.globalData.ver) {
uni.showToast({
title: '有新的版本发布,程序已启动自动更新。新版本下载完成后将自动弹出安装程序。',
mask: true,
duration: 5000,
icon: "none"
});
var prg = 0;
var dtask = plus.downloader.createDownload(downUrl, {}, function(d, status) {
// 下载完成
if (status == 200) {
plus.runtime.install(plus.io.convertLocalFileSystemURL(d.filename), {}, {}, function(
error) {
uni.showToast({
title: '安装失败',
mask: false,
duration: 1500
});
})
} else {
uni.showToast({
title: '更新失败',
mask: false,
duration: 1500
});
}
});
dtask.start();
var showLoading = plus.nativeUI.showWaiting("正在下载");
dtask.addEventListener('statechanged', function(task, status) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
showLoading.setTitle("正在下载");
break;
case 2:
showLoading.setTitle("已连接到服务器");
break;
case 3:
prg = parseInt(
(parseFloat(task.downloadedSize) /
parseFloat(task.totalSize)) *
100
);
showLoading.setTitle("版本更新,正在下载" + prg + "% ");
break;
case 4:
plus.nativeUI.closeWaiting();
//下载完成
break;
}
});
}
},
fail: () => {},
complete: () => {}
});
},
}
}
</script>
服务器响应的代码
返回内容
{code: 0, message: '', data: {ver: 102, url: 'http://...com/file_102.apk'}}
代码来源
另:极力推荐官方的upgrade-center https://uniapp.dcloud.io/uniCloud/upgrade-center,非常方便
App.vue中的代码,负责检测
<script>
import { serverUrl } from '@/util/http'
export default {
globalData: {
title: '管理系统',
ver: 101,
},
onLaunch: function() {
console.log('App Launch')
this.checkVer()
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
},
methods: {
checkVer: function() {
uni.getSystemInfo({
success: (res) => {
console.log(res.platform);
//检测当前平台,如果是安卓则启动安卓更新
if (res.platform == "android") {
this.AndroidCheckUpdate();
}
}
})
},
AndroidCheckUpdate: function() {
var _this = this;
uni.request({
url: serverUrl + '/check-ver',
method: 'GET',
data: {},
success: res => {
console.log('res', res.data.data)
const data = res.data.data
const ver = data.ver
const downUrl = data.url
if (ver > this.globalData.ver) {
uni.showToast({
title: '有新的版本发布,程序已启动自动更新。新版本下载完成后将自动弹出安装程序。',
mask: true,
duration: 5000,
icon: "none"
});
var prg = 0;
var dtask = plus.downloader.createDownload(downUrl, {}, function(d, status) {
// 下载完成
if (status == 200) {
plus.runtime.install(plus.io.convertLocalFileSystemURL(d.filename), {}, {}, function(
error) {
uni.showToast({
title: '安装失败',
mask: false,
duration: 1500
});
})
} else {
uni.showToast({
title: '更新失败',
mask: false,
duration: 1500
});
}
});
dtask.start();
var showLoading = plus.nativeUI.showWaiting("正在下载");
dtask.addEventListener('statechanged', function(task, status) {
// 给下载任务设置一个监听 并根据状态 做操作
switch (task.state) {
case 1:
showLoading.setTitle("正在下载");
break;
case 2:
showLoading.setTitle("已连接到服务器");
break;
case 3:
prg = parseInt(
(parseFloat(task.downloadedSize) /
parseFloat(task.totalSize)) *
100
);
showLoading.setTitle("版本更新,正在下载" + prg + "% ");
break;
case 4:
plus.nativeUI.closeWaiting();
//下载完成
break;
}
});
}
},
fail: () => {},
complete: () => {}
});
},
}
}
</script>
服务器响应的代码
返回内容
{code: 0, message: '', data: {ver: 102, url: 'http://...com/file_102.apk'}}
收起阅读 »

App微信登录{"errcode":40029,"errmsg":"invalid code, rid: 6306ee95-187a67c0-5f5d2ec7"}
uni.login 获取 code 去后台换取 openid,这个操作一定不要放在 app.vue 的 onLaunch 里面,否则一直报错{"errcode":40029,"errmsg":"invalid code, rid: 6306ee95-187a67c0-5f5d2ec7"},浪费一上午时间,虽然不知道原因。
uni.login 获取 code 去后台换取 openid,这个操作一定不要放在 app.vue 的 onLaunch 里面,否则一直报错{"errcode":40029,"errmsg":"invalid code, rid: 6306ee95-187a67c0-5f5d2ec7"},浪费一上午时间,虽然不知道原因。
收起阅读 »
未配置appkey在模拟器需要重启设备才能生效
用了模拟器,测试了几十次,实在没办法查了下apk签名发现一致,然后重启下了设备(不重启清理设备缓存)就可以了,浪费了三个小时!
用了模拟器,测试了几十次,实在没办法查了下apk签名发现一致,然后重启下了设备(不重启清理设备缓存)就可以了,浪费了三个小时!

项目简要 uniapp框架会员移动网页客户端
项目简要
uniapp框架会员移动网页客户端
工作要求
- 增加功能, 优化和长期维护.
- 迁移 uniapp vue2 到 vue3.
开发者要求:
全职独立开发者, 谢绝团队.
至少2年 uniapp 项目开发经验.
至少1年 typescript 项目开发经验.
熟悉或使用过 thorui 优先.
有 迁移 uniapp vue2 到 vue3 的项目经验优先
使用过Gitflow
具备英文读写能力.
三,待遇:
- 基本底薪,月结 (考虑到接任何项目如果想提升代码质量,都需要熟悉,需要能优化,模块化代码)
- 底薪之外,按页面和功能付钱,多劳多得.
- 联系方式微信18872319732 邮箱xuqu911@126.com
项目简要
uniapp框架会员移动网页客户端
工作要求
- 增加功能, 优化和长期维护.
- 迁移 uniapp vue2 到 vue3.
开发者要求:
全职独立开发者, 谢绝团队.
至少2年 uniapp 项目开发经验.
至少1年 typescript 项目开发经验.
熟悉或使用过 thorui 优先.
有 迁移 uniapp vue2 到 vue3 的项目经验优先
使用过Gitflow
具备英文读写能力.
三,待遇:
- 基本底薪,月结 (考虑到接任何项目如果想提升代码质量,都需要熟悉,需要能优化,模块化代码)
- 底薪之外,按页面和功能付钱,多劳多得.
- 联系方式微信18872319732 邮箱xuqu911@126.com

阿里云的全部ip名单,可用于需要固定ip的服务
阿里云的ip是不固定的,但是是有限的,下面我给大家总结了全部的ip,直接复制到需要固定ip的地方(比如公众号开发以及微信支付开发),就可以使用
"106.55.29.200",
"120.231.66.200",
"120.239.43.174",
"39.103.221.6",
"8.142.75.1",
"8.142.83.203",
"39.99.151.148",
"8.142.31.50",
"39.103.228.214",
"8.142.86.138",
"8.142.108.54",
"39.103.144.175",
"8.142.44.148",
"8.142.94.233",
"8.142.87.84",
"39.103.202.108",
"121.89.199.46",
"8.142.93.173",
"8.142.99.25",
"8.142.85.206",
"39.101.204.97",
"39.99.157.94",
"39.101.167.155",
"8.142.88.23",
"8.142.47.50",
"8.142.179.15",
"39.103.193.98",
"8.142.138.9",
"121.89.212.145",
"8.142.87.158",
"39.101.201.16",
"39.101.182.192",
"8.142.42.137",
"39.99.132.159",
"39.99.137.216",
"8.142.22.15",
"8.142.95.141",
"39.99.251.65",
"39.101.129.61",
"39.99.250.2",
"39.101.173.37",
"39.101.142.99",
"121.89.193.70",
"39.99.240.217",
"39.99.146.78",
"39.99.132.65",
"39.101.191.40",
"8.142.67.254",
"8.142.80.242",
"8.142.81.80",
"8.142.32.185",
"8.142.87.23",
"8.142.72.42",
"8.142.77.108",
"39.101.244.65",
"8.142.40.226",
"39.103.148.233",
"8.142.173.109",
"39.103.145.49",
"8.142.95.18",
"8.142.176.18",
"8.142.98.127",
"39.101.141.231",
"121.89.197.154",
"39.101.197.200",
"8.142.81.141",
"8.142.138.201",
"39.101.164.90",
"8.142.171.162",
"39.103.161.119",
"39.103.152.225",
"121.89.222.174",
"39.103.183.106",
"8.142.9.24",
"39.99.234.169",
"39.103.165.245",
"8.142.94.109",
"39.103.212.201",
"8.142.178.207",
"39.103.222.215",
"121.89.205.102",
"39.99.246.77",
"121.89.247.104",
"39.98.109.221",
"39.101.190.159",
"121.89.210.4",
"8.142.178.97",
"39.99.134.234",
"8.142.79.219",
"8.142.132.52",
"8.142.178.7",
"39.103.157.151",
"39.99.144.235",
"8.142.95.241",
"39.103.146.215",
"39.101.167.224",
"39.101.195.123",
"8.142.178.156",
"8.142.47.165",
"39.101.189.210",
"8.142.8.54",
"39.101.128.177",
"8.142.137.190",
"8.142.112.255",
"8.142.38.212",
"8.142.34.149",
"39.103.189.27",
"8.142.177.67",
"39.99.242.182",
"39.103.191.229",
"39.101.151.72",
"39.99.137.10",
"39.101.180.174",
"39.101.194.204",
"8.142.175.108",
"39.99.225.246",
"39.103.175.44",
"121.89.216.225",
"8.142.102.247",
"39.103.193.188",
"8.142.81.253",
"39.103.169.76",
"8.142.139.61",
"8.142.129.165",
"39.103.153.141",
"39.98.123.208",
"39.103.187.241",
"121.89.192.168",
"8.142.104.215",
"8.142.112.199",
"39.103.235.149",
"8.142.108.16",
"39.101.198.114",
"8.142.130.158",
"8.142.28.178",
"8.142.122.80",
"8.142.100.107",
"8.142.33.161",
"8.142.124.208",
"8.142.70.82",
"8.142.69.207",
"39.103.226.236",
"8.142.104.109",
"8.142.201.83",
"8.142.245.139",
"8.142.201.94",
"8.142.242.43",
"8.142.242.29",
"8.142.241.195",
"8.142.207.222",
"8.142.201.77",
"8.142.245.236",
"8.142.251.249",
"8.142.252.124",
"8.142.201.62",
"8.142.242.188",
"8.142.234.66",
"8.142.252.80"
阿里云的ip是不固定的,但是是有限的,下面我给大家总结了全部的ip,直接复制到需要固定ip的地方(比如公众号开发以及微信支付开发),就可以使用
"106.55.29.200",
"120.231.66.200",
"120.239.43.174",
"39.103.221.6",
"8.142.75.1",
"8.142.83.203",
"39.99.151.148",
"8.142.31.50",
"39.103.228.214",
"8.142.86.138",
"8.142.108.54",
"39.103.144.175",
"8.142.44.148",
"8.142.94.233",
"8.142.87.84",
"39.103.202.108",
"121.89.199.46",
"8.142.93.173",
"8.142.99.25",
"8.142.85.206",
"39.101.204.97",
"39.99.157.94",
"39.101.167.155",
"8.142.88.23",
"8.142.47.50",
"8.142.179.15",
"39.103.193.98",
"8.142.138.9",
"121.89.212.145",
"8.142.87.158",
"39.101.201.16",
"39.101.182.192",
"8.142.42.137",
"39.99.132.159",
"39.99.137.216",
"8.142.22.15",
"8.142.95.141",
"39.99.251.65",
"39.101.129.61",
"39.99.250.2",
"39.101.173.37",
"39.101.142.99",
"121.89.193.70",
"39.99.240.217",
"39.99.146.78",
"39.99.132.65",
"39.101.191.40",
"8.142.67.254",
"8.142.80.242",
"8.142.81.80",
"8.142.32.185",
"8.142.87.23",
"8.142.72.42",
"8.142.77.108",
"39.101.244.65",
"8.142.40.226",
"39.103.148.233",
"8.142.173.109",
"39.103.145.49",
"8.142.95.18",
"8.142.176.18",
"8.142.98.127",
"39.101.141.231",
"121.89.197.154",
"39.101.197.200",
"8.142.81.141",
"8.142.138.201",
"39.101.164.90",
"8.142.171.162",
"39.103.161.119",
"39.103.152.225",
"121.89.222.174",
"39.103.183.106",
"8.142.9.24",
"39.99.234.169",
"39.103.165.245",
"8.142.94.109",
"39.103.212.201",
"8.142.178.207",
"39.103.222.215",
"121.89.205.102",
"39.99.246.77",
"121.89.247.104",
"39.98.109.221",
"39.101.190.159",
"121.89.210.4",
"8.142.178.97",
"39.99.134.234",
"8.142.79.219",
"8.142.132.52",
"8.142.178.7",
"39.103.157.151",
"39.99.144.235",
"8.142.95.241",
"39.103.146.215",
"39.101.167.224",
"39.101.195.123",
"8.142.178.156",
"8.142.47.165",
"39.101.189.210",
"8.142.8.54",
"39.101.128.177",
"8.142.137.190",
"8.142.112.255",
"8.142.38.212",
"8.142.34.149",
"39.103.189.27",
"8.142.177.67",
"39.99.242.182",
"39.103.191.229",
"39.101.151.72",
"39.99.137.10",
"39.101.180.174",
"39.101.194.204",
"8.142.175.108",
"39.99.225.246",
"39.103.175.44",
"121.89.216.225",
"8.142.102.247",
"39.103.193.188",
"8.142.81.253",
"39.103.169.76",
"8.142.139.61",
"8.142.129.165",
"39.103.153.141",
"39.98.123.208",
"39.103.187.241",
"121.89.192.168",
"8.142.104.215",
"8.142.112.199",
"39.103.235.149",
"8.142.108.16",
"39.101.198.114",
"8.142.130.158",
"8.142.28.178",
"8.142.122.80",
"8.142.100.107",
"8.142.33.161",
"8.142.124.208",
"8.142.70.82",
"8.142.69.207",
"39.103.226.236",
"8.142.104.109",
"8.142.201.83",
"8.142.245.139",
"8.142.201.94",
"8.142.242.43",
"8.142.242.29",
"8.142.241.195",
"8.142.207.222",
"8.142.201.77",
"8.142.245.236",
"8.142.251.249",
"8.142.252.124",
"8.142.201.62",
"8.142.242.188",
"8.142.234.66",
"8.142.252.80"
收起阅读 »

关于数组去重和获取重复元素的数组
var arr=[1,2,3,4,3,5,4,6,7,2,1,4];
var newArr=[];
for (let i = 0; i < arr.length; i++) {
// let num=0;
for (let j = i+1; j < arr.length; j++) {
if(arr[i]==arr[j]){
// num++
arr.splice(j,1);//去重
}
}
if(num==1){//这里用num==1来做判断的好处,用倒数第二个元素作参考,打印出重复的元素。不会出现多次打印相同的重复元素,表现了打印出结果的唯一性。
newArr.push(arr[i]);
console.log("重复元素:"+arr[i])
}
num=0;
if(num>=1&&arr.indexOf(arr[i])==i){
console.log("重复元素:"+arr[i]+",重复次数:"+num)//打印出重复元素的次数
}
}
var arr=[1,2,3,4,3,5,4,6,7,2,1,4];
var newArr=[];
for (let i = 0; i < arr.length; i++) {
// let num=0;
for (let j = i+1; j < arr.length; j++) {
if(arr[i]==arr[j]){
// num++
arr.splice(j,1);//去重
}
}
if(num==1){//这里用num==1来做判断的好处,用倒数第二个元素作参考,打印出重复的元素。不会出现多次打印相同的重复元素,表现了打印出结果的唯一性。
newArr.push(arr[i]);
console.log("重复元素:"+arr[i])
}
num=0;
if(num>=1&&arr.indexOf(arr[i])==i){
console.log("重复元素:"+arr[i]+",重复次数:"+num)//打印出重复元素的次数
}
}

后台保活、不保证所有场景下有效(ios)
后台保活、不保证所有场景下有效(ios) :https://ext.dcloud.net.cn/plugin?id=9118
后台保活、不保证所有场景下有效(ios) :https://ext.dcloud.net.cn/plugin?id=9118