Uni-app框架(小程序开发)
一、安装以及配置
- 下载Hbuilder X标准版,下载插件,scss/sass编译、uni-app编译、内置浏览器、内置终端。查看更多
- 下载微信开发者工具,安装后,点设置=》安全=》开启服务端口。查看更多
- 登陆微信开发者工具,在微信公众平台上扫码登陆获得测试号的appID
-
第一次使用,需要配置开发工具的相关路径。点击工具栏的运行 -> 运行到小程序模拟器 -> 运行设置,配置相应小程序开发者工具的路径。
-
在HbuilderX打开已有项目,点击运行->运行到小程序模拟器-微信开发者工具,可以同步更新
二、uni-app是什么
- 基于Vue.js开发的前端应用框架
- 开发一套代码,能同时发布到iOS. Android、 H5、以及 各种小程序平台。
-
支持通过npm安装第三方包
三、创建运行以及打包
3.1、创建uni-app
在点击工具栏里的文件 -> 新建 -> 项目:
选择uni-app类型,输入工程名,选择模板,点击创建,即可成功创建。
3.2、运行uni-app
此处只针对微信小程序开发,点击运行->运行到小程序模拟器-微信开发者工具
3.3、打包uni-app
此处只针对微信小程序发布
-
申请微信小程序AppID,参考:微信教程
-
在HBuilderX中顶部菜单依次点击 "发行" => "小程序-微信",输入小程序名称和appid点击发行即可
-
四、框架介绍
4.1、目录结构
┌─components uni-app组件目录
│ └─comp-a.vue 可复用的a组件
├─hybrid 存放本地网页的目录,
详见
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─wxcomponents 存放小程序组件的目录,
详见
├─main.js Vue初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及监听
应用生命周期
├─manifest.json 配置应用名称、appid、logo、版本等打包信息,
详见
└─pages.json 配置页面路由、导航条、选项卡等页面类信息,
详见
4.2、开发规范
为了实现多端兼容,综合考虑编译速度,运行性能等因素,uni-app 约定了如下开发规范:
为兼容多端运行,建议使用 flex 布局进行开发
4.2.1 页面文件向导Vue单文件组件(SFC)规范
.vue
文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue
文件包含三种类型的顶级语言块 <template>
、<script>
和 <style>
,还允许添加可选的自定义块:
<template>
<view>
注意必须有一个view,且只能有一个根view。所有内容写在这个view下面。
</view>
</template>
<script>
export default {
}
</script>
<style>
</style>
-
每个
.vue
文件最多包含一个<template>
块。<template>
内最多包含一个<view>
标签 -
每个
.vue
文件最多包含一个<script>
块。 -
一个
.vue
文件可以包含多个<style>
标签 -
任何匹配
.css
文件 (或通过它的lang
特性指定的扩展名) 的 webpack 规则都将会运用到这个<style>
块的内容中
4.2.2 组件标签靠近小程序规范,详见 uni-app 组件规范
-
<view>
标签在uniapp中的含义与标准html中的<div>
标签能力相当 -
不能直接使用html中的img,你应该使用uniapp的组件标签image
-
<view>
标签的属性是变量时,属性前面需增加:
冒号前缀,属性值仍使用引号包裹,但引号里不是字符串,而是js。
4.2.3 互连能力(JS API)靠近微信小程序规范
- 需要将 wx替换为 uni,详见 uni-app 接口规范
- 自定义后台api,和react项目一样,统一定义
4.2.4 css样式规范
uni-app
支持的通用 css 单位包括 px、rpx
- rpx 即响应式 px,一种根据屏幕宽度自适应的动态单位。以 750 宽的屏幕为基准,750rpx 恰好为屏幕宽度。屏幕变宽,rpx 实际显示效果会等比放大,但在 App(vue2 不含 nvue) 端和 H5(vue2) 端屏幕宽度达到 960px 时,默认将按照 375px 的屏幕宽度进行计算,具体配置参考:rpx 计算配置 。
- 计算公式:
设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
750 * 元素在设计稿中的宽度 / 设计稿基准宽度
五、页面与page.json
pages
- 每次新建页面,均需在
pages.json
中配置pages
列表;未在pages.json -> pages
中配置的页面,uni-app
会在编译阶段进行忽略; - 删除页面时,需做两件工作:删除
.vue
文件;删除pages.json -> pages
列表项中的配置; uni-app
会将pages.json -> pages
配置项中的第一个页面,作为当前工程的首页(启动页)。
tabBar
- tabBar 中的 list 是一个数组,只能配置最少2个、最多5个 tab,tab 按数组的顺序排序;
-
tabbar 的页面展现过一次后就保留在内存中,再次切换 tabbar 页面,只会触发每个页面的onShow,不会再触发onLoad;
-
代码跳转到 tabbar 页面,api只能使用uni.switchTab (opens new window),不能使用uni.navigateTo、uni.redirectTo;
subPackages
-
分包加载配置,此配置为小程序的分包加载机制。
-
微信小程序每个分包的大小是2M,总体积一共不能超过20M。
-
主包放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本
六、vue语法
插值
<template>
<view>
<view>{{ number + 1 }}</view>
<view>{{ ok ? 'YES' : 'NO' }}</view>
<!-- 把一个字符串分割成字符串数组,颠倒其元素的顺序,把数组中的所有元素放入一个字符串 -->
<view>{{ message.split('').reverse().join('') }}</view>
</view>
</template>
<script>
export default {
data() {
return {
number:1,
ok:true,
message: 'Hello Vue!'
}
}
}
</script>
指令
v-bind
- v-bind缩写为‘ : ’
- 可以用修饰符指定不同的绑定类型。
<image v-bind:src="imgUrl"></image>
<!-- 缩写 -->
<image :src="imgUrl"></image>
v-on
v-on 指令,它用于监听 DOM 事件。v-on缩写为‘ @ ’,下文简称为 @事件
v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。
v-html
- App端和H5端支持
v-html
,微信小程序会被转为rich-text
,其他端不支持v-html
。 - 跨端的富文本处理方案详见:富文本/渲染/显示/图文混排方案。rich-text、uparse、v-html的区别 - DCloud问答
条件渲染
v-if和v-else
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy
值的时候被渲染。 使用 v-else
指令来表示 v-if 的“else 块”。
<template>
<view>
<view v-if="type === 'A'">A</view>
<view v-else-if="type === 'B'">
B
</view>
<view v-else-if="type === 'C'">
C
</view>
<view v-else>其他</view>
</view>
</template>
<script>
export default {
data() {
return {
type:'B'
}
}
}
</script>
v-show
v-show
是一个根据条件展示元素选项的指令 。用法大致和 v-if
一样
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的CSS
属性的display
列表渲染
在 v-for 里使用数组
v-for
指令需要使用item in list
形式的特殊语法,其中list
是源数据数组,而item
则是被迭代的数组元素的别名。- 第一个参数
item
则是被迭代的数组元素的别名。 - 第二个参数,即当前项的索引
index
,是可选的。
- 第一个参数
在 v-for 里使用对象
- 第一个参数
value
是被迭代的对象元素的属性值。 - 第二个参数为
property
名称 (也就是键名)。 - 第三个参数作为索引。
<template>
<view>
<view v-for="(arr, name, index) in object">
<view class="name">
{{name}}
</view>
<view v-for="(item, i) in arr">
{{item.label}}:{{item.value}}
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
object: {
title: [
{label: '111', value: '11'}
{label: '222', value: '22'}
],
name: [],
time: []
}
}
}
}
</script>
七、生命周期
5.1、页面生命周期
函数名 | 说明 | 平台差异说明 |
onLoad | 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例 | |
onShow | 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面 | |
onReady | 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发 | |
onHide | 监听页面隐藏 | |
onUnload | 监听页面卸载 | |
onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 |
onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例 | |
onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项 | |
onTabItemTap | 点击 tab 时触发,参数为Object,具体见下方注意事项 | 微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序 |
onShareAppMessage | 用户点击右上角分享 | 微信小程序、QQ小程序、支付宝小程序、字节小程序、飞书小程序、快手小程序、京东小程序 |
onPageScroll | 监听页面滚动,参数为Object | nvue暂不支持 |
onShareTimeline | 监听用户点击右上角转发到朋友圈 | 微信小程序 |
onAddToFavorites | 监听用户点击右上角收藏 | 微信小程序 |
onPullDownRefresh
- 需要在
pages.json
里,找到的当前页面的pages节点,并在style
选项中开启enablePullDownRefresh
。 - 需要在onLoad生命周期内开启
uni.startPullDownRefresh
- 当处理完数据刷新后,
uni.stopPullDownRefresh
可以停止当前页面的下拉刷新。
5.2、组件生命周期
函数名 | 说明 |
onLaunch | 当uni-app初始化完成时触发(局部只触发一次) |
onOpen | 当uni-app启动,或从后台进入前台显示 |
onHide | 当uni-app从前台进入后台 |
onError | 当uni-app报错时触发 |
onUniNViewMessage | 对nvue页面发送的数据进行监听,可参考 nvue 向 vue 通讯 |
onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数(2.8.1+) |
onPageNotFound | 页面不存在监听函数 |
onThemeChange | 监听系统主题变化 |
- 应用生命周期仅可在 App.vue 中监听,在其他页面监听无效。
- onlaunch 里进行页面调整,如遇白屏报错,请参考 https://ask.dcloud.net.cn/article/35942
八、路由
- uni-app页面路由为框架统一管理,开发者需要在pages.json里配置每个路由页面的路径和页面样式。
- uni-app有两种页面路由重定向方式:使用导航器组件扩展,调用API重定向。
页面栈
框架以栈的形式管理当前所有页面,当发生路由切换的时候,页面栈的表现如下:
路由方式 | 页面栈表现 | 触发时机 |
初始化 | 新页面入栈 | uni-app:的第一个页面 |
:新页面 | 新页面入栈 | 调用API uni.navigateTo ,使用组件 <navigator open-type =“ navigate” /> |
页面重启 | 当前页面出栈,新页面入栈 | 调用API uni.redirectTo ,使用组件 <navigator open-type =“ redirectTo” /> |
页面返回 | 页面不断出栈,直到目标返回页 | 调用API uni.navigateBack ,使用组件 <navigator open-type =“ navigateBack” /> ,用户按左上角返回按钮,安卓用户点击物理后退键 |
标签切换 | 页面全部出栈,只留下新的标签页面 | 调用API uni.switchTab ,使用组件 <navigator open-type =“ switchTab” /> ,用户切换Tab |
重加载 | 页面全部出栈,只留下新的页面 | 调用API uni.reLaunch ,使用组件 <navigator open-type =“ reLaunch” /> |
九、组件
scroll-view
可滚动视图区域。用于区域滚动。
性名 | 类型 | 默认值 | 说明 |
scroll-x | Boolean | FALSE | 允许横向滚动 |
scroll-y | Boolean | FALSE | 允许纵向滚动 |
scroll-top | Number/String | 设置竖向滚动条位置 | |
scroll-left | Number/String | 设置横向滚动条位置 | |
scroll-into-view | String | 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 | |
show-scrollbar | Boolean | FALSE | 控制是否出现滚动条 |
refresher-enabled | Boolean | FALSE | 开启自定义下拉刷新 |
refresher-threshold | Number | 45 | 设置自定义下拉刷新阈值 |
refresher-default-style | String | "black" | 设置自定义下拉刷新默认样式,支持设置 black,white,none,none 表示不使用默认样式 |
refresher-background | String | "#FFF" | 设置自定义下拉刷新区域背景颜色 |
refresher-triggered | Boolean | FALSE | 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 |
enable-flex | Boolean | FALSE | 启用 flexbox 布局。开启后,当前节点声明了 display: flex 就会成为 flex container,并作用于其孩子节点。 |
scroll-anchoring | Boolean | FALSE | 开启 scroll anchoring 特性,即控制滚动位置不随内容变化而抖动,仅在 iOS 下生效,安卓下可参考 CSS overflow-anchor 属性。 |
@scrolltoupper | EventHandle | 滚动到顶部/左边,会触发 scrolltoupper 事件 | |
@scrolltolower | EventHandle | 滚动到底部/右边,会触发 scrolltolower 事件 | |
@scroll | EventHandle | 滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY} | |
@refresherpulling | EventHandle | 自定义下拉刷新控件被下拉 | |
@refresherrefresh | EventHandle | 自定义下拉刷新被触发 | |
@refresherrestore | EventHandle | 自定义下拉刷新被复位 | |
@refresherabort | EventHandle | 自定义下拉刷新被中止 |
map
<template>
<map class="page-map" :latitude="latitude" :longitude="longitude" :polygons="polygons"
:polyline="polylines" :markers="markers" scale="11.5" @markertap="tapMarker"
@tap="tapMap" :circles="circles">
<my-callout slot="callout" :points="markers" rich="true"
:cutomContentStyle="cutomContentStyle" :markerDetail="markerDetail">
<!-- <my-callout slot="callout" :points="covers_fanglaopaishui"> -->
</my-callout>
</map>
</template>
<script>
export default {
data() {
return {
polygons: [],
polylines: [],
circles: [],
markers: [],
longitude: 120.0,
latitude: 30.0
}
},
methods: {
tapMarker(){
console.log("点位点击事件")
},
tapMap(){
console.log("地图点击事件")
}
}
}
</script>
地图服务商说明
地图服务商 | App | H5 | 微信小程序 |
高德 | √ | ||
Goolge | 3.4+ | 3.2.10+ | |
腾讯 | √ | √ |
注意
<map>
组件的宽/高推荐写直接量,比如:750rpx,不要设置百分比值。- 谷歌地图使用
wgs84
坐标,其他地图使用gcj02
坐标,用错坐标类型会显示偏移 - 原生map组件没有提供线和面覆盖物的点击事件监听,需要自行处理。多边形判断如下:
//判断是否在多边形内
windingNumber(p, poly) {
var px = p.latitude,
py = p.longitude,
sum = 0
for (var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
var sx = poly[i].latitude,
sy = poly[i].longitude,
tx = poly[j].latitude,
ty = poly[j].longitude
// 点与多边形顶点重合或在多边形的边上
if ((sx - px) * (px - tx) >= 0 && (sy - py) * (py - ty) >= 0 && (px - sx) * (ty - sy) === (py - sy) * (
tx - sx)) {
return 'on'
}
// 点与相邻顶点连线的夹角
var angle = Math.atan2(sy - py, sx - px) - Math.atan2(ty - py, tx - px)
// 确保夹角不超出取值范围(-π 到 π)
if (angle >= Math.PI) {
angle = angle - Math.PI * 2
} else if (angle <= -Math.PI) {
angle = angle + Math.PI * 2
}
sum += angle
}
// 计算回转数并判断点和多边形的几何关系
return Math.round(sum / Math.PI) === 0 ? 'out' : 'in'
}
chart图表
echarts引入
- 引入npm install echarts mpvue-echarts
- ECharts 在线构建 定制 echarts 的 js 文件
- 新建 common 文件夹,将定制文件放在 common 下
- 将node_modules下面的mpvue-echarts->src复制到components,如下图
- 示例如下
<template>
<view>
<view class="echarts-wrap">
<my-echarts id="main" ref="mapChart" :echarts="echarts"
:option="mapOption" v-if="mapOption.series" :onInit="initChart" />
</view>
</view>
</template>
<script>
import * as echarts from '@/common/echarts.min.js';
import myEcharts from '@/components/mpvue-echarts/src/echarts.vue';
export default {
components: {
myEcharts
},
data() {
return {
echarts,
mapOption: {},
}
},
onLoad() {
this.loadOption();
},
methods: {
loadOption(){
this. mapOption = {
throttleTouch: true,
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
}; // ECharts 配置项
},
initChart(canvas, width, height, option) {
console.log('图标', canvas);
let chart = null
chart = echarts.init(canvas, null, {
width: width,
height: height
});
chart.setOption(option);
return chart; // 返回 chart 后可以自动绑定触摸操作
}
}
}
</script>
<style>
.echarts-wrap {
width: 100%;
height: 300px;
}
</style>
常见错误
报错:this.echarts.setCanvasCreator is not a function 的解决办法
这个错误是由于 prors不能传递方法(之前是可以的,不知道是平台的差异还是版本的差异);
解决办法 将echarts.js 直接导入到echarts.vue 中.
还有uni api 有变动 echarts.vue 中有两处需要修改
createCanvasContext() 第二个参数传入当前组建 即this,
createSelectorQuery() 后面加上调用 in(this).
echarts.vue完整代码如下
u-charts引入
- 首先到gitee上把项目代码下载下来,下载地址
- u-charts.js放在common下或者components下
- 使用示例:
<template>
<view class="cw-container">
<canvas canvas-id="canvasLineA" id="canvasLineA" class="charts" width="640"
height="640" @touchstart="touchLineA"></canvas>
</view>
</template>
<script>
import uCharts from '@/components/u-charts/u-charts.js';
var canvaLineA = null;
export default {
data() {
return {
}
},
onLoad(res) {
this.loadData();
},
methods: {
loadData() {
let LineA = {
categories: ['潮汐', '潮汐2', '潮汐3'],
series: []
};
LineA.series = [{ //潮汐
color: "#3296FA",
data: [2,4,54,5]
}, {
color: "#47B024",
data: [2,4,63,2]
}, {
color: "#1E0BFB",
data: [6,4,3,4]
}
];
this.showLineA("canvasLineA", LineA);
},
showLineA(canvasId, chartData) {
canvaLineA = new uCharts({
$this: this,
canvasId: canvasId,
type: 'line',
fontSize: 11,
padding: [15, 1, 0, 10],
legend: {
show: true,
padding: 5,
lineHeight: 11,
margin: 0,
position: 'top',
},
dataLabel: false,
dataPointShape: true,
background: '#FFFFFF',
pixelRatio: 1,
categories: chartData.categories,
series: chartData.series,
animation: true,
xAxis: {
disableGrid: true,
type: 'grid',
gridColor: '#CCCCCC', //竖着的虚线
gridType: 'dash',
dashLength: 8,
// rotateLabel: true,
labelCount: 7,
},
yAxis: {
gridType: 'dash',
gridColor: '#CCCCCC', //横着的虚线
dashLength: 8,
splitNumber: 5,
format: (val) => {
return val.toFixed(0)
}, //左侧数值
min: 0,
max: 10,
},
extra: {
line: {
type: 'curve'
}
}
});
},
touchLineA(e) {
canvaLineA.touchLegend(e);
canvaLineA.showToolTip(e, {
format: function(item, category, key) {
return category + item.name + ':' + item.data
}
});
}
}
}
</script>
<style scoped lang="scss">
.cw-container {
height: 100%;
width: 100%;
background: #F6F6F6;
padding: 16rpx 0;
}
.qiun-charts {
width: 640rpx;
height: 500rpx;
background-color: #FFFFFF;
}
</style>
缺点:功能相对echarts较少
优点:体量小,加载快