目录
- 简介
- 新建项目并运行
- 开发页面
一、uniapp简介和项目搭建
1.1 uniapp 简介
-
概念:uniapp是一款开发跨平台前端应用的框架,基于vue。
-
特点
- 跨平台:只需要开发一套代码,就可以进行编译并运行在h5、各种小程序、ios、安卓平台上。跨平台是uniapp在基于vue开发代码后会根据要运行的平台进行源代码编译,编译成对应平台能够运行的代码并使用。
- 对vue友好的语法:为了实现跨平台,uniapp是自己封装了一整套页面和交互代码的语法,但是语法类似vue。所以对vue开发者就比较友好。
-
使用
- Hbuilder自带uniapp的支持。
-
版本
- uniapp针对于vue2 和vue3分别提供了版本支持,选择项目合适的版本进行开发。具体版本选择会在新建项目时就选择vue 的版本
1.2 uniapp开发工具:Hbuilder
-
Hbuilder和uniapp是同一家公司开发的,Hbuilder天生支持uniapp,并内置了各个平台的运行环境(部分环境需要额外下载工具,比如小程序)
-
特点
- 内置了uniapp以及其运行环境
- 公司有丰富的Hbuilder插件库(类似于vscode的扩展库)
-
下载:官网下载最新稳定版。免安装,下载解压可用
1.3 搭建和启动uniapp项目
1.3.1 新建uniapp项目
-
项目版本选择
1.3.2 运行项目
-
先选择要运行的平台,进行运行。
-
h5:点击工具栏中
运行->·运行到浏览器 -
小程序
-
点击工具栏中
运行->·
运行到微信开发工具- 编译完成后如果开启了微信开发工具的服务端口就会自动打开工具并启动项目
-
-
运行在安卓或ios平台
-
根据ios或安卓来进行不同的运行配置
- 安卓:通过use数据线连接手机和电脑,并且拥有操作手机文件的权限,运行后,在Hbuilder的运行选择手机中的安卓基座打开,当手机和电脑成功后再hbuilder的弹窗中会有对应的设备可选择,选择后Hbuilder会自动进行编译成
.apk文件并自动在手机上进行安装,用户就可以在手机上查看效果 - ios:需要提前在苹果的开发者中心网站申请开发者证书,申请下来后才可以在苹果手机上进行真机测试。
- 安卓:通过use数据线连接手机和电脑,并且拥有操作手机文件的权限,运行后,在Hbuilder的运行选择手机中的安卓基座打开,当手机和电脑成功后再hbuilder的弹窗中会有对应的设备可选择,选择后Hbuilder会自动进行编译成
-
-
1.4 项目文件夹架构
-
项目文件夹架构
-- pages: 包含了项目的所有页面,每个页面都是独立的文件夹,以及一个同名的.vue文件 -- static:包含了项目使用的所有静态资源。比如图片、视频等 App.vue:作为项目的根组件,也是项目的启动页面,但是该vue文件一般不会作为页面来使用,更多的是作为全局的js执行的文件,以及页面的公共样式 index.html:整个项目打包后的成品html文件。只针对于h5平台 main.js:作为项目的启动入口js文件,包含了vue2 和Vue3的启动代码 mainfest.json:当前项目针对各个平台的配置json文件 pages.json:项目的核心配置文件。包含了页面的配置以及全局导航栏、tabbar等相关配置,基本开发过程中的配置代码都会放在该json文件中。 uni.scss:全局的scss文件
二、uniapp页面开发
2.1 新建页面
-
在项目的pages文件夹右击->新建页面
2.2 页面开发
2.2.1 页面标签
-
概念:uniapp基于原生微信小程序的标签语法,自己封装了一套页面的组件用于构建页面。
-
常用的uniapp组件
- view:等同于一个
div - scroll-view:等同于带有滚动条的div
- image:相当于一个
img标签 - text:相当于一个
span标签 - swiper:轮播图组件
- input:等同于
input - button:按钮
- picker:等同于弹出式
select标签
- view:等同于一个
2.2.2 样式的处理
-
使用css
- uniapp默认支持css
- uniapp推荐使用class选择器
- 不推荐id
- 不能使用标签选择器
-
sass需要单独安装才能使用
-
需要下载sass插件后才能在vue文件里使用scss
-
安装后使用
<style lang="scss">scss代码</style>
-
2.2.3 页面布局
-
一般布局模式
-
尽量采用弹性布局。单位就是使用平时的css单位(rem、百分百、vw、vh)。
-
官方推荐使用rpx作为布局的单位
- rpx是微信官方推出的页面尺寸单位,uniapp支持。
- 指无论手机屏幕或者页面屏幕,750rpx就等于页面宽度的100%
-
2.2.4 将页面设置为启动页面
-
在项目的pages.json中设置启动页面
-
步骤
-
1.在pages.json中的page数组里将需要作为启动页面的对象作为pages数组的第一项即可
-
2.3 页面全局配置
-
需求
- 如何完成页面的注册
- 设置页面导航栏样式
- 设置底部导航栏(tabbar)
-
pages.json
- 页面的全局配置都在pages.json中完成配置
- 官方文档:uniapp.dcloud.net.cn/collocation…
2.3.1 pages页面数组
-
概念:小程序的每个页面在新建之后都需要再pages.json中完成注册,否则无法使用
-
注册
-
在pages.json中的pages数组添加一个对象,格式如下:
{ pages:[ { //页面的访问地址:以/pages开头 path:'/pages/home/home', style:{ //该页面的局部导航栏样式 } } ] }
-
-
细节
- pages数组的第一个就是小程序的启动页面
2.3.2 globalStyle
-
概念:该属性用于设置页面默认窗口样式
-
常用属性
{ "pages":[], "globalStyle": { //导航栏文本颜色 "navigationBarTextStyle": "black", "navigationBarTitleText": "uni-app", //导航栏背景颜色 "navigationBarBackgroundColor": "#1cb3fb", //下拉框背景颜色 "backgroundColor": "#f5f5f5", //是否开启下拉框 "enablePullDownRefresh":true }, }
2.3.3 tabbar配置
-
提供了
tabbar选项实现底部的导航栏 -
例子:
{ "pages":[], "globalStyle": {}, "tabBar": { //选择文字颜色 "selectedColor": "#1cb3fb", //默认颜色 "color": "#000", //标签页配置 "list": [ { "iconPath": "static/images/tabbar/home.png", "selectedIconPath": "static/images/tabbar/home_selected.png", "pagePath": "pages/home/home", "text": "首页" }, { "iconPath": "static/images/tabbar/category.png", "selectedIconPath": "static/images/tabbar/category_selected.png", "pagePath": "pages/category/category", "text": "分类" }, { "iconPath": "static/images/tabbar/car.png", "selectedIconPath": "static/images/tabbar/car_selected.png", "pagePath": "pages/car/car", "text": "购物车" }, { "iconPath": "static/images/tabbar/mine.png", "selectedIconPath": "static/images/tabbar/mine_selected.png", "pagePath": "pages/mine/mine", "text": "我的" } ] } }
三、网络请求
-
前提
- uniapp提供了专门api用于发送请求
uni.request. - 官方文档:
- uniapp提供了专门api用于发送请求
-
前置条件
-
确保微信开发工具详情里的本地设置中已经
勾选了不校验合法域名.如果这个不勾选,那么小程序就仅支持微信开发平台上已经注册的域名。不勾选就是小程序可以给任何网站发送请求
-
3.1 基本使用
-
语法使用
uni.request({ url: 'http://localhost:4001/home/groupGoods/get', //仅为示例,并非真实接口地址。 data: { // text: 'uni.request' }, method:"POST", header: { 'custom-header': 'hello' //自定义请求头信息 }, success: (res) => { console.log(res.data); } });
3.2 二次封装
-
概念:开发者对框架自己封装的api再次进行一次封装,为了更好的贴近开发者熟悉的使用方式。就比如uni.request可以封装为返回一个Promise对象的函数,在使用时就可以用熟悉的
async/await来处理请求 -
二次封装uni.request
-
1.根目录下的http文件夹下(没有就新建)新建一个request.js,里面就暴露封装好的函数,函数本身返回Promise对象
export default function (option={method:'get',data:{}}){ return new Promise(function(resolve,reject){ uni.request({ ...option, success:(res)=> { //将返回的数据传递给Resolve,就可以用await来接受 resolve(res) } }) })} -
2.在要使用 组件引入request.js并使用
import request from "../../http/request.js";export default{ created() { this.getSpellGoods(); }, data(){ return { activityGoods:[] } }, methods:{ async getSpellGoods(){ let res = await request({ url: 'http://localhost:4001/home/groupGoods/get', method:"post" }) console.log(res.data.data); this.activityGoods = res.data.data; } }};
-
3.3. 请求封装
-
前提:根据每个业务模块单独书写一个请求.js文件管理自身模块对应所有的请求代码,并引入到统一的出口Index.js中,在作为项目的全局变量在组件中进行使用
-
流程
-
1.针对每个业务模块书写请求.js文件并放入到modules文件夹中
-
2.调整request.js加入公共请求前缀的支持
//采用单条数据暴露的形式,相比于暴露整个对象,单个形式可以在引入的时候使用解构赋值export let baseURL = 'http://localhost:4001';export let request = function (option={method:'get',data:{}}){ return new Promise(function(resolve,reject){ uni.request({ ...option, success:(res)=> { //将返回的数据传递给Resolve,就可以用await来接受 resolve(res) } }) })} -
2.将请求代码书写在js文件后进行暴露并引入到出口文件
/http/index.js中,index.js暴露包含所有模块的请求属性import {baseURL,request} from "../request.js"; //获取前台的拼团商品列表 function getSpellactivityGoods(){ return request({ url:baseURL +'/home/groupGoods/get', method:"post" }) } export default { getSpellactivityGoods }; -
3.在Main.js中引入请求出口文件(Index.js)挂载到Vue的prototype上
-
4.在组件中通过
this.挂载变量名进行使用。在非组件(比如其他js文件中)使用就需要引入出口index.js文件并使用
-
四、DOM交互实现
- uniapp自己封装了一套dom相关的api,并且语法跟原生的方式不同。
4.1 dom相关api
-
api文档
-
创建dom查询器
-
uni.createQuerySelector.in(组件);
- 基于某个组件生成一个dom查询器
-
-
selector/selectorAll:基于css选择器进行查询(利用查询器)
-
boundingClientRect:生成一个查询指定dom节点尺寸和位置的请求
-
exec:执行所有的dom查询请求
4.2 一般使用流程
-
1.利用createQuerySelector创建一个基于当前组件的dom查询器。即查询范围是当前组件
-
2.利用css选择器确定查询的条件
-
3.调用boundingClientRect添加dom查询请求
-
4.调用exec完成查询,查询结果会放在第三步传入的回调函数。
-
例子
//基于当前组件对象生成一个dom查询器 const query = uni.createSelectorQuery().in(this); //调用api确定查询节点范围,查询节点为id为boxlet elem = query.select('#box')elem.boundingClientRect(data => { console.log("得到布局位置信息" + JSON.stringify(data)); console.log("节点离页面顶部的距离为" + data.top);}).exec();
4.3 应用:分类页面右侧列表滚动和左侧列表联动
-
理解
-
核心代码
-
需要给右侧列表设置滚动事件
scrollEvent(event){ console.log(event.detail.scrollTop); //当前滚动条距离 let top = event.detail.scrollTop; //拿到所有列表项的高度:dom查询 // 1. 新建查询器 let query = uni.createSelectorQuery().in(this); // 2.利用css选择器确定要查找的具体标签 let elems = query.selectAll(".category-item"); // 3.新建节点尺寸位置信息查询请求 elems.boundingClientRect((nodes)=>{ //查询的结果 console.log(nodes); //判断得到curIndex:让当前滚动距离和列表项的累加和进行判断 let totalHeight = 0;//高度累加和 for(let i =0;i<nodes.length;i++){ totalHeight+=nodes[i].height; //判断 if(top < totalHeight){ this.curIndex =i; break; } } }).exec();//执行请求
-
4.4 用户反馈api
4.4.1 加载动画
-
showLoading():显示加载动画
-
语法
uni.showLoading({ title:"加载中", mask:true }); -
特点
- 不会自动消失,需要搭配
hideLoading()才能消失
- 不会自动消失,需要搭配
-
应用:
- 一般用于发送请求获取数据。发送请求时显示loading,数据回来后再隐藏loading
-
-
hideLoading():隐藏加载动画
-
语法
uni.hideLoading();
-
4.4.2 弹窗反馈
-
showToast():消息弹窗
-
语法
uni.showToast({ title:"加载成功", icon:'susscess', mask:true})- mask:是否显示透明蒙层(遮慕,避免用户误操作),默认false,不影响弹窗显示期间用户操作
-
-
hideToast():提前隐藏消息弹窗
-
语法
uni.hideToast();
-
五、页面跳转和传参
5. 1 页面跳转
- uniapp提供了组件和api两种跳转方式
5.1.1 api跳转
-
uniapp提供了5个api用于跳转各种页面
-
api分类
| API | 说明 | | —————————— | —————————————————————————————— | | uni.navigateTo() | 跳转非tabbar页面,不能无限跳转,最多跳5层左右,不然会报错.针对无限跳转一般会使用redirectTo和数组来实现
| | uni.switchTab() | 跳转到tabBar页面,并关闭其他非tabbar页面 | | uni.redirectTo() | 跳转到应用的任意一个页面,并且关闭当前页面(无法通过自带后退按钮回去上一页) | | uni.reLaunch() | 跳转到应用的任意一个页面,并关闭其他所有页面 | | uni.navigateBack() | 关闭当前页面,跳回到某个页面或多级页面,默认是返回到上一个,可以通过设置delta,设置返回的页数,默认为1.比如为2表示返回上上个页面 |
-
语法
uni.navigateTo({ url:"/pages/detail/detail?_id"+要传递的数据 }) uni.switchTab({ url:"/pages/detail/detail?_id"+要传递的数据 }) uni.rediectTo({ url:"/pages/detail/detail?_id"+要传递的数据 }) uni.reLaunch({ url:"/pages/detail/detail?_id"+要传递的数据 }) uni.navigateBack({ delta:2 }) -
应用
- 日常不涉及到tabbar页面,建议使用navigateTo,如果可能出现无限跳转的情况,建议使用redirectTo+数组的形式处理。
- 如果是tabbar页面,没有严格限制,一般使用SwitchTab比较多
- 如果要使用navigateBack,一般搭配navigateTo使用。因为其他方式会关闭已跳转页面。
5.1.2 组件跳转
-
uniapp提供了
<navigator>实现组件跳转 -
语法
<navigator url="页面的跳转地址" open-type="跳转类型">显示文本内容</navigator> -
特点
- 里面的open-type规定跳转使用的模式。是navigate、switchTab、redirect、relaunch、navigateback中的一种。默认navigate
- 目前可以实现绝对地址跳转
5.2跳转页面接受参数
-
在页面的生命周期函数OnLoad中接受
export default{ onLoad(options){ console.log(options._id); } }
六 、本地存储
-
uniapp提供了一系列api实现本地存储功能。
-
分类:根据api为同步代码还是异步代码分为两种
- 同步方式
- 异步方式
6.1 同步方式
-
概念:同步api无需回调函数即可实现对数据的保存和读取
-
相关api
- uni.setStorageSync:保存
- uni.getStorageSync:读取
-
语法
1.保存数据到本地 uni.setStorageSync("key","value"); 2.读取本地数据 let value = uni.getStorageSync("key");
6.2 异步方式
-
需要通过回调函数来实现对数据的保存和读取
-
语法
1. 保存数据到本地 uni.setStorage({ key:'数据名称', data:'要保存的数据', success:()=>{ console.log('保存成功后会执行的回调函数') } }) 2.读取本地数据 uni.getStorage({ key:'数据名称', success:(data)=>{ console.log('读取成功后会执行回调函数并将数据作为参数进行使用') } })
6.3 查看本地存储
- 在微信开发工具,调试器里的Storage标签页中查看
七、微信登录
- 前提:用户的昵称和头像是不能作为用户的唯一凭证,微信平台针对每个用户设计了openid这个唯一的凭证,可以理解为用户在微信平台的
身份证,而开发的小程序就把从微信服务器获取openid并保存到数据库的整个过程就称为微信平台的登录过程。而用户登录是需要开发者提前申请appid。appid是小程序的唯一凭证(编号) - 微信登录核心:拿到用户的openid
- 前置条件:如果小程序想拿到openid,则微信服务器需要开发小程序的id以及密钥。小程序的id就是appid
7.1 申请appid
-
概念:每个小程序(无论是开发中还是已上线),都有自己独一无二的编号,称为appid。需要再微信公众平台上进行申请。
-
注册后获取appid:
-
配置appid
-
1.在Hbuilder的mainfest.json中,填写微信小程序的appid
-
2.在微信开发工具左上角完成扫码登录,后并将appid填写在右侧菜单中详情->基本信息的对应位置上。
-
7.2 微信小程序登录流程
-
文字流程
-
第一部分:获取openid并保存
- 前端通过login()获取临时凭证(只能用一次),并携带appId以及appSecret到后端(在公司中是后端在服务器中写好,前端只需要传临时凭证)。后端接受后将id、Secret以及code发送给微信服务器,成功情况下主要返回session_key以及openid。后端拿到数据后保存openid到数据库。之后将openi以及session_key打包成token返回前端。前端拿到数据后保存到本地
-
第二部分:完成跟用户相关业务时携带token
- 用户在进行跟用户相关请求时,在header中携带token传递给后端,后端通过token进行验证用户。
-
-
官方流程:
7.3 登录开发流程(基于uniapp,原生直接将uni修改为wx)
-
1.在登录函数中获取临时凭证
methods:{ async login(){ uni.login({ success:(res)=>{ let code = res.code; //发送登录请求 } }) } } -
2.书写登录请求代码(请求封装)
function wxLogin(data){ return request({ url:"http://124.70.54.24:3006/payment/wxLogin", method:"post", data:{ ...data, "appId":"你自己的id", "appSecret":"你自己的密钥" } }); } -
3.获取临时凭证之后就发送登录请求
methods:{ login(){ uni.login({ success:async (res)=>{ let code = res.code; //发送登录请求 let res = await this.$http.userHttp.wxLogin({ code, userInfo:{} }); console.log(res.data.token); //保存到本地 uni.setStorageSync('token',res.data.token); } }) } }
7.4 用户登录信息业务流程
-
目的:实现用户保存登录状态(重新进入小程序无需重新登录)
-
流程
-
1.当用户进入我的页面时,可以利用生命周期函数来判断本地是否有token,如果有,则尝试用token获取用户信息并显示在页面上,如果token有效,但是用户信息为空,就可以使用getUserInfo内置api获取默认用户信息展示在页面上。如果token失效或没有则进入第二步
-
2.当用户点击登录按钮时,则进行登录流程:
- 获取临时凭证code
- 获取后携带appid、appSecret以及code一起发送给后端(wxlogin)。后端就会转发到微信服务器进行登录。拿到openid后保存到数据库之后将openid封装成token返回给前端
- 前端拿到token后保存到本地。
- 后续业务需要使用token就放在请求头中进行处理。
-
7.5 修改用户的信息
-
1.用户登录之后进入到修改用户页面
-
2.Data中的原数据userInfo的属性绑定到各个的表单标签中
-
3.给确认按钮绑定点击事件,触发时发送请求修改用户信息
-
4.可选:头像处理
- 点击头像时,点击事件中调用chooseImage事件,获取用户选择图片的临时路径
- 获取临时路径后就在success里调用uni.uploadFile将临时路径对应的图片上传到服务器中
- 上传成功后获取到图片上传后的地址,并赋给userinfo里的头像属性。
- 点击确认修改时就可以将图片信息以及其他数据一起发送给后端
7.6 小程序非登录情况下获取默认用户信息
-
前提:在小程序2.27之前,是可以直接调用uniapp提供的api
getUserInfo直接获取用户的个人信息。只不过小程序官方为了维护用户的合法使用权益,强制22年10月27日之后的小程序不能直接在用户未授权情况下获取用户的个人信息。所在2.27版本之后再次调用getUserInfo就只能获取默认的用户信息:昵称统一为微信用户,头像是一个灰色头像。 -
目的:实现调用getUserInfo获取默认的用户信息
-
语法
uni.getUserInfo({ success:(res)=>{ console.log(res); } })
八、图片处理
- 前提:uniapp针对图片的处理提供了很多的api,根据实际业务选择对应的api进行处理
8.1 上传图片
-
目的:将用户选择的图片上传到指定服务器(课堂用的是老师的,后续就使用公司的服务器)
-
相关api
-
选择图片:
uni.chooseImage -
上传图片:
uni.uploadFiles
-
-
语法
-
chooseImage:选择系统中的图片,并且获取该图片在小程序中保存的临时路径
uni.chooseImage({ success:(res)=>{ console.log(res.tempFilePaths[0]); } }) -
uploadFile:可以将临时路径对应的文件上传到指定的服务器
uni.uploadFile({ url:"http://124.70.54.24:3001/upload", filePath:通过chooseImage拿到的临时路径, name:'file', success:(res)=>{ console.log(res) } })-
关键参数
- url:服务器的地址
- filePath:待上传的文件路径
- name:后端接受上传文件的属性名。我服务器是file。后续由公司后端开发工程师提供。
-
-
-
一般使用示例
uni.chooseImage({ sourceType: ['album', 'camera'], success: ({ tempFilePaths, tempFiles }) => { console.log('临时路径',tempFilePaths); //上传 uni.uploadFile({ url: "http://124.70.54.24:3001/upload", filePath: tempFilePaths[0], name: 'file', success: (res) => { // console.log('上传结果',JSON.parse(res.data)); this.userInfo.avatarUrl = JSON.parse(res.data).data; } }) } })
九、生命周期函数
-
前提
-
小程序本身会有三类的生命周期
- 整个应用生命周期
- 页面生命周期
- 组件生命周期
-
9.1 应用生命周期
- 官方文档:uniapp.dcloud.net.cn/collocation…
- 具体生命周期函数
| 函数名 | 说明 |
|---|---|
| onLaunch | 当uni-app 初始化完成时触发(全局只触发一次) |
| onShow | 当 uni-app 启动,或从后台进入前台显示 |
| onHide | 当 uni-app 从前台进入后台 |
| onError | 当 uni-app 报错时触发 |
| onUniNViewMessage | 对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯 |
| onUnhandledRejection | 对未处理的 Promise 拒绝事件监听函数(2.8.1+) |
| onPageNotFound | 页面不存在监听函数 |
| onThemeChange | 监听系统主题变化 |
| onLastPageBackPress | 最后一个页面按下Android back键,常用于自定义退出。app-uvue-android 3.9+ |
-
应用生命周期函数在app.vue里声明
export default { onLaunch: function() { console.log('App Launch') }, onShow: function() { console.log('App Show') }, onHide: function() { console.log('App Hide') } } -
具体使用
- 引入状态机后,可以在onLaunch中向服务器获取数据并挂载到状态机中
- 当小程序从后台切换回来时,可以使用onShow重新加载数据。将数据保存到状态机中
9.2 页面生命周期
- 官方文档:uniapp.dcloud.net.cn/tutorial/pa…
- 具体生命周期
| 函数名 | 说明 | 平台差异说明 | 最低版本 |
|---|---|---|---|
| onInit | 监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad | 百度小程序 | 3.1.0+ |
| onLoad | 监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例 | ||
| onShow | 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面。页面激活时触发 | ||
| onReady | 监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发 | ||
| onHide | 监听页面隐藏 | ||
| onUnload | 监听页面卸载 | ||
| onResize | 监听窗口尺寸变化 | App、微信小程序、快手小程序 | |
| onPullDownRefresh | 监听用户下拉动作,一般用于下拉刷新,参考示例,要求pages.json设置了该页面可以下拉刷新 | ||
| onReachBottom | 页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项 |
-
在某个页面.vue中声明
export default{ onLoad(options){ }, onShow(){ } } -
应用
- OnLoad可以用于获取跳转后传递的数据,或者发送请求获取服务器数据赋给data(代替created)
- onShow:实现在页面切换回来时更新显示的数据
- onReady:实现加载完毕弹窗广告等业务
9.3 组件生命周期
-
跟vue的组件生命周期时一模一样
- beforecreate
- created
- beforemount
- mounted
- beforeupdate
- updated
- beforeDestroy
- destroyed
-
在页面.vue中进行声明,跟页面生命周期同级别
十、引入状态机
-
前提
- uniapp本身是基于vue 的,虽然自己没有事先引入状态机,但是项目本身是下载了vue的所有相关包,我们可以手动引入状态机进行使用。
-
目的:使用状态机来管理多个页面共享的数据-即全局数据
10.1 创建状态机
-
uniapp本身没有store文件夹之类的,需要手动的新建store文件夹以及书写对应的index.js(仿造vue项目中的写法)
-
流程
-
1.在项目根目录新建store文件夹并新建index.js作为主仓库
-
2.index.js引入vuex并书写基础代码
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { }, modules: { } })
-
-
3.在main.js中引入并作为Vue的全局变量$store进行使用
10.2 使用辅助函数
-
在页面中仍可以用原生方式
this.$store.state去使用状态机数据,但是一般还是使用辅助函数来使用 -
特点:引入和使用语法跟传统的vuex一模一样
-
语法
import {mapState,mapActions,mapMutations,mapGetters} from "vuex" export default{ computed:{ ...mapState(['userInfo']), ...mapGetters(['数据']) }, methods:{ ...mapActions(['getUserInfo']), ...mapMutations(['changeUserInfo']) } }
10.3 仓库的模块化
-
概念:uniapp中使用状态机的流程和vue项目是一样的
-
流程
-
1.在store文件夹下新建modules文件夹
-
2.针对数据新建子仓库.js用于放置该模块的所有状态机内容
export default{ namespaced:true,//开启命名空间,方便能够使用辅助函数 state:{}, getters:{}, mutations:{}, actions:{}, modules:{} } -
3.将第2步的子仓库.js引入到主仓库中,并注册在modules属性中:主仓库.js
import Vue from 'vue' import Vuex from 'vuex' import $http from "../http/index.js" //引入子模块 import userStore from "modules/userStore.js"; Vue.use(Vuex) export default new Vuex.Store({ state: { }, getters: {}, mutations: { }, actions: { }, //注册子仓库 modules: { userStore } -
4.在页面上引入命名辅助函数根据子模块名称获取针对该子模块数据的辅助函数
//主仓库 // import { // mapState, // mapActions, // mapMutations // } from "vuex" //子仓库 import {createNamespacedHelpers} from "vuex"; const {mapState,mapActions,mapMutations}= createNamespacedHelpers("userStore"); export default{ computed:{ ...mapState(['userInfo']) }, methods:{ ...mapMutations(['changeUserInfo']), ...mapActions(['getUserInfo']) } }
-
十一、UI框架
- 前提:小程序也有对应的ui框架快速搭建基于uniapp的美观可交互页面。包括uni官方提供的uni-ui框架,或者是比较普及的uview,或其他收费的ui框架(firstUI)
11.1 uni-ui
-
概念:是uniapp官方团队开发的一款跨平台ui框架,专门适配uniapp项目。
-
特点
- 组件丰富,文档齐全
- 只是部分组件有适配的问题,所以普及度不是最高的
-
引入
-
在uniapp的插件市场搜索uni-ui,进行一键导入,即可参考官方文档进行使用
-
地址:uniapp.dcloud.net.cn/component/u…
-
登录插件市场后点击一键导入到Hbuilder,选择需要导入的项目,点击确定。导入成功后组件会在uni_modules文件夹中,页面可以直接使用
-
-
例子
<uni-section title="双标题卡片" type="line" > <uni-card title="基础卡片" sub-title="副标题" extra="额外信息" :thumbnail="avatar" @click="onClick"> <text class="uni-body">这是一个带头像和双标题的基础卡片,此示例展示了一个完整的卡片。</text> </uni-card> </uni-section>
11.2 uview2.0
-
概念:是第三方团队针对uniapp开发的ui框架。有uview1.0、2.0、以及针对vue3的uviewvue3版本。
-
官方:uviewui.com/
-
特点
- 界面美观、文档齐全、演示友好
- 普及度高
-
引入
-
去uniapp插件市场下载uview2.0
-
完成代码的配置
-
引入uview主js库:在main.js中引入uviewjs并使用(在引入vue之后引入)
import uView from '@/uni_modules/uview-ui' Vue.use(uView) -
在引入uView的全局SCSS主题文件: 在项目根目录的
uni.scss中引入此文件。/* uni.scss */ @import '@/uni_modules/uview-ui/theme.scss'; -
引入uView基础样式:在app.vue中书写
<style lang="scss"> /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ @import "@/uni_modules/uview-ui/index.scss"; </style> -
根据官方组件文档,进行使用
<template> <view> <u-button text="登录" type="primary" :disabled="true"></u-button> <u-number-box v-model="value" @change="valChange"></u-number-box> </view> </template> <script> export default { data() { return { value: 1 } }, methods: { valChange(e) { console.log('当前值为: ' + e.value) } } } </script> <style> </style> -
加载成功在微信开发工具会有以下输出
-
-
细节
-
如果在引入之后测试过程中发生错误,那么确保本地详情已经勾选上以下部分,之后再重新测试
-
-
十二、微信支付
-
官方文档:pay.weixin.qq.com/
-
目的:
- 如何开通微信支付
- 微信支付的开发流程
12.1 前期准备(组长或项目经理)
-
开通商户号(mchid)以及appId
-
商户号
- 营业执照
- 法人代表
- 银行卡
-
-
绑定商户号以及appId
- 小程序内部支付付的款项会打入到商户号对应的银行卡中
- 可以多对多
-
(商户号)配置apiv3 key
-
(商户号)下载并配置商户证书
-
(后端开发人员)后端项目配置(官方提供)
12.2 开通微信支付
概要流程:
- 确保小程序已上线,已注册商户号
- 商户号配置秘钥(apiv3key)和证书等(后端)
- 搭建后端支付项目(java、php、go)
- 小程序开通位微信支付和商户号进行绑定(组长)
- 前端根据开发流程完成和后端的支付业务处理(前端代码)
大概流程:
-
1.需要 拥有上线小程序以及注册商户号,主要是获取小程序的appID以及商户号的mchid
- 没有商户号需要到商户平台进行注册
-
2.需要将商户号以及小程序进行关联。可以一对多。一个小程序可以绑定多个商户号,商户号可以对应多个小程序
-
3.当商户号以及小程序部分都搞定之后,就需要针对商户号进行各种证书的申请和接入。保证商户号开通微信支付,
- 配置apiv3密钥。主要用于用户支付后微信支付服务器返回支付的结果到 开发服务器(后端)提供的一个地址,而微信返回给该接口的就是加密的数据,就需要配置v3密钥进行解密才能拿到支付的真正数据。
- 配置CA证书
-
4.当开发完小程序之后,进行上线,那么就可以申请小程序接入微信支付,需要将小程序和已开通微信支付的商户号进行绑定
-
5.需要后端项目已经搭建好支付所需的签名、证书对应的代码。官方已经提供了针对Java、php、go三套搭建好支付环境的后端项目,设计好支付系统的接口
-
6.后端支付环境搭建好之后,前端就根据官方的开发流程进行代码开发(实际代码不多,主要是后端)
12.3 微信支付开发流程
-
大概流程
- 1.用户下单,生成后端订单
- 2.后端利用通知地址和下单api,完成微信生成订单
- 3.小程序调用requestpayment完成支付,支付结果由微信服务器发送到到后端服务器并保存到数据库。
- 4.小程序发送订单查询请求进行查询
-
图解
-
详细流程
- 1.用户点击下单,将购物车数据和用户信息(token)发送给后端服务器,后端服务器生成该系统自己的订单号
- 2.后端生成订单号之后将订单id以及支付通知地址发送给微信支付服务器,生成微信支付系统订单并返回预支付标识(prepay_id)
- 3.后端将prepay_id和其他参数返回给前端小程序后,小程序就调用
requestPaymentapi唤起微信支付控件,之后微信就会进行支付鉴权,如果鉴权失败则会返回对应的错误代码,比如用户未开通微信支付等,正常唤起微信支付控件后进入第四步 - 4.微信鉴权完成后等待用户输入密码,密码输入完成并微信进行支付完成后就将支付结果发送给第二步后端服务器提供的通知url(外网地址,https,该数据需要商品号配置的v3密钥解密),后端服务器保存支付结果。
- 5.前端小程序自己发送查询请求用于查询支付结果,查询后将支付结果呈现给用户
-
前端部分总结
- 用户点击下单时需要携带订单数据到后台服务器
- 用户点击支付手动调用
requestPayment进行支付处理 - 用户输入支付密码后等待后端返回支付结果或直接进入到支付确认页面再主动发订单查询请求查询支付结果
-
前端掌握
- 大致开发流程以及开通 微支付的大致流程
- 下单api的参数
- requestpayment所需参数
- api文档:pay.weixin.qq.com/docs/mercha…
十三、uniapp图表(ucharts)
- 前提:本身uniapp对echarts的完全支持仅限于h5,因为uniapp对于app是没有提供原生浏览器的dom技术支持,如果要支持app端需要使用uniapp内置的renderjs技术才能实现。但这样操作比较麻烦,所以采用第三方插件ucharts来进行图表展示
13.1 引入ucharts
-
概念:ucharts是一款跨平台的高性能图表插件,基于uniapp。可以通过插件市场搜索秋云图表进行一键导入并使用
-
官方页面:www.ucharts.cn/v2/#/
-
安装
-
到Hbuilder插件市场进行一键导入,导入完成后会导入到uni_modules文件夹,可以直接使用
-
13.2 ucharts使用
-
一般使用流程
-
在页面中使用ucharts组件并包裹在一个views容器中,需要给view设置尺寸等,图表会自适应
<view class="charts-box"> <qiun-data-charts type="column" :chartData="chartData1" /> </view><style> .charts-box { margin-top: 100rpx; width: 100%; height: 300px; } </style> -
2.在data中声明图表需要使用的图表数据
export default{ data(){ return{ chartData1:{} } } } -
3.在onReady中获取服务器数据并赋给图表所绑定的data原数据
export default{ onReady(){ this.chartInit(); }, methods:{ //... chartInit(){ //模拟从服务器获取数据时的延时 setTimeout(() => { let res = { categories: ["2016", "2017", "2018", "2019", "2020", "2021"], series: [{ name: "目标值", data: [35, 36, 31, 33, 13, 34] }, { name: "完成量", data: [18, 27, 21, 24, 6, 28] } ] }; //进行一次深拷贝保证数据和图表实时更新 this.chartData1 = JSON.parse(JSON.stringify(res)); }, 500); }
-
-
细节
- 后续图表就可以根据官网的例子以及发送请求获取要展示的数据赋给图表的原数据从而实现图表的更新
十四、地图处理
-
前提:利用uniapp内置的map组件以及第三方的地图服务api来完成地图相关业务
-
业务
- 获取用户地理位置
- 使用map来显示指定地理位置的地图
- 点击地图来选择某个位置
- 在地图上进行标注
14.1 获取用户所在的地理位置
-
概念:uniapp提供了
getLocationapi获取用户当前所在位置的经纬度。 -
语法
uni.getLocation({ // type: '1|gcj02,wgs84|', success: ({ longitude, latitude }) => { console.log( longitude, latitude); }, fail: (err) => { console.log('地理位置失败',err); } }); -
细节
- 如果直接使用该api,是无法获取用户位置,需要进行授权
-
获取用户授权
-
uniapp环境下需要再mainfest.json中声明
requirePrivateInfos以及premission字段来尝试获取用户的地理位置授权{ //... "mp-weixin" : { "appid" : "wxda8209dccb5cdae9", //... //用户地理位置授权 "requiredPrivateInfos": ["getLocation"], "permission" : { "scope.userLocation" : { "desc" : "获取地理位置为了方便使用地图等服务" } } }, } -
第一次获取地理位置会让用户进行地理位置授权
-
14.2 选择位置
-
概念:uniapp提供了
chooseLocation来实现用户选择某个位置并返回对应的地址信息,也需要在配置文件中进行授权声明 -
语法:默认在用户当前位置进行选择
uni.chooseLocatioin({ success:(res){ console.log(res); } }) -
授权处理
- uniapp环境下需要再mainfest.json中的微信小程序中添加chooseLocation的使用授权
{ //... "mp-weixin" : { "appid" : "wxda8209dccb5cdae9", //... //用户地理位置授权 "requiredPrivateInfos": ["getLocation","chooseLocation"], "permission" : { "scope.userLocation" : { "desc" : "获取地理位置为了方便使用地图等服务" } } }, } -
点击map地图实现选择位置业务
-
思路
- 给map组件设置点击事件,获取经纬度,然后将经纬度作为chooseLocation选择地图范围的中心经纬度(即指定区域进行选择),将获取的地理位置赋给原数据进行下一步处理。
-
代码流程
-
1.给map设置点击事件
<map @click="chooseAddress"></map> -
2.在函数中使用chooseLocation函数。点击位置通过事件对象来获取
methods:{ chooseAddress(event){ //通过event.detail获取经纬度,赋给chooseLocation uni.chooseLocation({ longitude:event.detail.longitude, latitude:event.detail.latitude, success: ({ name, address, longitude, latitude }) => { console.log(name, address, longitude, latitude ); //将地理位置赋给原数据 this.userAddressInfo.address.privince = address.match(/^.+省/)[0]; this.userAddressInfo.address.city = address.match(/省.+市/)[0].slice(1); this.userAddressInfo.address.area = address.match(/市.+区/)[0].slice(1); this.userAddressInfo.address.street = address.match(/区.+$/)[0].slice(1); }, fail: (error) => {} }) } } -
3.可选。将登录用户的姓名和手机号作为默认数据显示在收货地址的姓名和手机号上
- 引入辅助函数使用用户数据。(如果状态机数据和组件原数据名字重复就需要重命名)
- 调用actionapi,获取状态机数据并和组件的用户数据进行合并(注意合并顺序,组件原数据在后)
created(){ this.getUserInfo(); console.log('状态机数据',this.userInfo); this.userAddressInfo = {...this.userAddressInfo,...this.userInfo}; console.log(this.userAddressInfo); },
-
-
十五、uniapp 补充
15.1触底事件
-
uniapp提供了触底事件
onReachBottom来实现页面滚动到底部时执行代码 -
语法:页面
export default{ onReachBottom(){ console.log('触底更新') } }
15.2 扫码
-
概念:uniapp和微信小程序都提供了
scancode用于进行扫码功能,可以得到对应的字符串数据进行使用 -
语法
uni.scancode({ success:({result})=>{ consol.log(result) } }) -
应用
- 可以将二维码的扫描文本为一个页面的地址并携带参数(比如邀请码,商品id等),就可以实现跳转到指定页面
-
不足:
- 只能是小程序内进行扫码,也只能跳转小程序内部页面。
- 如果要实现微信扫码进入小程序,需要小程序已上线以及在微信公众平台已申请小程序专属二维码,通过微信扫一扫该二维码就可以进入该小程序。再利用二维码的参数再跳转小程序的指定页面
15.3 分享
-
概念:uniapp和微信提供了两种分享方式:分享给朋友或朋友圈。两种方式默认都没有开启,需要声明钩子函数之后才能够使用
-
分享给朋友
-
概念:需要再vue中声明钩子函数
onShareAppMessage并将分享的内容作为该函数的返回值才能开启分享。还需要用户点击才能调用分享功能 -
语法
-
1.声明钩子函数(跟data同级别)
export default{ onShareAppMessage() { return { title: "分享的标题", //分享名片的logo "imageUrl": "/static/logo.png", //朋友点击之后进入的页面 "path": "/pages/order/order?table=4" } } } -
2.通过点击右上角
...或点击带有分享的按钮进行触发分享1.点击小程序页面右上角... 进行分享 2.组件中讲某个按钮作为分享按钮 <button open-type="share">分享</button>
-
-
细节
- 只能分享小程序内部页面给朋友。不能分享外部链接
-
-
分享到朋友圈
-
概念:uniapp和微信小程序也是提供了另一个钩子函数
onShareTimeLine用于开启分享到朋友圈 -
语法
- 1.开启分享给朋友圈
export default{ onShareTimeline() { return { title:"分享到朋友圈", query:"?id=1", imageUrl:"/static/logo.png" } } }- 2.通过右上角
...中的分享到朋友圈
-
细节
- 只能分享当前小程序页面到朋友圈
- 如果该页面要分享到朋友圈,官方推荐该页面是纯内容页面(比如文章页面),小程序官方也对分享页面为了安全考虑做了很多的限制。
-
文档
-
15.4 自定义组件
-
概念:在小程序中我们也可以用组件化开发思维来开发小程序。uniapp也提供了自定义组件的语法支持,而且还提供了easycom快速注册和引入自定义组件的语法模式
-
业务
- 如何在uniapp中创建和使用自定义组件
- 如何使用easycom组件注册模式
15.4.1 uniapp中创建自定义组件
-
语法流程
-
几乎跟vue是一样的。先在项目根目录新建components文件夹,里面的每个自定义组件建议单独用一个文件夹来保存,components目录示例如下:
spellGoodsmini10 -- components -- Header Header.vue -- Tabbar Tabbar.vue -- pages -- static -
自定义组件里的内容跟平常的组件一样,只不过没有页面生命周期,只能使用组件生命周期
-
自定义组件的引入跟vue是一样的
- import引入
- 注册到components属性中
-
15.4.2 easycom模式
-
uniapp针对于自定义组件提供了一种快速注册和使用的模式-easycom模式
-
easycom模式是指如果自定义组件是放在项目根目录下的components文件夹中并且每个组件都被包裹在一个同名的文件夹中,那么就认为这种自定义组件的书写格式符合easycom模式。
-
作用
- 符合easycom模式的自定义组件无需引入注册,直接在父组件或页面中进行使用
十六、uniapp分包
前提:微信小程序上线对代码体积有严格的要求(无需下载,用完即走)。体积大小不能超过2m,实际微信开发工具上传代码时推荐不超过1.5m。但是小程序官方为了保证小程序 的功能丰富,推出了分包机制(源自微信小程序,uniapp提供支持),可以允许小程序分成多个模块,其中有一个主模块(主包),其他的每个模块称为一个分包。在上线的时候我们会只上传主包代码,其他分包代码则通过分包机制来进行下载使用(比如用户访问分包页面时下载分包的内容)
16.1 分包机制
-
是指将整个小程序代码按照模块的划分拆分为多个相互独立的文件夹的过程。参与分包的代码只是pages文件夹以及static文件夹,其他文件不参与分包
-
为什么要分包
- 模块化处理
- 满足上线要求(不超过1.5m)
-
分包的流程
- 需要将代码按照模块进行拆分
- 在pages.json中完成分包配置
16.1 分包的划分
-
大概内容
-
按照业务数据模块来进行划分:比如用户、订单、商品等方式来划分,我们可以分为用户分包、订单分包等。每个分包都有一个独立的文件夹,文件夹主要包含了页面以及该分包要使用的静态资源文件夹(static)。除了分包外,每个小程序都必须有一个主包(一般包含tabbar页面以及要使用的静态资源)
--pages 主包目录 -- 各个tabbar页面的文件夹 -- orderPages 订单分包 -- orderDetail -- orders -- toOrder -- static 保存订单分包页面所需要使用的静态资源 -- userPages -- setUserInfo -- address -- goodPages -- list
-
16.2 分包配置
-
概念:完成分包划分后,需要调整pages.json里的内容并添加分包的配置代码
-
流程
-
1.将已经分包的页面路径进行调整
页面路径: 分包的目录名/页面文件夹名称/页面名称 例子:提交订单页面 orderPages/toOrder/toOrder -
2.书写
subPackages完成分包的具体配置"subPackages": [ //用户分包 //... //订单分包 { "root": "orderPages", "pages": [{ "path": "toOrder/toOrder", "style": { "navigationBarTitleText": "订单详情", "enablePullDownRefresh": false } }, { "path": "orders/orders", "style": { "navigationBarTitleText": "订单中心", "enablePullDownRefresh": false } } ] }, //商品分包 { "root": "goodPages", "pages": [{ "path": "list/list", "style":{ "navigationBarTitleText": "", //是否开启下拉刷新 "enablePullDownRefresh": true } }] } ],
-
16.3 分包预下载机制
-
概念:分包预下载机制是指 在进入小程序某个页面时,由小程序自动预下载可能需要的分包,提升进入后续分包页面时的启动速度
-
语法
{ //... "preloadRule": { "pages/category/category": { "network": "all", "packages": ["goodPages"] }, "pages/car/car": { "network": "all", "packages": ["orderPages"] } } }
uniapp 业务
-
分类页面一级菜单和二级菜单滚动交互
-
列表触底加载下一页以及下拉刷新数据
-
微信登录
-
用户头像上传
-
引入状态机管理用户数据
-
使用uview构建页面
-
图表显示未支付已支付订单
-
收货地址地图显示和点击处理
-
如何分享给朋友和朋友圈
- 分享给朋友以及携带参数
- 什么时候用分享到朋友圈:商品详情页面点击分享按钮
-
如何扫码
- 通过扫描文本进行页面跳转和传参
-
自定义tabbar实现
- 第一种:自定义组件
- 第二种:事先在pages.json中完成所有可能会使用的Tabbar标签页,也就是list中就包含了所有可能会用到的,建议不超过5个。当用户没有登录时,先默认展示游客状态下的Tabbar页面,用户登录后再进行切换。可以通过uniapp内置的
setTabbarItem来决定其中的某一项展示或不展示。有平台的兼容性问题
-
如何分包
-
如何部署和上线
- 开发功能完毕后进行性能测试(自带的调试器性能标签页和小程序官方性能优化指南)
- 预览没问题就点击上传输入版本号,第一次就是1.0。上传之后是体验版
- 在微信公众平台对体验版进行测试,测试没问题则提交审核。审核通过后就上线
- 后续维护也是从第一步重新开始即可。只不过版本号需要更新
-
小程序性能优化指南
-
如何运行在ios或安卓平台
- 安卓:通过usb连接手机或使用模拟器来运行,
- ios:需要先申请开发者证书以及签名才能用真机模拟。
-
ios、安卓的页面适配
- iOS底部的安全距离:在uniapp的mainfest.json中完成app-plus的配置,第二在app.vue中添加公共样式,即添加底部的安全padding:bottom-padding:env(safe-area-inset-bottom)
-
安卓
- 如果安卓版本太低,比如小于5,页面适配会出问题,比如滚动条之类的