H5App、微信小程序开发
启动uniapp项目(已安装vue-cli)
vue create -p dcloudio/uni-preset-vue user-uni-order
目录结构
┌─components //uni-app组件目录
│ └─comp-a.vue //可复用的a组件
├─common // 通用的js&css工具等
├─hybrid //存放本地网页的目录
├─platforms //存放各平台专用页面的目录
├─pages //业务页面文件存放的目录
│ ├─index
│ │ └─components // 页级别组件
│ │ └─vuex // index页面vuex主要存放index的逻辑
│ │ └─index.vue // index页面
├─static //存放应用引用静态资源(如图片、视频等)
│ ├─mp-weixin //条件编译png
│ │ └─a.png
│ │ └─b.png
├─store // 状态统一管理,将各个页面的vuex汇总
├─service // 汇总请求,api等
│ └─api.js // 接口api相关
│ └─config.js // 环境配置
│ └─index.js
│ └─request.js // 网络请求
├─ttcomponents // 头条小程序自定义组件存放目录
├─main.js //Vue初始化入口文件
├─App.vue //应用配置,用来配置App全局样式以及监听
├─manifest.json //配置应用名称、appid、logo、版本等打包信息
└─pages.json //配置页面路由、导航条、选项卡等页面类信息
为了实现多端兼容,综合考虑编译速度、运行性能等因素,uni-app
约定了如下开发规范:
wx
替换为 uni
,Vue.js
规范」,同时补充了App及页面的生命周期onLoad 监听页面加载,主要通过这个获取页面参数 onLoad(option)}{}
,参考示例
onShow 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
onReady 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
onHide 监听页面隐藏
onUnload 监听页面卸载
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。 最好 自己打印出来 看下 所需信息 const pages = getCurrentPages()
uni.navigateTo({ url: 'test?id=1&name=uniapp' });:保留当前页面,跳转到某个页面
uni.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面。
uni.switchTab(OBJECT):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
uni.navigateBack({ delta: 2 });:关闭当前页面,返回上一页面或多级页面.通过 getCurrentPages()
获取当前的页面栈,决定需要返回几层。
触发全局的自定事件:uni.$emit(eventName,OBJECT)
附加参数都会传给监听器回调。
监听全局的自定义事件:uni.$on(eventName,callback)
事件可以由 uni.$emit 触发,回调函数会接收所有传入事件触发函数的额外参数。
uni-app的Storage在不同端的实现不同:
具体操作代码
uni.setStorage({
key: 'storage_key',
data: JSON.stringify(data), // 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象
success: function () {
console.log('success');
}
});
uni.getStorage({
key: 'storage_key',
success: function (res) {
console.log(res.data);
}
});
uni.removeStorage({
key: 'storage_key',
success: function (res) {
console.log('success');
}
});
uni.clearStorage()
Vant UI
安装
npm i vant -S # 通过npm安装vant的H5版本
在main.js中引入
import Vant from 'vant';
Vue.use(Vant);
//对vant进行注册,注意这里没有引入vant的样式文件,在main.js中 引入样式文件会报错,请在App.vue中引入
引入样式库
<style>
@import 'vant/lib/index.css';
</style>
Color UI
为小程序开发的UI样式,在其官网: www.color-ui.com/ 下载UI库文件
将下载的colorui 文件夹复制到我们的项目根目录(注意 是CSS 本版的,犹豫是 H5项目,请不要复制wxss版本)
键盘
uni.hideKeyboard():隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
uni.onKeyboardHeightChange(CALLBACK):监听键盘高度变化
网络状态
uni.getNetworkType(OBJECT):获取网络状态
内存
uni.onMemoryWarning(CALLBACK):监听内存不足事件
剪贴板
uni.setClipboardData(OBJECT):设置系统剪贴板的内容。
uni.getClipboardData(OBJECT):获取系统剪贴板内容。
屏幕
uni.setScreenBrightness(OBJECT):设置屏幕亮度。
uni.getScreenBrightness(OBJECT):获取屏幕亮度
uni.setKeepScreenOn(OBJECT):设置是否保持常亮状态。仅在当前应用生效,离开应用后设置失效。
截屏事件
uni.onUserCaptureScreen(CALLBACK):监听用户主动截屏事件,用户使用系统截屏按键截屏时触发此事件。
手机联系人
uni.addPhoneContact(OBJECT):调用后,用户可以选择将该表单以“新增联系人”或“添加到已有联系人”的方式(APP端目前没有选择步骤,将直接写入),写入手机系统通讯录,完成手机通讯录联系人和联系方式的增加。
App平台提供了更多通讯录相关API,包括读取联系人,详见:https://www.html5plus.org/doc/zh_cn/contacts.html
拨打电话
uni.makePhoneCall(OBJECT):拨打电话。
扫码
uni.scanCode(OBJECT):调起客户端扫码界面,扫码成功后返回对应的结果。
蓝牙
振动
uni.vibrate(OBJECT):使手机发生振动。
uni.vibrateLong(OBJECT):使手机发生较长时间的振动(400ms)。
uni.vibrateShort(OBJECT):使手机发生较短时间的振动(15ms)。
获取第三方服务商
登录
支付
分享
从 github 下载 uni-app 代码块,放到项目目录下的 .vscode 目录即可拥有和 HBuilderX 一样的代码块。
运行
npm run dev:%PLATFORM%
打包
npm run build:%PLATFORM%
%PLATFORM%
可取值如下:
值 | 平台 |
---|---|
h5 | H5 |
mp-alipay | 支付宝小程序 |
mp-baidu | 百度小程序 |
mp-weixin | 微信小程序 |
mp-toutiao | 头条小程序 |
mp-qq | qq 小程序 |
安装包
npm i @dcloudio/uni-helper-json
vscode插件
下载vetur
微信小程序中默认的wxml、wxss,功能有限:
不支持组件化
不能使用less、scss等预编译器
,套用目前的spa框架如vue、react可以解决上述问题,会大大有利于项目的开发,且一套框架可以在微信小程序、支付宝小程序、百度小程序等多端运行。
vue有腾讯开发的wepy,美团开发的mpvue,dcloud开发的uniapp,react有京东开发的Taro,
美团和腾讯的貌似都不怎么好,使用uniapp社区好,功能多,十端一套代码
https://mp.weixin.qq.com/waxmp/home在这里注册成为开发者
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html下载开发者工具
文件处理
把之前的vue web项目的前端代码copy到新项目下
html模版处理
1.标签自动转换
uni-app的标签组件与小程序相同,比如<div>
变成了<view>
,<span>
变成了<text>
。
但uni-app的编译器已经自动处理了这部分转换,如果源码中写了可自动转换的组件,在编译到非H5端时会被自动转换(再编译回到H5端时div还是div)。
2.音频标签
左右、上下滑动切换,有专门的swiper组件,不要使用div模拟
input的search,原来的type没用了,改成confirmtype,
js处理
web中的window、navigator、document等api不可以直接使用,需要替换,具体如下:
window对象:
cookie、session、localstorage改换成uni.storage
Alert、confirm改成uni.showmodal
ajax换成uni.request,也可以使用插件uni.axios等
navigator对象:
geolocation 的定位方式改为 uni.getLocation,
useragent的设备api没有了,改用uni.getSystemInfo
dom对象:
vue中使用双向数据绑定,不需要操作dom
其他api
web中还有canvas、video、audio、websocket、webgl、webbluetooth、webnfc,这些在uni-app中都有专门的API。
生命周期:
uniapp补充了小程序的生命周期,包括app的启动、页面加载等。
vue h5一般在created或者mounted中请求数据,而在uni-app的页面中,使用onLoad或者onShow中请求数据。(组件仍然是created或者mounted)
web端的插件有些不能使用,需要到uniapp插件市场去寻找对应的插件
css处理
uniapp的app、小程序仍然是web-view的形式展示,所以大部分css选择器依然支持
不支持被替换的html标签对应的样式也会自动替换为对应标签
不支持*选择器
https://ask.dcloud.net.cn/article/36174
https://segmentfault.com/a/1190000016614852?utm_source=sf-related
微信小程序主要分为 逻辑层 和 视图层,以及在他们之下的原生部分。逻辑层主要负责 JS 运行,视图层主要负责页面的渲染,它们之间主要通过 Event
和 Data
进行通信,同时通过 JSBridge
调用原生的 API。这也是以微信小程序为首的大多数小程序的架构。
也就是说,只需要在逻辑层调用对应的 App()/Page()
方法,且在方法里面处理 data、提供生命周期/事件函数等,同时在视图层提供对应的模版及样式供渲染就能运行小程序了。这也是大多数小程序开发框架重点考虑和处理的部分。
小程序本质上是运行在 webview 上的一个 H5 应用,代码经过打包后分别运行在 render 线程与 worker 线程,这么做最大的原因是保证平台安全性,不能让开发者控制 render 线程,控制 render 线程将会造成小程序平台方管控困难,比如通过 js dom api 操作 dom 元素,通过 location.href 随意跳转,那整个小程序就完全不可控,可以轻意绕过小程序审核,上线时是个正常小程序,开发者可以随意控制界面上展示的内容或随意跳转到赌博或黄色页面。小程序平台就把 view 与逻辑分离,view 放在 render 线程,提供了一种特殊的语言(微信叫 wxml 、支付宝叫 axml)来写 view,并且不能写入 js 代码,逻辑就放在 worker 线程,由于 worker 并不能操作 dom,所以就解决了上面管控困难的问题,
每个小程序界面有 axml 与 js 文件,js 文件是页面逻辑,逻辑主要做两件事情:
https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/component-plus/
安装
npm i @miniprogram-component-plus/col --save
npm i @miniprogram-component-plus/row --save
开发者工具构建 npm,勾选“使用 npm 模块”
页面 json 文件中加入 usingComponents 字段
{
"usingComponents": {
"mp-col": "@miniprogram-component-plus/col",
"mp-row": "@miniprogram-component-plus/row"
}
}
使用
<view class="page__desc">三列均分布局</view>
<view>
<mp-row>
<mp-col span="{{8}}">
<view>
<view class="col">
</view>
</view>
</mp-col>
<mp-col span="{{8}}">
<view>
<view class="col">
</view>
</view>
</mp-col>
<mp-col span="{{8}}">
<view>
<view class="col">
</view>
</view>
</mp-col>
</mp-row>
</view>
安装
npm install --save threejs-miniprogram
使用
import {createScopedThreejs} from 'threejs-miniprogram'
Page({
onReady() {
wx.createSelectorQuery()
.select('#webgl')
.node()
.exec((res) => {
const canvas = res[0].node
// 创建一个与 canvas 绑定的 three.js
const THREE = createScopedThreejs(canvas)
// 传递并使用 THREE 变量
})
}
})
开发者通过在 app.json subpackages
字段声明项目分包结构
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
subpackages
中,每个分包的配置有以下几项
root: 分包根目录
name:分包别名,分包预下载时可以使用
pages:分包页面路径,相对于分包根目录
independent:分包是否是独立分包
打包原则
subpackages
后,将按 subpackages
配置路径进行打包,subpackages
配置路径外的目录将被打包到主包中subpackage
的根目录不能是另外一个 subpackage
内的子目录tabBar
页面必须在主包内引用原则
packageA
无法 require packageB
JS 文件,但可以 require 主包、packageA
内的 JS 文件;使用 分包异步化 时不受此条限制packageA
无法 import packageB
的 template,但可以 require 主包、packageA
内的 templatepackageA
无法使用 packageB
的资源,但可以使用主包、packageA
内的资源独立分包
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。
一个小程序中可以有多个独立分包。
开发者通过在app.json
的subpackages
字段中对应的分包配置项中定义independent
字段声明对应分包为独立分包
{
"pages": [
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "moduleA",
"pages": [
"pages/rabbit",
"pages/squirrel"
]
}, {
"root": "moduleB",
"pages": [
"pages/pear",
"pages/pineapple"
],
"independent": true
}
]
}
独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。
此外,使用独立分包时要注意:
app.wxss
对独立分包无效,应避免在独立分包页面中使用 app.wxss
中的样式;App
只能在主包内定义,独立分包中不能定义 App
,会造成无法预期的行为;在3大主流渲染引擎里,webview、react native/weex、flutter,复杂度依次降低,渲染性能依次上升。(uni-app是双渲染引擎,webview和weex都内置了,随便开发者使用切换)
flutter作为界面库(注意它只是界面库,dart语言是另一个项目),它唯一要干的事情就是渲染界面。不像HTML5,flutter界面库连视频、定位等都没有,就是一个纯排版引擎,绘制文字、按钮、图片等常用界面控件。这个排版引擎的特点是简单、高性能。提升性能是有代价的,你究竟想要灵活丰富的css3,还是想要固定flex模式排版,抑或是最简单但高性能的flutter排版?开发便利性和运行性能不可兼得。
浏览器的html提供了tag和样式分离的写法,还有各种各样的选择器,但其实这也是有代价的。它导致webview初始化时要同时先启动webkit排版引擎来解析这些编写随性的html、css,同时还要启动一个js引擎比如v8或jscore来解析里面的js。
而dart就很简单,只启动一个dart引擎,解析严格的dart语法,它不会去操心有些标签未闭合要如何容错,不会判断宽度320后面是px还是rem或者是动态计算百分比。
flutter的性能高,除了简单严格,还有一个特点,就是逻辑层与视图层统一,运行在同一套dart虚拟机下。
我们知道rn和weex,也是原生渲染的,它们的性能高于webview。但同为原生渲染的,怎么会慢于flutter呢?其实不是原生渲染慢,而是js和原生通信慢。
rn和weex都采用了独立的js引擎(iOS是jscore,Android是v8,最新版rn开始在Android上搞自己的js引擎Hermes),从js与dart的比较上,性能稍逊一筹。但这不是主要问题,因为v8的jit不是盖的,也是编译为原生代码解析的。性能上的主要问题是,rn、weex的js引擎和原生渲染层是两个运行环境。
当js引擎联网获取到数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,当用户在屏幕上操作原生视图层时,要给js引擎发送通知,也会产生这个通信折损。
webview渲染小程序,为什么性能高,核心是预载。点击一个新页面时,webview是提前创建好的,不会走复杂的webkit、v8的初始化流程,连开发者的js代码,也是预载好的。所以点击新页面时,它的渲染速度和原生应用没什么差别。当然也有个坏处,就是启动慢。微信里启动小程序速度看着还行,其实是微信在启动小程序之前,就已经提前初始化了小程序运行环境。
flutter,在iOS上写一个button,要用CupertinoButton,是iOS风格的控件,在Android上则要用RaisedButton,是Material风格的控件。
rn也是如此,它的官方说法是:learn once,write anywhere。它都不敢说:write once,run anywhere。因为它确实要求开发者写2套代码。
国产Android Rom,根本不是Material风格,很多rom以仿iOS体验为卖点。中国的App,全都是贴近iOS的中性风格,中国的用户换了手机,不管是手机os本身,还是App的使用,都不会造成切换障碍。
rn和flutter这种“跨平台”排版引擎,其跨平台性,对于中国开发者而言,又打了折扣。uni-app默认也是这种通用ui风格。uni-app的开发者只需要写一套界面ui,就可以适应不同手机的用户,真正的 write once,run anywhere。
对于国外的开发者,rn、flutter的生态肯定比uni-app好,比如facebook登陆分享、Google地图等。
但对于国内的开发者,那是反过来的,中国开发者需要的全端推送(UniPush集成了iOS、华为、小米、OPPO等众多原厂推送)、各种国内登陆、支付、分享SDK、各种国内地图、各种ui库、以及Echart图表等,都是在uni-app体系里,这方面生态可比rn、flutter丰富多了。uni-app的插件市场有数千款插件,不能说应有尽有,但确实是最丰富的跨端开发框架生态了。
uni-app的生态还比其他竞品强在如下方面:
这些丰富的生态兼容,是rn和flutter无法享受的。
除了flutter,rn/weex/uni-app都可以动态热更新。
webview、rn/weex,都有一个特点,可以远程动态载入js代码,可以更新本地的js代码。前端开发者认为动态性是天经地义的,但其实flutter并不支持。
rn,要求开发者学习react,要求精通flex布局,要求原生开发协作。
flutter,要求开发者学习dart,了解dart和flutter的API、要求精通flex布局,要求原生开发协作。
uni-app,要求开发者学习vue,了解小程序。
学习成本和难度,直接意味着:开发成本、招聘成本、上线速度、上线风险。
从代码的写法来说,flutter没有tag和样式的说法,更没有选择器,从头到尾只有dart语言,它的界面控件是用dart代码new出来的,每个控件的样式,是在new的时候设置的类json写法的参数。
如果我们要嵌套布局,就要不停的在dart里写child,同时在dart里给child们设样式参数。上面的代码,只是嵌套了1层,实际开发中,dom要嵌套好多层,想象那样的代码。。。所以大家都诟病dart是“嵌套地狱”。
flutter使用的也是flex布局思想,这是一个强嵌套布局模型,比web常规排版引擎的嵌套更多。当界面复杂时,flutter的代码要嵌套几十层,每层的元素的json样式都和元素一起混写在dart代码里,让人崩溃。
或者,你可以这么理解,这是一个只有js,没有html和css的浏览器。你需要用js createElement来创建元素,用js的style方法给每个element设style,反正就是不能写html和css代码。前端都已经发展到各种mvc等视图逻辑分离的架构了,也有了vue组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应dart这种低效的界面开发模式?从开发模式来讲,这确实是一种倒退。
flutter与uni-app的比较:
flutter与uni-app的相对优势:
flutter与uni-app的相对劣势:
rn和uni-app的比较
rn与uni-app的相对优势:
rn与uni-app的相对劣势: