小程序的核心技术主要是三个:
网址 : 微信小程序
网址 : 微信开发者工具下载地址与更新日志 | 微信开放文档
Vue的MVVM和小程序MVVM对比
网址 : 小程序
可能会自动注册完成
ps : 也可以反向注册,在这里直接配置,文件夹会自动生成
text页面
{{message}}
item : {{item}} => index: {{index}}
当前计数 : {{counter}}
直接修改data中的数据,不会引起页面的刷新
小程序和react中都不会,只有vue劫持了属性才能直接操作
ps : 修改data并且希望页面重新渲染,必须使用 this.setData()
// pages/text/text.js
Page({
/**
* 页面的初始数据
*/
data: {
// 1. 数据绑定,{{}} 语法
message: 'star',
// 2. 列表渲染数据
movies: ['迪迦大战肯德基', '图图和小新抢东西吃'],
// 3. 计数器参数
counter: 0
},
// 监听计数器增加按钮触发
increment() {
// 此方法修改后的数据不会在页面上响应
// this.data.counter += 1
this.setData({
counter: this.data.counter + 1
})
},
// 监听计数器减少按钮触发
decrement() {
this.setData({
counter: this.data.counter - 1
})
},
})
小程序的宿主环境 => 微信客户端
ps : 宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件
双线程模型 :
项目配置文件 => 比如项目名称、appid等
网址 : 项目配置文件 | 微信开放文档
小程序搜索相关的
网址 : sitemap 配置 | 微信开放文档
全局配置
网址 : 全局配置 | 微信开放文档
{
"pages": [
// 默认显示的页面
"pages/text/text",
"pages/index/index",
"pages/logs/logs"
],
"window": {
// 下拉 loading 的样式,仅支持 dark 黑色 / light 白色
// 需要到页面的.json中加入 "enablePullDownRefresh": true , 开启即可
// 最好别在全局开启下拉刷新
"backgroundTextStyle": "dark",
// 导航栏背景颜色
"navigationBarBackgroundColor": "#f00",
// 导航栏标题文字内容
"navigationBarTitleText": "Weixin",
// 导航栏标题颜色,仅支持 black / white
"navigationBarTextStyle": "black"
},
// 底部导航按钮
"tabBar": {
// 文字默认的颜色
"color":"#fff",
// 选中时文字的颜色
"selectedColor":"#ff8189",
// 导航是一个数组
"list": [
{
// 页面路径
"pagePath": "pages/index/index",
// 文本
"text": "首页",
// 默认显示的图标
"iconPath": "assets/images/tabbar/home.png",
// 选中时显示的图标
"selectedIconPath": "assets/images/tabbar/home_active.png"
},
{
"pagePath": "pages/text/text",
"text": "记录",
"iconPath": "assets/images/tabbar/category.png",
"selectedIconPath": "assets/images/tabbar/category_active.png"
}
]
},
// 表明启用新版的组件样式
"style": "v2",
// 配置搜索相关文件,基本不需更改
"sitemapLocation": "sitemap.json"
}
页面配置
每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置
页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项
网址 : 页面配置 | 微信开放文档
{
// 是否使用组件
"usingComponents": {
// 需要在这里配置
},
// 页面顶部标题文字
"navigationBarTitleText": "冲啊",
// 页面顶部标题颜色
"navigationBarTextStyle": "white",
// 页面顶部背景颜色
"navigationBarBackgroundColor": "#0f0",
// 是否开启下拉刷新
// Page.js 中,onPullDownRefresh 开启这个,可以监听到是否下拉刷新了
"enablePullDownRefresh": true,
}
每个小程序都需要在 app.js 中调用 App 函数 注册小程序示例
网址 : App(Object object) | 微信开放文档
注册App时,一般做如下事情 :
小程序的打开场景较多 :
在 onLaunch 和 onShow 生命周期回调函数中,会有options参数,其中有scene值
// app.js
App({
/**
* 生命周期回调——监听小程序初始化。
* 小程序初始化时触发,只有执行一次
*/
onLaunch(options) {
console.log('onLaunch =>', 'scene :', options.scene);
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
},
/**
* 生命周期回调——监听小程序启动或切前台
* 每次打开小程序都会执行
*/
onShow(options) {
console.log('onShow =>', 'scene :', options.scene);
// 可根据场景值,跳转到对应的页面
wx.navigateTo({
// url: 'url',
})
},
onHide() {
console.log('onHide => 隐藏~');
}
})
注意 : 定义在全局的数据不会响应式
共享的数据通常是一些固定的数据
// app.js
App({
// 定义的全局变量
globalData: {
token: '',
userInfo: {
name: 'coder',
age: 18
}
},
// 页面初始化调用的回调函数
onLaunch(options) {
// 登录
wx.login({
success: res => {
console.log('code =>', res.code);
// 发送 res.code 到后台换取 openId, sessionKey, unionId
this.globalData.token = res.token || 'abcdefghijklmnopqrstuvwxyz'
}
})
}
})
// pages/text/text.js
Page({
// 页面加载的时候触发
/**
* 获取页面所需数据
*/
onLoad() {
// 获取共享的数据
// 1. 获取app实例对象
const app = getApp()
// 2. 从app实例对象中获取数据
const token = app.globalData.token
const userInfo = app.globalData.userInfo
console.log('userInfo :', userInfo);
console.log('token :', token);
// 3. 拿到token后发送网络请求
// wx.request({
// url: 'url',
// token
// })
// 4. 展示数据到页面
this.setData({
userInfo
})
},
/**
* 页面的初始数据
*/
data: {
userInfo: {}
},
})
在生命周期函数中,完成应用程序启动后的初始化操作
这里简单写写,详细的登录操作在下方
// app.js
App({
// globalData
globalData: {
userState: {
openId: '',
sessionKey: '',
unionId: ''
},
userInfo: {}
},
// 页面初始化调用的回调函数
onLaunch(options) {
// 从本地获取用户状态信息,判断是否需要登录
const userState = wx.getStorageSync('userState')
// 如果不存在,则进行登录
if (!userState || !userState.openId) {
wx.login({
success: res => {
console.log('code =>', res.code);
// 发送 res.code 到后台换取 openId, sessionKey, unionId
this.getUserState(res.code)
}
})
}
},
// 获取用户信息
getUserState(code) {
wx.request({
// 填入请求地址
url: 'url',
code,
success: (res) => {
const { openId, unionId, sessionKey, userInfo } = res
// 将登录成功的数据,保存在storage中
wx.setStorageSync('userState', {
openId,
unionId,
sessionKey,
})
wx.setStorageSync('userInfo', userInfo)
// 将登录成功的数据,保存在globalData中
this.globalData.userState = {
openId,
unionId,
sessionKey,
}
this.globalData.userInfo = userInfo
}
})
//
}
})
小程序中的每个页面, 都有一个对应的js文件, 其中调用 Page函数 注册页面示例
网址 : Page(Object object) | 微信开放文档
注册Page页面时,一般做如下事情 :
网址 : 生命周期 | 微信开放文档
// logs.js
Page({
data: {
pagaData: {}
},
// 页面加载时促发
onLoad() {
const _this = this
// 发送网络请求
wx.request({
url: 'www.baidu.com',
success: (res) => {
console.log(this, res);
this.setData({
pagaData: res.pagaData || {}
})
},
error(err) {
console.log(_this, err);
}
})
}
})
// logs.js
Page({
data: {
// 定义初始化数据
movies: ['葫芦娃大战喜羊羊', '蜡笔小新殴打图图'],
},
// 页面加载时促发
onLoad() { }
})
// logs.js
Page({
data: {
// 定义初始化数据
btns: ['red', 'blue', 'green', 'pink', 'yellow'],
},
// 页面加载时促发
onLoad() { },
// 绑定事件
handClick() {
console.log('我被点击了');
},
// 传递参数
clickQuery(e) {
console.log('我被点击了,参数是 : ', e.target.dataset);
},
btnsClick(e) {
console.log('循环出的按钮', e.target.dataset);
}
})
{
"usingComponents": {},
// 开启下拉刷新
"enablePullDownRefresh": true
}
// logs.js
Page({
data: {
},
// 监听用户下拉刷新
onPullDownRefresh() {
console.log('用户下拉刷新');
// 模拟网络请求
setTimeout(() => {
// api: 停止下拉刷新
wx.stopPullDownRefresh({
success: (res) => {
console.log('成功关闭下拉刷新', res);
},
fail: (err) => {
console.log('关闭失败', err);
}
})
}, 1000);
}
})
{
"usingComponents": {},
// 页面上拉触底事件触发时距页面底部距离,单位为px
// 距离底部多少距离,触发
"onReachBottomDistance": 100
}
// logs.js
Page({
data: {
// 默认展示50条数据
countsNum: 50,
// 到达底部后,需要增加的数量
countsSize: 40
},
// 监听页面是否滚动到达底部
onReachBottom() {
this.setData({
// 到达底部后,增加
countsNum: this.data.countsNum + this.data.countsSize
})
console.log('滚动到底部');
}
})
页面数据 : {{item}}
// logs.js
Page({
data: {
// 定义初始化数据
btns: ['red', 'blue', 'green', 'pink', 'yellow'],
},
// 页面加载时促发
onLoad() { },
// 页面滚动
onPageScroll(e) {
console.log(e); // 距离顶部的距离
},
})
Text组件 : 用于显示文本, 类似于span标签, 是行内元素
text | 微信开放文档
Hello world
{{message}}
{{message}}
>
Button组件用于创建按钮,默认块级元素
button | 微信开放文档
open-type用户获取一些特殊性的权限,可以绑定一些特殊的事件
Page({
getUserProfile(e) {
// 推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
// 点击允许
success: (res) => {
console.log('success', res);
},
// 点击拒绝
fail: (err) => {
console.log('fail', err);
}
})
}
})
Page({
getPhoneNumber(e) {
// 如果点击了拒绝
if (e.target.errMsg !== 'getPhoneNumber:ok') {
return wx.showToast({
title: '用户未同意授权手机号',
icon: 'none'
})
}
// 如果点击确认
cosnt { code, encryptedData, iv } = e.target
// 把数据传给后端,后端会去解密拿到手机号的
wx.request({
url: 'https://example.com/onLogin',
data: {
appId: '',
openId: '',
code,
encryptedData,
iv
},
method: "post",
success: function (res) {
console.log(res);
}
})
}
})
View视图组件 : 块级元素,独占一行,通常用作容器组件,和div差不多
view | 微信开放文档
scroll-view : 可以实现局部滚动
scroll-view | 微信开放文档
{{item}}
.contain {
height: 300px;
}
.box {
height: 100px;
color: white;
font-weight: bold;
}
Page({
data: {
viewColors: ['red', 'pink', 'green', 'blue']
},
scrollTop() {
console.log('到达顶部');
},
scrollBottom() {
console.log('到达底部');
},
// 滚动中触发
scrollIng({ detail }) {
console.log(detail);
}
})
注 : 若要开启flex布局,须加上enable-flex这个属性
{{item}}
.contain {
display: flex;
}
.box {
/* 不压缩 */
flex-shrink: 0;
width: 150px;
height: 150px;
color: white;
font-weight: bold;
}
Page({
data: {
viewColors: ['red', 'pink', 'green', 'blue']
},
scrollLeft() {
console.log('到达左侧');
},
scrollRight() {
console.log('到达右侧');
},
// 滚动中触发
scrollIng({ detail }) {
console.log(detail);
// detail.deltaX > 0,往左滚动
// detail.deltaX < 0,往右滚动
}
})
Image组件 : 用于显示图片
image | 微信开放文档
Page({
data: {
imgUrl: ''
},
choseImage() {
// 选择本地图片
wx.chooseMedia({
// 最多可以选择的文件个数
count: 1,
// 只能拍摄图片或从相册选择图片
mediaType: 'image',
}).then(res => {
if (res.errMsg !== 'chooseMedia:ok') return
console.log(res);
const imageList = res.tempFiles || []
const imgUrl = imageList[0].tempFilePath || ''
this.setData({
imgUrl
})
})
}
})
Swiper组件 => 用来做轮播图效果
swiper | 微信开放文档
{{item.text}}
.s-swiper {
/* 注意 : swiper默认有个150px的高度 */
height: 300rpx;
}
.s-item {
color: #fff;
font-weight: 800;
text-align: center;
line-height: 300rpx;
}
Page({
data: {
// 轮播数据
swiperData: [{
text: 'A',
color: 'green'
},
{
text: 'B',
color: 'black'
},
{
text: 'C',
color: 'skyblue'
},
{
text: 'D',
color: 'pink'
},
{
text: 'E',
color: 'blue'
}],
}
})
{{item.text}}
.s-swiper {
/* 注意 : swiper默认有个150px的高度 */
height: 300rpx;
margin-top: 20rpx;
}
.s-item {
/* 用来做间距的颜色 */
background-color: #fff;
display: flex;
/* 使其居中 */
justify-content: center;
}
.content {
/* 重要 */
width: 100%;
color: #fff;
font-weight: 800;
text-align: center;
line-height: 300rpx;
/* 加入动画 */
transform: scale(.9);
transition: transform .6s ease-in-out 0s;
}
.active {
transform: scale(1);
}
Page({
data: {
// 轮播数据
swiperData: [{
text: 'A',
color: 'green'
},
{
text: 'B',
color: 'black'
},
{
text: 'C',
color: 'skyblue'
},
{
text: 'D',
color: 'pink'
},
{
text: 'E',
color: 'blue'
}],
// 当前轮播模块索引
currentIndex: 0
},
/**
* 监听方法
*/
// 轮播图滚动
handleChange(e) {
this.setData({
currentIndex: e.detail.current
})
}
})
model:value => 双向绑定功能
Page({
data: {
message: 'abc'
},
})
页面样式的三种写法:行内样式、页面样式、全局样式
优先级依次是:行内样式 > 页面样式 > 全局样式
权重
rpx(responsive pixel): 可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx
在iphone6上,屏幕宽度为375px,共有750个物理像素,1px === 2rpx
iphone6为标准,设计稿是375,1px === 2rpx => 设计稿16px,我们写32rpx
iphone6为标准,设计稿是750,1px === 1rpx => 设计稿20px,我们写20rpx
.view {
/* 在375的设计稿中,200rpx === 100px */
width: 200rpx;
height: 200rpx;
background-color: blue;
line-height: 200rpx;
text-align: center;
color: #fff;
}
wx:if --- wx:elif --- wx:else
优秀
及格
不及格
hidden属性:
hidden和wx:if的区别
hidden => 控制隐藏和显示是控制是否添加hidden属性,相当于display:none
wx:if => 是控制组件是否渲染的
block : 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
index : 遍历后在wxml中可以使用一个变量index,保存的是当前遍历数据的下标值
item : 数组中对应某项的数据
{{item}} --- {{index}}
{{item}} --- {{index}}
{{item}} --- {{index}}
wx:for-item = ' ' => item 重命名
wx:for-index = ' ' => index 重命名
{{str}} --- {{key}}
使用wx:for时,可以添加一个key来提供性能
wx:key 的值以两种形式提供 :
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构
为什么要设计WXS语言
WXS使用的限制和特点 :
WXS有两种写法 :写在标签中 || 写在以.wxs结尾的文件中
WXS标签的属性 :
wxs :
// 2. 定义函数
function priceFormat(price) {
return price + '元'
}
// 3. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出
module.exports = {
priceFormat: priceFormat
}
{{format.priceFormat(money)}}
// 1. 定义函数
function priceFormat(price) {
return price + '元'
}
// 2. 导出 : 必须导出后,才能被使用,且必须被CommonJs导出
module.exports = {
priceFormat: priceFormat
}
{{format.priceFormat(money)}}
['对象.属性']: 修改的值
data: {
dataObj: {
name: 'aaa',
age:15
}
}
// 修改对象的属性
this.setData({
['dataObj.age']: 77
})
// 删除对象的属性
delete this.data.dataObj.age
this.setData({
dataObj: this.data.dataObj
})
data: {
arr: [{
name: '123'
}, {
name: 'abc'
}]
}
// 修改第二个元素的属性
const index = 2
this.setData({
[`arr[${index}].name`]: '555'
})
// 删除某个数组元素
this.data.dataList.splice(index, 1)
this.setData({
dataList: this.data.dataList
})
某些组件会有自己特性的事件类型
input : bindinput || bindblur || bindfocus
scroll-view : bindscrolltowpper || bindscrolltolower
当某个事件触发时, 会产生一个事件对象, 并且这个对象被传入到回调函数中
target : 触发事件的元素
currentTarget : 处理事件的元素(大部分情况使用target)
.outer {
width: 400rpx;
height: 400rpx;
background-color: #0f0;
display: flex;
justify-content: center;
align-items: center;
margin: 100rpx auto;
}
.inner {
width: 150rpx;
height: 150rpx;
background-color: #00f;
}
Page({
outerClick(e) {
console.log(e);
// target : 触发事件的元素 => 点击的是蓝色,所以 target === inner
console.log('target:', e.target);
// currentTarget : 处理事件的元素 => 冒泡到外层了,所以 currentTarget === outer
console.log('currentTarget:', e.currentTarget);
}
})
touches : 当前屏幕上有多少个手指
changedTouches : 较上一个状态,改变了多少个手指
方式一 : 使用data-*
方式二 : 使用mark ( 2.7.1版本以上 ) => 事件 | 微信开放文档
data- : 需要区分currnetTarget 和 target,一般使用currnetTarget即可
mark : 会自动合并所有的mark数据,不受影响
传递
Page({
outerClick(e) {
// 通过data- : 传递过来的数据
const { name, age } = e.currentTarget.dataset
console.log(name, age);
// 通过mark : 传递过来的数据,子组件和父组件mark数据会合并
console.log(e.mark); // { know: "是的", address: "地球" }
const { address } = e.mark
console.log(address);
}
})
{{item}}
.nav {
display: flex;
align-items: center;
height: 100rpx;
}
.item {
flex: 1;
text-align: center;
}
.text {
display: inline-block;
padding-bottom: 10rpx;
border-bottom: 6rpx solid #fff;
}
.active {
border-bottom-color: orange;
}
Page({
data: {
dataList: ['衣服', '裤子', '鞋子'],
currentIndex: 0
},
itemClick(e) {
// 注意,这个时候使用currentTarget,才能拿到传递过来的参数
// 如果不这么做,那么点到文字上就不会进行切换
const { index } = e.currentTarget.dataset
this.setData({
currentIndex: index
})
}
})
事件捕获 : 从外到内
事件冒泡 : 从内到外
总是先捕获,再冒泡
const query = wx.createSelectorQuery()
query.select('.swiper-item-layout').boundingClientRect()
query.exec((res) => {
const winWid = wx.getSystemInfoSync().windowWidth // 获取当前屏幕的宽度
const height = res[0].height // 获取元素的高度
const width = res[0].width // 获取元素的宽度
const swiperHeight = height / width * winWid + 'px' // 等比例设置值
this.swiperHeight = swiperHeight
})
小程序刚刚推出时,是不支持组建化的,1.6.3版本后开始支持
组件化思想的应用 :
需要在 json 文件中进行自定义组件声明
将component 字段设为 true 可这一组文件设为自定义组件
在页面的json文件中,配置usingComponents,即可在页面中使用
在app.json的usingComponents声明某个组件,那么所有页面和组件可以直接使用该组件
组件内的class样式 : 只对组件wxml内的节点生效, 对于引用组件的Page页面不生效
ps : 组件内不能使用id选择器、属性选择器、标签选择器 => 因为会作用到外面,不安全
外部使用class的样式 : 只对外部wxml的class生效,对组件内是不生效的
ps :外部使用了id选择器、属性选择器不会对组件内产生影响
外部使用了标签选择器,会对组件内产生影响
在Component对象中,可以传入一个options属性
其中options属性中有一个styleIsolation(隔离)属性
styleIsolation有三个取值 :
// pages/logs/components/mainList.js
Component({
options: {
// 1. 默认值,相互不影响
// styleIsolation: "isolated",
// 2. 页面可以影响组件内部,组件内部不能影响页面
// styleIsolation: "apply-shared",
// 3. 相互都能影响
styleIsolation: "shared",
}
})
可以使用 properties 属性
// pages/logs/components/mainList.js
Component({
properties: {
// 传递过来的数据
title: {
type: "String",
value: '我是默认的'
}
}
})
说实话,有点繁琐,咕噜咕噜~
可在父组件里调用 this.selectComponent ,获取子组件的实例对象
调用时需要传入一个匹配选择器 selector,如:this.selectComponent(".my-component")
ps : 如果有多个,可以使用 this.selectAllComponents
// pages/logs/components/mainList.js
Component({
data: {
dataList: ['衣服', '裤子', '鞋子'],
currentIndex: 0
},
// 绑定的方法
methods: {
itemClick(e) {
const { index } = e.currentTarget.dataset
this.setData({
currentIndex: index
})
this.triggerEvent('itemClick', index)
},
// 定义一个方法
textFun() {
console.log('我是组件的方法!');
}
}
})
Page({
itemClick(params) {
const { detail: index } = params
console.log(index);
},
onShow() {
// 1. 获取自定义组件实例,通过类选择器
const mainListRef = this.selectComponent('.main-list-ref')
// 2. 调用自定义组件方法
mainListRef.textFun()
// 3. 获取自定义组件数据
console.log(mainListRef.data.dataList); // ["衣服", "裤子", "鞋子"]
}
})
小程序的插槽不支持默认值
header
footer
123
冲啊!
// pages/logs/components/mainList.js
Component({
options: {
// 开启使用多个插槽 => 具名插槽
multipleSlots: true
}
})
A
B
冲啊!
小程序的插槽不支持默认值 => 可以用css的empty伪类 + 兄弟选择器来解决
header
哈哈哈哈,我是默认
footer
/* 默认 隐藏默认值 */
.default {
display: none;
}
/* 当插槽为空时,显示 => 运用empty伪类 + 兄弟选择器 */
.content:empty+.default {
display: block;
}
behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins”
// 创建一个Behavior并导出
export const counterBehaviors = Behavior({
// 定义数据
data: {
count: 10
},
// 接收参数
properties: {},
// 引入其他behaviors
behaviors: [],
// 定义方法
methods: {
text() {
console.log('text');
}
}
})
// 1. 倒入behaviors
import { counterBehaviors } from '../../../behaviors/counter'
Component({
// 2. 组件使用behaviors
behaviors: [counterBehaviors]
})
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发
ps : 最重要的生命周期是 created attached detached
组件的的生命周期也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)
Component({
// 生命周期写在这里面
lifetimes: {
// 组件实例被创建,可以用来进行网络请求
created() {
console.log('created');
},
// 组件实例进入页面节点树中
attached() {
console.log('attached');
},
// 组件渲染布局完成后
ready() {
console.log('ready');
},
// 组件被移除时
detached() {
console.log('detached');
}
}
})
一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理
组件所在页面的生命周期 => 在 pageLifetimes 定义段中定义
Component({
// 组件生命周期
lifetimes: {
created() {
console.log('created'); // 1
},
attached() {
console.log('attached'); // 2
},
ready() {
console.log('ready'); // 4
},
detached() {
console.log('detached');
}
},
// 组件所在页面的生命周期
pageLifetimes: {
show() {
console.log('show', '组件所在页面被展示时执行'); // 3
},
hide() {
console.log('hide', '组件所在页面被隐藏时执行');
},
resize(e) {
console.log('resize', '组件所在页面尺寸变化时执行', e);
}
}
})
微信提供了专属的API接口,用于网络请求: wx.request(Object object)
网址 : RequestTask | 微信开放文档
Page({
data: {
dataList: []
},
onLoad() {
wx.request({
// 请求地址
url: 'https://www.baidu.com/',
// 不管是post还是get,请求参数都是放到data中的
data: {
age: 18
},
// 请求成功的回调
success: (res) => {
const data = res.data.data
console.log(data);
this.setData({
dataList: data
})
},
// 请求失败的回调
fail: (err) => {
console.log(err);
}
})
}
})
export function request(option) {
return new Promise((resolve, reject) => {
wx.request({
...option,
success: (res) => {
resolve(res.data)
},
fail: reject
})
})
}
// 1. 导入
import { homeDataList } from '../../service/request/home/index'
Page({
data: {
dataList: []
},
async onLoad() {
const params = {
url: 'https://www.baidu.com/',
data: {
age: 18
}
}
// 2. 直接使用
homeDataList(params).then(res => {
console.log('res', res);
}).catch(err => {
console.log('err', err);
})
// 3. 使用async/await
const dataList = await homeDataList(params)
console.log(dataList);
}
})
class request {
// 设置baseUrl
constructor(baseUrl) {
this.baseUrl = baseUrl
}
// 封装 request 方法
request(option) {
const { url } = option
return new Promise((resolve, reject) => {
wx.request({
...option,
// 拼接地址
url: this.baseUrl + url,
success: (res) => {
resolve(res.data)
},
fail: reject
})
})
}
// 封装 get 方法
get(option) {
return this.request({ ...option, method: 'GET' })
}
// 封装 post 方法
post(option) {
return this.request({ ...option, method: 'POST' })
}
}
// 可创建多个实例,请求不同的地址
export const starRequest = new request('https://www.baidu.com')
每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信
小程序登录后台 – 开发管理 – 开发设置 – 服务器域名
配置时需要注意 :
showToast 和 showLoading 只能同时显示一个
wx.showToast({
// 提示内容
title: 'title',
// 图标 => none error loading success
icon: 'success',
// 自定义图标 => 自定义图标的本地路径,image 的优先级高于 icon
image: '/assets/images/tabbar/cart_active.png',
// 持续时间
duration: 2000,
// 是否显示透明蒙层,显示期间不能进行交互
mask: true,
// 成功回调
success: (res) => {
console.log('展示成功', res);
},
// 失败回调
fail: (err) => {
console.log('展示失败', err);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: (data) => {
console.log('展示', data);
}
})
和 showToast => icon为loadind,展示的效果相同
但是可以手动控制关闭弹窗的时间
wx.showLoading({
// 提示内容
title: '加载中',
// 是否显示透明蒙层,显示期间不能进行交互
mask: true,
// 成功回调
success: (res) => {
console.log('展示成功', res);
},
// 失败回调
fail: (err) => {
console.log('展示失败', err);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: (data) => {
console.log('展示', data);
}
})
// 两秒后,关闭弹窗 => 可在请求数据完成后,再调用该方法
setTimeout(function () {
wx.hideLoading()
}, 2000)
wx.showModal({
// 提示的标题
title: '你有钱吗',
// 提示的内容
content: '我有',
// 是否显示取消按钮
showCancel: true,
// 取消按钮的文字,最多 4 个字符
cancelText: '骗你哒',
// 取消按钮的文字颜色,必须是 16 进制格式的颜色字符串
cancelColor: '#f0f',
// 确认按钮的文字,最多 4 个字符
confirmText: '真的啦',
// 确认按钮的文字颜色,必须是 16 进制格式的颜色字符串
confirmColor: '#00f',
// 是否显示输入框
// editable: true,
// 显示输入框时的提示文本
// placeholderText: '我是提示内容',
// 成功回调
success: (res) => {
/**
* content => editable 为 true 时,用户输入的文本
* confirm => 为 true 时,表示用户点击了确定按钮
* cancel => 为 true 时,表示用户点击了取消
*/
if (res.confirm) {
console.log('用户点击确定')
} else if (res.cancel) {
console.log('用户点击取消')
}
},
// 失败回调
fail: (err) => {
console.log('展示失败', err);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: (data) => {
console.log('展示', data);
}
})
wx.showActionSheet({
// 警示文案
alertText: '你有钱吗',
// 按钮的文字数组,数组长度最大为 6
itemList: ['吃饭', '喝水', '打豆豆', '睡觉'],
// 按钮的文字颜色
itemColor: '#0f0',
// 成功回调
success: (res) => {
/**
* tapIndex => 用户点击的按钮序号,从上到下的顺序,从0开始
*/
console.log('展示成功', res, res.tapIndex);
},
// 失败回调,监听取消
fail: (err) => {
console.log('展示失败', err);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: (data) => {
console.log('展示', data);
}
})
分享是小程序扩散的一种重要方式,小程序中有两种分享方式,通过 onShareAppMessage
此事件处理函数需要 return 一个 Object,用于自定义转发内容
点击右上角的菜单按钮,之后点击转发
直接配置 onShareAppMessage 方法即可
Page({
onShareAppMessage() {
return {
title: '我是标题', // 分享后显示的标题
path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径
imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片
}
}
})
监听用户点击页面内转发按钮 => button 组件 open-type="share"
页面设置后,再配置 onShareAppMessage 方法即可
// wxml
// js
Page({
onShareAppMessage() {
return {
title: '我是标题', // 分享后显示的标题
path: '/pages/logs/logs', // 分享后打开的路径,别人打开的页面的路径
imageUrl: '/assets/images/tabbar/cart_active.png' // 分享后显示的图片
}
}
})
获取当前设备的信息,用于手机信息或者进行一些适配工作
wx.getSystemInfo(Object object)
Page({
onShow() {
wx.getSystemInfo({
success: (res) => {
console.log('success', res);
},
fail: (err) => {
console.log('fail', err);
},
complete: (res) => {
console.log('complete', res);
},
})
}
})
对于用户的关键信息,比如获取用户的位置信息,需要获取用户的授权后才能获得
在app.json中进行配置
地址 : 全局配置 | 微信开放文档
{
"pages": [
"pages/index/index"
],
// 配置权限
"permission": {
// 配置位置权限
"scope.userLocation": {
// 弹出框中显示的内容
"desc": "我需要你的位置信息,马上给我"
}
},
"window": {
},
"tabBar": {
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
Page({
onShow() {
wx.getLocation({
type: 'wgs84', // wgs84 返回 gps 坐标
altitude: false,// 传入 true 会返回高度信息,但是会减慢接口返回速度
isHighAccuracy: true, // 开启高精度定位
highAccuracyExpireTime: 5000,// 高精度定位超时时间(ms),指定时间内返回最高精度,该值3000ms以上高精度定位才有效果
// 接口调用成功的回调函数
success: (res) => {
/**
* latitude => 纬度,范围为 -90~90,负数表示南纬
* longitude => 经度,范围为 -180~180,负数表示西经
* speed => 速度,单位 m/s,看当前设备是否在移动
* accuracy => 位置的精确度,反应与真实位置之间的接近程度,可以理解成10即与真实位置相差10m,越小越精确
* altitude => 高度,单位 m
* verticalAccuracy => 垂直精度,单位 m(Android 无法获取,返回 0)
* horizontalAccuracy => 水平精度,单位 m
*/
console.log('success', res);
},
// 接口调用失败的回调函数
fail: (err) => {
console.log('fail', err);
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: (res) => {
console.log('complete', res);
},
})
}
})
存储的代码执行完后,才会继续往后执行
也就是说,下一行代码就能获取到存储的值
Page({
onShow() {
// 存
wx.setStorageSync('name', 'coder')
wx.setStorageSync('age', 18)
wx.setStorageSync('array', [1, 2, 3, 4])
wx.setStorageSync('Object', { friends: '小明' })
// 取
console.log(wx.getStorageSync('name')); // coder
// 删
wx.removeStorageSync('name')
// 清空
wx.clearStorageSync()
}
})
不影响其他代码执行 => 存储后,不能立马获取到值
Page({
onShow() {
// 存
wx.setStorage({
key: 'name',
data: "coder",
encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 true
success: ({ errMsg }) => {
console.log(errMsg); // setStorage:ok
}
})
// 取
wx.getStorage({
key: 'name',
encrypt: true, // 2.21.3 => 若开启加密存储,setStorage 和 getStorage 需要同时声明 encrypt 的值为 true
success: ({ errMsg, data }) => {
console.log(errMsg, data); // getStorage:ok => coder
}
});
// 删
wx.removeStorage({
key: 'name',
success: ({ errMsg }) => {
console.log(errMsg); // removeStorage:ok
}
})
// 清空
wx.clearStorage({
success: ({ errMsg }) => {
console.log(errMsg); // clearStorage:ok
}
})
}
})
Page({
data: {
imagePath: ""
},
// 一、点击下载
onDownload() {
// 1. 获取手机相册权限
wx.authorize({
scope: 'scope.writePhotosAlbum',
success: () => {
// 2. 获取临时文件路径
this.getTempPath()
},
fail: () => {
wx.showToast({
title: '未授权,请前往微信设置页面中打开授权',
icon: 'none'
})
}
})
},
// 二、获取临时文件地址
getTempPath() {
wx.downloadFile({
// 真实图片地址
url: 'https://n.sinaimg.cn/sinakd10116/32/w787h845/20200723/14c6-iwtqvyk5713368.jpg',
success: ({ errMsg, tempFilePath }) => {
if (errMsg !== 'downloadFile:ok') {
return wx.showToast({
title: '下载失败',
icon: 'none'
})
}
// 3. 保存文件到手机相册
this.saveFile(tempFilePath)
// 也可展示到页面上
this.setData({
imagePath: tempFilePath
})
}
})
},
// 三、保存文件到手机相册
saveFile(filePath) {
// 下载图片到手机本地
wx.saveImageToPhotosAlbum({
filePath,
success: ({ errMsg }) => {
if (errMsg !== 'saveImageToPhotosAlbum:ok') {
return wx.showToast({
title: '下载失败',
icon: 'none'
})
}
wx.showToast({
title: '下载成功',
icon: 'none'
})
}
})
}
})
跳转到 tabBar 页面
并关闭其他所有非 tabBar 页面,使用 navigateBack 无法退回
// 跳转页面
wx.switchTab({
url: '/pages/text/text',
success: (res) => { console.log('success', res); },
fail: (err) => { console.log('fail', err); },
complete: (res) => { console.log('complete', res); },
})
保留当前页面,跳转到应用内的某个页面
但是不能跳到 tabbar 页面
// index页面
Page({
// 监听方法
handleClick() {
const name = 'coder'
const age = 19
// 跳转页面
wx.navigateTo({
// 地址 ?后面为携带的参数
url: `/pages/jump1/jump1?name=${name}&age=${age}`,
})
}
})
// ---------------------------------------------------------------------------
// pages/jump1/jump1.js
Page({
// 接受从index页面跳转过来时接受到的参数
onLoad(option) {
console.log(option); // {name: "coder", age: "18"}
}
})
wx.navigateBack(Object object) => 关闭当前页面,返回上一页面或多级页面
Page({
onShow() {
setTimeout(() => {
// 页面返回
wx.navigateBack({
// 默认返回上一页,可以设定
delta: 1
})
}, 3000);
}
})
在界面跳转过程中需要相互传递一些数据
使用URL中的query字段
// index
Page({
handleClick() {
const name = 'coder'
const age = 19
// 跳转页面
wx.navigateTo({
url: `/pages/jump1/jump1?name=${name}&age=${age}`,
})
}
})
在详情页内部拿到首页的页面对象,直接修改数据
// jump1页面
Page({
onShow() {
setTimeout(() => {
// 页面返回
wx.navigateBack({
// 默认返回上一页,可以设定
delta: 1
})
}, 3000);
},
// 拿到传递过来的数据
onLoad(option) {
console.log(option);
},
/**
* 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发
*/
// 页面被注销时调用
onUnload() {
// 1. 获取到已经存在的所有页面
const pages = getCurrentPages()
// 2. 拿到上一个页面的实例 当前页面为最后一个,所以上一个页面是减2
const prePage = pages[pages.length - 2]
// 3. 直接设置值
prePage.setData({ message: 'ccc' })
}
})
在小程序基础库 2.7.3 开始支持events参数,也可以用于数据的传递
使用URL中的query字段进行传递,定义events对象
// index页面
Page({
// 监听方法
handleClick() {
const name = 'coder'
const age = 19
// 跳转页面
wx.navigateTo({
url: `/pages/jump1/jump1?name=${name}&age=${age}`,
// 使用该参数
events: {
// 设置方法名 => 在子组件中调用该方法,传递数据过来
acceptData(data) {
console.log('acceptData', data); // {name:'coder'}
},
// 设置方法名
acceptOtherData(data) {
console.log('acceptOtherData', data); // {age:18}
}
}
})
}
})
使用eventChanner,传递数据到上一个页面
// jump1页面
Page({
onShow() {
setTimeout(() => {
// 页面返回
wx.navigateBack({
// 默认返回上一页,可以设定
delta: 1
})
}, 3000);
},
// 拿到传递过来的数据
onLoad(option) {
console.log(option);
},
/**
* 写在这里的理由 : 用户可能点击顶部状态栏中的返回键,写在这不管怎么返回,都会触发
*/
// 页面被注销时调用
onUnload() {
// 1. 拿到eventChanner渠道
const eventChanner = this.getOpenerEventChannel()
// 2. 通过渠道,拿到回调函数,并且传递数据给上一个页面
eventChanner.emit('acceptData', {
name: 'coder'
})
eventChanner.emit('acceptOtherData', {
age: 18
})
}
})
navigator组件主要就是用于界面的跳转的,也可以跳转到其他小程序中
跳转
跳转
跳转
openid : 当 在小程序 用微信功能登录时,每个微信都具备唯一标识openid
可把 openid 保存到数据库中,即使用户更换了手机,也能通过 openid 识别为同一用户
unionid : 在微信的不同产品之间可用来识别是否为同一用户
小程序的 openid 和 公众号的 openid,可能是不一样的,但是unionid一样
再开一个页面或窗口 => 进行账号绑定 || 手机号绑定
openid - unionid - 手机号 => 就建立了联系
登录操作
可以写到 app.js 的 onLaunch 中
也可以写到 页面.js 的 onLoad 中
Page({
/**
* onLoad登录操作
*/
onLoad() {
// 1. 判断token是否有值
const token = wx.getStorageSync('token') || ''
// 2. 判断token是否过期
// ......
// 有值 且 没过期
if (token && '没过期') {
// 做其他操作
} else {
// 3. 获取code
this.requestCode()
}
},
// 登录获取code
requestCode() {
wx.login({
success: ({ code }) => {
// 4. 将code发给后端
this.requestBack(code)
},
})
},
// 将code发给后端
requestBack(code) {
console.log(code);
wx.request({
url: 'https://www.baidu.com',
data: { code },
method: 'POST',
success: (res) => {
// 5. 拿到身份标识( 自定义登录态 ),可能不会返回openid, unionid,看后端
const { openid, unionid, token } = res.data
// 6. 把 自定义登录态 存入storage
wx.setStorageSync('token', token)
},
})
}
})
git操作都是大同小异,详细的可以看我之前写的git文章
网址 : 版本控制工具 之 Git_玄鱼殇的博客