01
JSON 配置
配置文件,app.json是当前小程序的全局配置,page.json是局部配置,可以独立定义每个页面的一些属性
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html
pages字段
存放小程序所有页面路径,模拟器会显示数组第一项的页面
tabBar字段
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar
tab 栏可以通过tabBar配置,list表示tab 的列表,接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:
"tabBar": {
"list": [
{
//页面路径,必须在 pages 中先定义
"pagePath": "pages/home/home",
//tab 上按钮文字
"text": "home",
//图片路径,当 position 为 top 时,不显示 icon
"iconPath": "./icon/首页_home.png",
//选中时的图片路径
"selectedIconPath": "./icon/首页_home (1).png"
},
{
"pagePath": "pages/shopping/shopping",
"text": "shopping",
"iconPath": "./icon/购物车_shopping.png",
"selectedIconPath": "./icon/购物车_shopping (1).png"
}
],
"color": "#666",
"selectedColor": "#2F88FF",
"backgroundColor": "#eee",
"borderStyle": "white"
},
window字段
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#window
用于设置小程序的状态栏、导航条、标题、窗口背景色
"window": {
//下拉 loading 的样式,仅支持 dark / light
"backgroundTextStyle": "dark",
//是否开启全局的下拉刷新。
"enablePullDownRefresh": true,
//窗口的背景色
"backgroundColor": "#fcf",
//导航栏背景颜色
"navigationBarBackgroundColor": "#ccf",
//导航栏标题文字内容
"navigationBarTitleText": "day01",
//导航栏标题颜色,仅支持 black / white
"navigationBarTextStyle": "black"
},
WXML 模板
标签
view是块级元素类似于div标签,text是行内元素类似于span标签,block是空标签类似于template标签
图片 image组件
小程序的image组件默认宽度320px,高度240px,使用mode属性来设置图片裁剪、缩放的模式
widthFix表示宽度占满,高度跟随原图比例做自适应,heightFix同理,其他模式无法显示全图
WXSS 样式
单位
尺寸单位为rpx可以根据屏幕宽度进行自适应。1px=2rpx
样式
对同一个选择器,页面样式表比公共样式表拥有更高的权重,页面的根元素是page
JS 逻辑交互
处理一些逻辑事件,接受一个对象类型参数
全局:App()
局部单个页面:Page()
数据data
data是一个对象,使用时用双花括号将变量包起来,文本渲染用双花括号,属性值也是用双花括号
data-xxx为自定义属性
<checkbox data-num="{{num}}" checked="{{checked}}" />
Page({
data: {
checked: false,
num: 1,
},
});
上面的checked值还可以写成如下:
<checkbox checked="{{false}}" />
注意:如果直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值
数据路径运算:显示对象的某一属性值或数组的某一下标值称为数据路径运算
<view>{{obj.name}}</view>
<view>{{arr[0]}}</view>
全局数据
全局数据定义在app.js的globalData中,**getApp()**获取到到App实例之后在通过app.globalData.xxx获取到数据
const app = getApp()
const safeAreaHeight = app.globalData.safeAreaHeight
02
事件
事件绑定
用bind来绑定事件,用catch来捕获事件,不能在方法名后面携带参数
语法:bind(catch)+事件类型,bind(catch)事件类型之间可以加冒号
注意点:小程序的事件名直接写在最外层,不需要写在methods里面
事件对象
用基础事件对象e来接收,在基础事件对象中可以获取到id属性和data-xx自定义属性
currentTarget和target的区别
事件是绑定在谁身上,currentTarget就指向谁
事件触发在谁身上,target就指向谁
setData修改数据
直接修改this.data只是改了逻辑层的数据,没有更新视图层
调用this.setData既修改了逻辑层的数据,还更新了视图层
1,setData第一个参数是对象类型,第二个参数更新渲染完毕后的回调函数
2,尽可能的去合并setData,setDatab比较消耗性能
3,可以不经过data定义,直接setData新增字段
4,数组或对象的某一项可以单独修改
数据双向绑定
1,输入框的val值通过bindinput的事件对象e拿到数据,在通过this.setData来更新data里面的值
2,model:value支持数据双向绑定,但是不支持数据路径的数据双向绑定
if和hidden
wx:if为真时才渲染,如果不经常切换使用wv:if,多个条件判断时候搭配wx:elif,wx:else来使用
hidden为真时只是样式上被隐藏了,如果频繁切换使用hidden
判断多个组件标签时候可以用block标签包裹,block不会在页面中做任何渲染,只接受控制属性
for
wx:for,默认的数组项变量名为item,默认下标变量名为index
使用wx:for-item来改变数组项的变量名,使用wx:for-index来改变下标的变量名
wx:key表示唯一的标识符
1,**this,item本身是一个唯一的字符串或者数字才可以,能用index作为key值但是不推荐
2,id
03
路由跳转
switchTab
跳转到tabBar页面用switchTab,此时页面全部出栈,只留下新的 Tab 页面
<!-- 跳转到tab页面 -->
<button bindtap="toTabB">跳转到tabB页面</button>
<!-- 导航组件方式 -->
<navigator url="../tabB/tabB" open-type="switchTab">跳转到tabB页面</navigator>
toTabB() {
wx.switchTab({
url: '../tabB/tabB',
})
}
navigateTo
跳转到普通页面用navigateTo,可以传参,在通过onLoad的参数获取
传参方式是在路径后写问号,问号后是key=val这种形式,不同的key=va1之间用&去隔开
还有两种方式可以在路径后传参,是redirectTo和reLaunch,switchTab不能传参
<!-- 跳转到普通页面 -->
<button bindtap="toPageX">跳转到普通页面</button>
<!-- 导航组件方式 -->
<navigator url="../x/x?a=1" open-type="navigate">跳转到普通页面</navigator>
toPageX() {
wx.navigateTo({
url: '../x/x?a=1&b=2&id=3',
})
}
navigateBack
返回用navigateBack,注意导航组件的方式不需要写url了,此时页面不断出栈
默认返回上一页,delta是返回的层级,如果返回层级大于现有的页面只能返回最开始的页面
<button bindtap="goBack">返回上一页</button>
<navigator open-type="navigateBack" delta="1">返回上一页</navigator>
goBack() {
wx.navigateBack({
delta: 1,
})
},
reLaunch
重启动用reLaunch,此时页面全部出栈,只留下新的页面,点击小房子图标会回到路由第一个路径的页面
<button bindtap="reLaunchToZ">重启动到页面z</button>
<navigator url="../z/z" open-type="reLaunch">重启动到页面z</navigator>
reLaunchToZ() {
wx.reLaunch({
url: '../z/z',
})
},
redirectTo
重定向用redirectTo,此时当前页面出栈,新页面入栈
<button bindtap="redirectToZ">重定向到页面z</button>
<navigator url="../z/z" open-type="redirect">重定向到页面z</navigator>
redirectToZ() {
wx.redirectTo({
url: '../z/z',
})
},
页面生命周期
onLoad(query):页面加载时触发
onShow():页面展示或切入前台时触发
onReady():页面初次渲染完成时触发
onHide():页面隐藏或切入后台时触发
onUnload():页面卸载时触发
1,页面进栈执行onLoad onShow onReady
2,隐藏执行onHide,出栈执行onUnload,多次显示执行onShow
3,特殊:tab页面从头到尾只会执行一次onLoad,切换tab执行的是onHide和onShow,
按照文档,tab切换是属于出栈的,但是不会执行onUnload和onLoad
4,onLoad中能获取和更新data的数据一般还会在onLoad里面去调用接口获取数据渲染页面,还可以在 onLoad 的参数中获取到当前页面路径中的参数
5,什么情况会执行onUnload? 例如:1.y返回x,y出栈 2.y重定向到z,y出栈 3.y重启动到z,除了z之外的页面都出栈
全局生命周期
onLaunch():监听小程序初始化,只会执行一次,比如去调用接口,判断手机是否需要进行安全区域适配
onShow():监听小程序启动或者是切前台
onHide():监听小程序切后台
WXS语法
在视图层里不能运行js,wxs可以在模板中去使用js处理一些数据,不支持es6语法,有点类似vue的过滤器
导出时使用module.exports导出方法或变量,引入wxs路径(src)时给wxs模块(module)起名字来使用
<wxs src="../wxs/price.wxs" module="priceModule" />
<view>
<!-- {{price.toFixed(2)}} -->
{{price2}}//通过this.setData修改
{{priceModule.handlePrice(price)}}
{{priceModule.handlePrice2(price)}}
</view>
function handlePrice(price) {
return price.toFixed(2)
}
function handlePrice2(price) {
return price.toFixed(2) + '元'
}
module.exports = {
handlePrice: handlePrice,
handlePrice2: handlePrice2
}
数据缓存
小程序中不需要通过JSON.stringify序列化的对象
同步
存缓存:wx.setStorageSync(key, value)
取缓存:wx.getStorageSync(key)
删某一个缓存:wx.removeStorageSync(key)
清空缓存:wx.clearStorageSync()
异步
存进去的缓存不需要马上用到,就可以用异步,不会阻塞下面的执行
异步会返回Promise对象,因此缓存异步语法支持.then操作
存缓存:wx.setStorage({
key: xxx,
data: xxx,
success() {}, //成功的回调函数,代表存储成功
fail() {} // 失败的回调
})
取缓存:wx.getStorage({
key: xxx,
success(res) {
console.log(res.data) //拿到当前这个key的值
}
})
删某一个缓存:wx.removeStorage({
key: 'str',
success() { }
})
清空缓存:wx.clearStorage({
success() {}
})
或者:wx.clearStorage().then(() => { })
day04
自定义组件的使用
1,创建:新建Component,引入时在usingComponents里引入,左边写自定义组件名右边写文件路径,使用 时把自定义组件名当标签名使用
2,properties为组件的属性列表,父传子过来的参数 (类似于Vue的props),定义属性简化的写法为:属性:类型
完整写法为:属性: {type: xxx,value: xxx'}
3,组件的方法要写在methods里面,可以在这里触发自定义事件,由父级去监听
4,组件自定义事件语法为:this.triggerEvent(事件名,参数(子传父的数据),事件选项(了解即可) ),要写多个 参数时采用对象的方式,类似Vue的this.$emit(事件名,参数1,参数2,...)
5,使用时与vue不同之处,:parentdata="msg" 变成 parentdata="",冒号变成双花括号
@clickChild="clickChild" 变成 bind:clickChild="clickChild",**@变成bind**
注意:在自定义组件样式中不要使用id选择器
插槽
匿名插槽:组件内 微信小程序不支持默认值,调用时在组件标签内传递插槽内容
具名槽口: 组件内调用时通过slot属性指定对应的名称
小程序默认不支持多个插槽,需要去子组件的js配置,开启多个插槽选项options: { multipleSlots: true }
下拉刷新
1,"enablePullDownRefresh": true:开启下拉刷新(json文件中配置)
2,onPullDownRefresh:监听下拉刷新事件,可以在这里去发送请求,获取 最新的数据,重新渲染页面
3,onPullDownRefresh:停止下拉刷新
4,startPullDownRefresh:开始下拉刷新的动作,会自动触发onPullDownRefresh里面的逻辑
上拉触底
1,onReachBottom:监听上拉触底
2,onReachBottomDistance:页面上拉触底事件触发时距页面底部距离(json文件中配置)
项目
底部安全区域适配
通过获取系统信息,判断手机是否有底部安全区域
1,wx.getSystemInfo:获取系统信息,可以通过成功回调函数的参数可以拿到对应的属性值screenHeight(屏幕 高度)和safeArea(安全区域)
2,screenHeight - safeArea.bottom即可得到底部安全区域高度
3,在把底部安全区域高度存缓存里面,要用的时候在取出来
App({
onLaunch() {
wx.getSystemInfo({
success: (res) => {
// console.log(res);
const {
screenHeight,
safeArea
} = res
let safeAreaHeight = screenHeight - safeArea.bottom
wx.setStorageSync('safeAreaHeight', safeAreaHeight)
},
})
}
})
Page({
data: {
safeAreaHeight: 0
},
onLoad() {
const safeAreaHeight = wx.getStorageSync('safeAreaHeight')
this.setData({
safeAreaHeight
})
},
})
<view style="padding-bottom: {{safeAreaHeight}}px;">xxx</view>
方法二,直接存在全局数据里面,在通过App实例获取数据
App({
globalData: {
safeAreaHeight: 0
},
onLaunch() {
wx.getSystemInfo({
success: (res) => {
// console.log(res);
let {
screenHeight,
safeArea
} = res
this.globalData.safeAreaHeight = screenHeight - safeArea.bottom
console.log(this.globalData.safeAreaHeight);
},
})
}
})
let app = getApp()
Page({
data: {
safeAreaHeight: app.globalData.safeAreaHeight
}
})
自定义tabBar
https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html
1,配置tabBar,配置custom字段,设置 "custom": true,开启自定义tabBar功能
2,新建custom-tab-bar的文件夹,并在其中添加名为index的组件页面
3,使用vant的Tabbar组件,wx:for渲染数据
4,通过onChange事件对象e拿到索引,根据索引来实现路由跳转(wx.switchTab)
5,去每个页面onShow生命周期中通过this.getTabBar获取组件实例,并调用 setData修改active的值来实现 tabBar图标的高亮
注意:使用自定义tabBar,tab页面会受安全区域影响,安全区域高度需要加上自定义tabBar的高度
自定义导航栏
1,去widow配置"navigationStyle": "custom"
2,创建自定义导航栏组件,使用固定定位到顶部,注意在wxss里面,不能使用本地图片
自定义按钮组件
1,封装按钮组件,在properties里面定义组件的属性数据通过父级传过来
2,在methods里面触发自定义事件,让父级监听
自定义底部文字组件
1,封装底部文字组件,在properties里面定义数组通过父级传过来,数据项使用wx:for循环
2,在properties里面定义底部安全区域通过父级传过来
获取用户信息wx.getUserProfile
1,调用wx.getUserProfile开放接口,获取用户信息,页面产生点击事件后才可调用
2,需要去调试基础库减低版本低于2.27.1(详情,本地设置,调试基础库)
<button bindtap="handleGetUserProfile">获取用户信息</button>
handleGetUserProfile() {
wx.getUserProfile({
//必须写desc
desc: "用于完善会员资料", //声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res);
},
fail: (err) => {
console.log(err);
},
});
},
如果基础库版本太高可以通过头像昵称填写能力获取
头像昵称填写能力
获取用户头像
1,需要将 button 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径
2,在通过事件对象e中获取到头像信息在显示在图片中
<button open-type="chooseAvatar" bind:chooseavatar="handChooseAvatar">获取用户头像</button>
<image src="{{avatarUrl}}" style="width: 100rpx;height: 100rpx;" />
handChooseAvatar(e) {
console.log(e);
this.setData({
avatarUrl: e.detail.avatarUrl
})
}
获取用户昵称
1,需要将 input 组件 type 的值设置为 nickname,当用户在此 input 进行输入时,键盘上方会展示微信昵称
2,在通过bindinput监听输入事件显示在页面中
注意:输入框是原生组件,pc端模拟器会有问题,开发者在使用到原生组件时尽量在真机上进行调试
<input type="nickname" placeholder="获取用户昵称" value="{{nickname}}" bindinput="handleInput" />
<view>昵称:{{nickname}}</view>
// 获取用户昵称,监听用户名称输入,pc端模拟器会有问题
handleInput(e) {
console.log(e);
this.setData({
nickname: e.detail.value
})
}
获取手机号
需要将 button 组件 open-type 的值设置为 getPhoneNumber
当用户点击并同意之后,可以通过 bindgetphonenumber 事件回调获取到动态令牌code,然后把code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,用code来换取用户手机号。每个code有效期为5分钟,且只能消费一次
注意:个人开发者不能调用该接口,开发时可以用测试号体验
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNum">获取手机号</button>
//把e.detail.code通过接口给后端,后端拿到code后去微信后台换取手机号,然后再通过接口把手机号传给前端
getPhoneNum(e) {
console.log(e);
},
获取位置wx.getLocation
1,在 app.json 中配置requiredPrivateInfos
2,还需要用户授权,小程序接口权限设置permission,scope.userLocation精确地理位置,desc为必填字段
3,调用 wx.openSetting 打开设置授权地理位置界面 ,这个api只能由用户主动产生点击行为去触发
<button bindtap="handleOpenSetting">点击授权地理位置</button>
onShow() {
// 获取地理位置
wx.getLocation({
type: 'wgs84', //gps坐标
// 如果授权过一次,后续用wx.getLocation获取地理位置默认都是成功
success(res) {
console.log(res);
const latitude = res.latitude
const longitude = res.longitude
const speed = res.speed
const accuracy = res.accuracy
},
// 如果拒绝过一次,后续用wx.getLocation获取地理位置默认都是失败
fail: err => {
console.log(err);
}
})
},
handleOpenSetting() {
wx.openSetting()
},
"requiredPrivateInfos": [
"getLocation"
],
"permission": {
"scope.userLocation": {
"desc": "收集地理位置为了更好的服务" //接口用途说明
}
}
打开地图选择位置wx.chooseLocation
在 app.json 中配置requiredPrivateInfos 在调用wx.chooseLocation即可
"requiredPrivateInfos": [
"chooseLocation"
],
handleChooseLocation() {
wx.chooseLocation({
success: (res) => {
console.log(res);
},
fail: (err) => {
console.log(err);
}
})
}
打包
上传之后,去微信公众平台中的版本管理里面提交审核即可
分包
整个小程序,主包加分包不能超过20M,单个包不能超过2M
如果包太大可以使用分包,在 app.json subpackages 字段声明项目分包结构
{
"pages":[
xxx
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
wx.downloadFile
使用 wx.downloadFile 方法下载一个文件,下载成功之后会将文件保存到临时文件夹中,然后使用wx.openDocument 方法打开该文件,如果没有配置合法域名会报错,解决方法如下:
1,在详情=>本地设置=>不校验合法域名
2,在微信公众平台=>开发管理=>开发设置=>服务器域名中配置合法域名
onCheck() {
wx.downloadFile({
url: "https://hxyyxy.nwsuaf.edu.cn/docs/2020-08/db2f3058866c4280ac9b2e05410ea87c.pdf",
success: function (res) {
const filePath = res.tempFilePath; //临时文件夹路径
wx.openDocument({
filePath: filePath,
});
},
});
}
