原生小程序基础笔记
一、小程序目录结构
小程序主要提供了 4 种文件类型:
类型名称 | 作用 | 是否必须存在 |
---|---|---|
.wxml | 用于页面的布局结构,相当于网页中 .html 文件 | 是 |
.wxss | 用于页面的样式,相当于网页中的 .css 文件 | 否 |
.js | 用于页面的逻辑 | 是 |
.json | 用于页面的配置 | 否 |
文件作用
文件名 | 作用 | 是否必须存在 |
---|---|---|
app.js | 小程序入口(首先执行的文件) | 是 |
app.json | 小程序的全局配置 | 是 |
app.wxss | 小程序的全局样式 | 否 |
project.config.json | 小程序开发者工具配置 | 是(会自动创建) |
sitemap.json | 小程序搜索优化 | 否 |
二、配置文件
小程序配置文件是一种json格式的文件。
作用:可以起到快速新建页面、设定小程序首页、设置窗口样式及设置导航栏和底部tabBar等作用。
分类:
- 全局 app.json
- 页面 page.json
app.json 是当前小程序的全局配置,包括了:
- 小程序首页
- 界面表现
- 网络超时时间
- 底部 tab
- …等配置
1.全局配置
pages
用于配置小程序的页面路径。这个配置项是一个数组,每个元素都是一个字符串,表示小程序包中的一个页面路径。
App({
"pages": [
'pages/index/index', // 首页
'pages/about/about', // 关于页面
'pages/contact/contact' // 联系页面
...
]
...
})
window
用于设置小程序的状态栏、导航条、标题、窗口背景色。
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
navigationBarTitleText | string | 空白 | 导航栏标题文字内容 |
navigationBarTextStyle | string | black | 导航栏标题颜色,仅支持 black / white |
navigationBarBackgroundColor | 16 进制颜色 | #00000 | 导航栏背景颜色,如 #000000 |
navigationStyle | string | default | 导航栏样式,仅支持 default / custom |
enablePullDownRefresh | boolean | false | 是否开启全局的下拉刷新 |
… 还有更多 |
App({
...
"window": {
// 导航栏文本颜色
"navigationBarTextStyle": "black",
// 导航栏标题文本
"navigationBarTitleText": "首页",
// 导航栏背景颜色
"navigationBarBackgroundColor": "#ff0000",
// 背景颜色
"backgroundColor": "#ccc",
// 背景文本样式
"backgroundTextStyle": "light",
// 启用下拉刷新
"enablePullDownRefresh": true
...
},
...
})
tabBar
常见配置属性
属性 | 类型 | 默认值 | 是否必须 | 说明 |
---|---|---|---|---|
list | array | 无 | 是 | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab |
color | 16 进制颜色 | 无 | 否 | tab 上的文字默认颜色,仅支持十六进制颜色 |
selectedColor | 16 进制颜色 | 无 | 否 | tab 上的文字选中时的颜色,仅支持十六进制颜色 |
backgroundColor | 16 进制颜色 | 无 | 否 | tab 的背景色,仅只持 16 进制颜色 |
borderStyle | string | black | 否 | tabbar 上边框的颜色, 仅支持 black / white |
position | string | bottom | 否 | tabBar 的位置,仅支持 bottom / top |
上述配置中 list 具体又包含以下内容:
属性 | 类型 | 默认值 | 是否必须 | 说明 |
---|---|---|---|---|
pagePath | string | 是 | 页面路径,必须在 pages 中先定义 | |
text | string | 是 | tab 上按钮文字 | |
iconPath | string | 否 | 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片,当 position 为 top 时,不显示 icon | |
selectedIconPath | string | 否 | 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片,当 position 为 top 时,不显示 icon |
App({
...
"tabBar": {
// 标签栏文字颜色
"color": "#000000",
// 选中标签栏文字颜色
"selectedColor": "#00b26a",
// 标签栏背景颜色为白色
"backgroundColor": "#FFFFFF",
// 标签栏边框样式
"borderStyle": "white",
// 标签栏位置在底部
"position": "bottom",
"list": [
{
// 页面路径
"pagePath": "pages/index/index",
// tab文字
"text": "首页",
// 未选中时的图标路径
"iconPath": "static/tabbar/home-default.png", // 选中时的图标路径
"selectedIconPath": "static/tabbar/home-active.png"
...
},
...
})
2.页面配置
页面配置只针对某个页面生效,如 index.json 是针对 index 页面生效,demo.json 只针对页面 demo 生效
- 不用写window字段
- 优先级比全局配置高
页面配置只针对某个页面生效,如 index.json 是针对 index 页面生效,demo.json 只针对页面 demo 生效
- 不用写window字段
- 优先级比全局配置高
pages
- 用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。
- 未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。
- 可以通过先在pages里写页面路径,然后保存的方式来快速新建页面。 注意:新建的页面,如果路径没在pages里面配置,则无法跳转到该页面
常用配置
属性 | 类型 | 默认值 | 是否必须 | 说明 |
---|---|---|---|---|
navigationBarTitleText | string | 空白 | 否 | 导航栏标题文字内容 |
navigationBarTextStyle | string | black | 否 | 导航栏标题颜色,仅支持 black / white |
navigationBarBackgroundColor | 16 进制颜色 | #00000 | 否 | 导航栏背景颜色,如 #000000 |
navigationStyle | string | default | 否 | 导航栏样式,仅支持 default / custom |
enablePullDownRefresh | boolean | false | 否 | 是否开启全局的下拉刷新 |
{
// 使用到的自定义组件,这里是一个空对象
"usingComponents": {},
// 导航栏背景颜色为绿色
"navigationBarBackgroundColor": "#00b26a",
// 导航栏文本颜色为黑色
"navigationBarTextStyle": "black",
// 禁用下拉刷新功能
"enablePullDownRefresh": false,
// 导航栏标题文本为"购物车"
"navigationBarTitleText": "购物车"
...
}
三、布局相关
部分选择器标签
组件名(标签) | 作用 | 与 html 对比 |
---|---|---|
view | 定义一个块级元素 | 相当于 html 中的 div 标签 |
text | 定义一个行内元素 | 相当于 html 中的 span 标签 |
小程序页面布局中的样式几乎和网页的 css 是一样的,部分选择器
选择器 | 示例 | 含义 |
---|---|---|
类选择器 | .navs | 根据类名选择元素 |
标签选择器 | text、view | 根据标签名选择元素 |
后代选择器 | .navs text | 根据标签的嵌套关系选择元素 |
四、小程序适配 响应式单位rpx
rpx (responsive pixel):规定不管屏幕为多少px,100%的屏幕宽度就是750rpx
100%屏幕的宽度 = 750rpx
实际开发当中设计稿的尺寸都是【以 750px 做为基准】,因此只需要将设计稿中看到的尺寸写成相应的 rpx 即可。
五、wxss引入资源
1.使用图片
wxss中不可以使用本地图片资源,可以使用网络图片,或者将图片转成base64
page {
background-image: url("data:image/png;base64,...");
}
.ctn{
background-image: url('https://www.../.png');
}
2.使用字体图标
wxss中使用字体图标时,字体资源必须是在线链接
@font-face {
font-family: "iconfont";
src: url('//at.alicdn.com/t/c/font_3509481_3gqwsneat14.woff2?t=1675394145994') format('woff2'),
url('//at.alicdn.com/t/c/font_3509481_3gqwsneat14.woff?t=1675394145994') format('woff'),
url('//at.alicdn.com/t/c/font_3509481_3gqwsneat14.ttf?t=1675394145994') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-clock:before {
content: "\e74b";
}
六、数据绑定
数据绑定步骤
1.在data中定义数据
Page({
data: {
属性1: "值1",
num:1
img: '/static/uploads/goods-1.jpg',
...
}
})
2.在模板中使用数据mustache(插值表达式)语法
<view>{{num}}</view>
<image src="{{img}}"/>
<text>{{ count >20?'成功':'失败' }}</text>
七、事件绑定
1.语法
小程序中绑定事件的语法有两种
<!-- bind事件名="事件回调" -->
<button type="warn" bindtap="fn">警告</button>
<!-- bind:事件名="事件回调" -->
<button type="primary" bind:tap="fn">成功</button>
2.事件捕获与冒泡
冒泡
bind用于绑定事件冒泡
<button bind:tap="fn">父</button>
catch用于阻止冒泡
<button catch:tap="fn">父</button>
捕获
capture 用于绑定事件捕获
capture-bind只能用冒号形式
<button capturn-bind:tap="fn">父</button>
capture-catch可以阻止冒泡、捕获事件
<button capturn-catch:tap="fn">父</button>
3.事件传参
错误写法: 小程序会以为 事件函数名称就是 “printNum(1)” ,那么它就会去找“printNum(1)” 这个函数 而不是 “printNum"
<!-- 错误写法 -->
<view class="item" data-num="1" bindtap="printNum(1)" />
正确写法:通过自定义属性传递
<view class="item" data-num="1" bindtap="printNum">
Page({
// e是事件对象,一般命名e/ev/event
printNum(e) {
const num = e.currentTarget.dataset.num;
console.log(num);
},
});
target及currentTarget的区别
target:事件发生地。事件真实发生的元素。 currentTarget: 事件绑定地。bind事件书写的那个元素。
事件对象属性
属性 | 类型 | 说明 |
---|---|---|
type | String | 事件类型 |
timeStamp | Integer | 页面打开到触发事件所经过的毫秒数 |
target | Object | 触发事件的组件的一些属性值集合 |
currentTarget | Object | 当前组件的一些属性值集合 |
detail | Object | 额外的信息 |
mark | Object | 承载额外数据 |
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
注意:
mark和dataset的区别
- mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值;
- dataset 仅包含一个节点的 data- 属性值
七、获取和设置data数据
小程序的渲染层与逻辑层
- WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层
- 小程序的渲染层和逻辑层分别由2个线程管理,两个线程的通信会经由微信客户端做中转
直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致
this.setData({
属性名1: 新值1,
属性名2: 新值2
})
//示例
Page({
data: {
num: 0,
},
handleAdd() {
// 获取data里的数据
let num = this.data.num;
// 更新
this.setData({
num: ++num,
});
}
});
注意:
获取data中的数据是this.data.xxx
八、双向绑定与表单元素
获取输入框的值的方式
1.监听事件
<input bindinput="handleInput" value="name" type="text" placeholder="请输入姓名" />
Page({
data: {
name: "",
},
handleInput(e) {
console.log(e.detail.value);
const name = e.detail.value;
this.setData({
name,
});
},
});
2.简易双向绑定
<input model:value="{{name}}" type="text" placeholder="请输入姓名" />
注意:
- 并不是所有的表单元素都支持数据双向绑定,其中 input、textarea、slider 组件可以支持。
- 简易双向绑定不支持路径。(例:页面的数据为{data: {person: {name: ‘’}}},将输入框中的值赋值给person下的name属性)
九、列表渲染
<!--基础用法-->
<view wx:for="{{list}}">
<!--
wx:for 结构内可以使用两个变量
item 循环项
index 循环索引
-->
{{item}} ------ {{index}}
</view>
<!-- 手动指定索引和当前项的变量名 -->
<view
wx:for="{{list}}"
wx:for-item="value"
wx:for-index="key"
>
{{value}}-------{{key}}
</view>
注意:引号和大括号 中间不要留有空白
key的用法
wx:key 针对不同的数组类型有不同的写法
*普通数组 wx:key="this"
Page({
data: {
list: [11, 22, 33, 44, 55]
})
<view wx:for="{{list}}" wx:key="*this">
当前索引号:{{index}}-------当前项:{{item}}
</view>
数组对象 wx:key=“具有唯一性的某个属性名”
Page({
data: {
list2: [{ id: 1, name: '周树人' }, { id: 2, name: '鲁迅' }]
}
})
<view wx:for="{{list2}}" wx:key="id">
当前索引号:{{index}}-------当前项:{{item.name}}
</view>
作用:
- 性能优化:
wx:key
的主要作用是帮助小程序更高效地更新渲染列表。当列表中的某一项发生变化时,小程序会根据wx:key
所指定的值来快速定位变化的项,而不是重新渲染整个列表。 - 唯一性标识:
wx:key
用于标识列表中每一项的唯一性。它通常会使用列表项的唯一标识(如数据中的某个属性),确保在列表中的每一项都有一个独特的标识。
十、条件渲染
wx:if
- 使用 wx:if 可以完全移除或重新渲染包含该指令的节点。
- 当条件为真时,该节点会被渲染出来,而当条件为假时,该节点将被从 DOM 树中移除。
- 适用于需要在不同条件下完全切换元素的场景,但频繁切换会有性能开销。
<view wx:if="{{gender === 1}}">
男
</view>
<view wx:elif="{{gender === 0}}">
女
</view>
<view wx:else>
未知
</view>
hidden
- 使用hidden属性可以简单地隐藏或显示一个节点,但该节点始终存在于 DOM 中。
- hidden 是通过样式(none/block)来实现元素的显示或隐藏。
- 适用于频繁切换元素的场景,因为节点一直存在,切换时不需要重新渲染。
<view hidden="{{isHidden}}">
这里是hidden盒子
</view>
十一、image组件
特点:
1.支持 JPG、PNG、SVG、WEBP、GIF 等格式。
2.默认大小为 320px * 240px(相框大小)
3.通过mode属性控制相片在相框的渲染效果
4.支持懒加载
常用属性
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
src | String | 图片资源地址 | |
mode | String | ‘scaleToFill’ | 图片裁剪、缩放的模式 |
lazy-load | boolean | false | 图片懒加载,在即将进入一定范围(上下三屏)时才开始加载 |
mode的常用取值
模式 | 值 | 说明 |
---|---|---|
缩放 | scaleToFill | 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 |
缩放 | aspectFit | 保持纵横比缩放图片,直到图片某一边碰到边界。 |
缩放 | aspectFill | 保持纵横比缩放图片,直到图片完全铺满边界。 |
缩放 | widthFix | 宽度不变,高度自动变化,保持原图宽高比不变 |
<image src="./cat.jpg" mode="scaleToFill"/>
<image src="./cat.jpg" mode="aspectFit"/>
<image src="./cat.jpg" mode="aspectFill"/>
<image src="./cat.jpg" mode="widthFix"/>
十二、小程序内置组件
1.swiper轮播图组件
特点:
swiper可以理解为小程序内置的轮播图标签,拥有了它可以让我们特别方便实现轮播功能。
默认宽度 和 高度 为 100% * 150px
常用属性
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
indicator-dots | Boolean | false | 是否显示面板指示点 |
autoplay | Boolean | false | 是否自动切换 |
circular | Boolean | false | 是否衔接轮播 |
示例
<swiper indicator-dots autoplay circular>
<swiper-item>
<image src=""></image>
</swiper-item>
<swiper-item>
<image src=""></image>
</swiper-item>
<swiper-item>
<image src=""></image>
</swiper-item>
</swiper>
2.navigator导航标签
特点:
1.类似以前web中的a标签。
2.块级元素
3.通过 url 来指定跳转的页面
4.还可以跳到其他小程序
常用属性
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
url | string | 当前小程序内的跳转链接 | |
open-type | string | navigate | 跳转方式 |
target | String | self | 在哪个目标上发生跳转,默认当前小程序 |
参考代码
<!-- 只能打开非 tabBar 页面 -->
<navigator url="/pages/swiper/index">以默认方式open-type="navigate"跳轮播图页面</navigator>
<navigator open-type="redirect" url="/pages/swiper/index">以open-type="redirect"跳轮播图页面</navigator>
<!-- 只能打开 tabBar 页面 -->
<navigator open-type="reLaunch" url="/pages/swiper/index">以open-type="reLaunch"跳轮播图页面</navigator>
<!-- open-type="switchTab" 只能跳转tabBar页面,非tabBar页面不能跳转 -->
<navigator open-type="switchTab" url="/pages/index/index">以open-type="switchTab"跳轮首面</navigator>
-------跳转其它小程序--------
<!-- 方式一:通过app-id -->
<navigator target="miniProgram" app-id="wx7696c66d2245d107">跳转蜜雪冰城</navigator>
<!-- 方式一:通过short-link -->
<navigator target="miniProgram" short-link="#小程序://蜜雪冰城/a2FGdG8xwuFeJdB">跳转蜜雪冰城</navigator>
总结
- navigateTo, redirect 只能打开非 tabBar 页面。
- switchTab 只能打开 tabBar 页面。
- reLaunch 可以打开任意页面。
页面栈
1.每次通过navigate方式跳转时,原页面并没有被销毁,而是放入了内存中,这样返回到上级页面时,就能快速打开,而不是重新创建。
2.这样多次调用后会形成一个层级结构,我们把这个层级结构就叫做页面栈。
3.小程序宿主环境限制了页面栈的最大层级为 10 层 ,当页面栈到达 10 层之后就没有办法再推入新的页面了
返回按钮
1.一般情况下页面栈长度大于1就会出现返回按钮,否则没有,可通过getCurrentPages()获取页面栈。
2.若页面设置了navigationStyle: “custom”,则不管页面栈长度多少都不会有返回按钮。
open-type
假设小程序当前页面栈为 [ pageA, pageB, pageC ],其中pageA在最底下,pageC在最顶上,也就是用户所看到的界面。则:
1.navigate
使用 open-type=“navigate” url=“pageD” (相当于wx.navigateTo({ url: ‘pageD’ }) )可以往当前页面栈多推入一个 pageD,此时页面栈变成 [ pageA, pageB, pageC, pageD ] 。
2.navigateBack
使用 open-type=“navigateBack” (相当于 wx.navigateBack()) 可以退出当前页面栈的最顶上页面,此时页面栈变成 [ pageA, pageB, pageC ] 。
3.redirect
使用open-type=“redirect” url=“pageE” (相当于 wx.redirectTo({ url: ‘pageE’ })) 是替换当前页变成pageE,此时页面栈变成 [ pageA, pageB, pageE ] 。当页面栈到达10层没法再新增的时候,往往就是使用redirectTo这个API进行页面跳转。
4.switchTab
使用open-type=“switchTab” url=“pageF” (相当于wx.switchTab({ url: ‘pageF’ }),此时原来的页面栈会被清空,然后会切到pageF所在的tab页面,页面栈变成 [ pageF ]
5.reLaunch
使用open-type=“reLaunch” url=“pageH” (相当于wx. reLaunch({ url: ‘pageH’ })) 重启小程序,并且打开pageH,此时页面栈为 [ pageH ]
十三、生命周期
分类
- 应用生命周期
- 页面生命周期
- 组件生命周期
1.应用生命周期钩子函数
参考文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/App.html
属性 | 说明 |
---|---|
onLaunch | 生命周期回调——监听小程序初始化。 |
onShow | 生命周期回调——监听小程序启动或切前台。 |
onHide | 生命周期回调——监听小程序切后台。 |
onError | 错误监听函数。 |
代码
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
},
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {
},
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {
},
/**
* 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
*/
onError: function (msg) {
}
})
注意:
1.用户在点击右上角的胶囊关闭小程序时,小程序并没有被销毁,只是将小程序置于后台运行了,因此小 onLaunch 并不会重复执行。
2.当小程序执行停留在后台约5分钟后小程序会自动被销毁,再次打开小程序时 onLaunch 会再次被执行。
场景值
所谓的场景描述的是用户打开小程序的方式,如扫码、搜索、分享等,并且每个场景都对应了一个数值,即场景值,根据这个场景值来判断用户打开小程序的方式,进而分析用户的行为,常见的场景值如下表所示:
场景值 ID | 说明 |
---|---|
1001 | 发现栏小程序主入口 |
1011 | 扫描二维码 |
1007 | 单人聊天会话中的小程序消息卡片 |
… | … |
获取小程序的声景值只能在全局生周期函数 onLaunch、onShow 中获取,代码如下所示
// app.js
App({
onLaunch(params) {
// 1001 发现栏小程序主入口
// 1011 扫描二维码
// 单人聊天会话中的小程序消息卡片
console.log(params.scene)
},
onShow(params) {
// 也可以获取场景值ID
console.log(params.scene)
},
})
2.页面生命周期钩子函数
参考文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/App.html
生命周期 | 必填 | 说明 |
---|---|---|
onLoad | 否 | 监听页面加载,若页面没被销毁只会执行 1 次 |
onShow | 否 | 监听页面显示 |
onReady | 否 | 监听页面初次渲染完成,只会执行 1 次 |
onHide | 否 | 监听页面隐藏 |
onUnload | 否 | 监听页面卸载 |
onPullDownRefresh | 否 | 监听用户下拉动作 |
onReachBottom | 否 | 页面上拉触底事件的处理函数 |
onShareAppMessage | 否 | 用户点击右上角分享 |
代码
Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
页面间传递及接收参数
- 传递:拼接到页面url中
- 接收:通过onLoad回调的第一参数。(只能是onLoad钩子)
<navigator url="pages/index/index?id=10086&name=周树人" ></navigator>
//pages/index/index
Page({
data: {
name: '',
age: '',
},
onLoad(params) {
// 查看地址中的参数
console.log(params)
// 记录存储地址参数
this.setData({ ...params })
},
})
<view>姓名:{{name}},年龄:{{age}}</view>
3.组件生命周期钩子函数
参考文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
生命周期 | 参数 | 描述 |
---|---|---|
created | 无 | 在组件实例刚刚被创建时执行,此时还不能调用 setData,一般用于给组件的this添加一些自定义的属性字段 |
attached | 无 | 在组件实例进入页面节点树时执行,绝大多数初始化工作可以在这个时机进行,例如发请求获取初始数据 |
ready | 无 | 在组件在视图层布局完成后执行 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 |
detached | 无 | 在组件实例被从页面节点树移除时执行,适合做一些清理工作 |
error | Object Error | 每当组件方法抛出错误时执行 |
组件所在页面的生命周期
有时,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。既在组件中监听页面的生命周期的变化。可以监听到的页面生命周期有以下三个:
生命周期 | 参数 | 描述 |
---|---|---|
show | 无 | 组件所在的页面被展示时执行 |
hide | 无 | 组件所在的页面被隐藏时执行 |
resize | Object Size | 组件所在的页面尺寸变化时执行 |
代码
Component({
// 推荐方式
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// 页面生命周期
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
十四、内置API
1.网络请求
wx.request
参考文档:https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
代码
// 小程序发起网络请求(调用接口)的方法
wx.request({
// 接口地址
url: 'api/path/xxx',
// 请求的方法
method: 'GET|POST|PUT',
// 请求时的数据
data: {},
success(res) {
// 成功响应的回调
},
// ...
})
示例
Page({
onLoad() {
// 页面加载完成即获取学生列表
this.getStudentList()
},
// 获取学生表表
getStudentList() {
// 调用小程序 api
wx.request({
url: '',
method: 'GET',
success: (res) => {
console.log(res)
},
})
},
})
合法域名
小程序规定 wx.request 调用接口的服务器地址(域名)必须事先在小程序的管理后台进行设置,否则是不允许发起网络请求。 解决方案有两个:
1.在小程序管理后台进行设置 (永久性解决)
2.在小程序开发工具中进行设置 (开发阶段临时解决,上线后还是得去后台配置合法域名)
注意:域名有个严格的要求:必须是 https 协议且已备案!
2.加载提示
wx.showLoading
wx.hideLoading
加载提示框常配合网络请求来使用,用于增加用户体验,对应的 API 有两个,分别为:
- wx.showLoading 显示加载提示框
- wx.hideLoading 隐藏加载提示框
它们的语法如下:
// 显示加载提示
wx.showLoading({
title: '正在加载...',
mask: true,
})
// 隐藏加载提示
wx.hideLoading()
示例
// pages/index/index.js
Page({
// ...省略前面小节代码
// 获取学生表表
getStudentList() {
// 显示提示框
wx.showLoading({
title: '正在加载...',
mask: true,
})
// 发起请求
wx.request({
url: '',
method: 'GET',
// 这里注意因为 this 的原因,推荐使用箭头函数
success: (res) => {
this.setData({
// 更新 students 数组
students: res.data.result,
})
},
complete() {
// 隐藏提示框
wx.hideLoading()
},
})
},
})
注意: 调用showLoading的时候还可以传入mask属性用于防止点击穿透!
3.消息提示
wx.showToast
参考文档:https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html
代码
wx.showToast({
title: "请输入姓名",
icon: "error",
mask: true,
});
注意:可以开启mask:true用于节流,防止元素被多次点击
4.本地存储
存储指定数据
- wx.setStorageSync 同步版本
- wx.setStorage 异步版本
获取指定数据
- wx.getStorageSync 同步版本
- wx.getStorage 异步版本
移除指定数据
- wx.removeStorageSync 同步版本
- wx.removeStorage 异步版本
清除所有数据
- wx.clearStorageSync 同步版本
- wx.clearStorage 异步版本
参考文档https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.setStorageSync.html
代码
//同步版本,存储对象类型,不需要JSON.stringify
wx.setStorageSync("person", {
name: "张三",
age: 18,
});
// 异步版本,相同的key会被覆盖
wx.setStorage({
key: "name",
data: "李四",
});
// 同步版本,获取存入的对象类型,不需要JSON.parse,
wx.getStorageSync("person");
// 异步版本,获取存入的数据
wx.getStorage({
key: "name",
success(res) {
console.log(res.data);
},
});
// 同步版本,移除指定key的数据
wx.removeStorageSync("name");
// 异步版本,移除指定key的数据
wx.removeStorage({
key: 'name'
});
// 同步版本,清空所有本地缓存数据
wx.clearStorageSync();
// 异步版本,清空所有本地缓存数据
wx.clearStorage()
5.路由相关
编程式路由跳转
参考文档:https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.navigateTo.html
// 相当于open-type="navigate" 保留当前页面,跳转到应用内的某个页面。
// 但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。
// 小程序中页面栈最多十层
wx.navigateTo({
url: "/pages/logs/logs",
});
// 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
// 相当于open-type="redirect"
wx.redirectTo({
url: "/pages/logs/logs",
});
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,只能用于跳转tabBar页面
// 相当于open-type="switchTab"
wx.switchTab({
url: "/pages/logs/logs", // 路径后不能带参数
});
// 关闭所有页面,打开到应用内的某个页面
// 相当于open-type="reLaunch"
wx.reLaunch({
url: "/pages/logs/logs",
});
// 关闭当前页面,返回上一页面或多级页面。
// 可通过getCurrentPages获取当前的页面栈,决定需要返回几层。
wx.navigateBack({
delta: 1, // 返回的页面数,如果delta大于现有页面数,则返回到首页
});
十五、npm构建
1.默认方式
小程序支持使用 npm 安装第三方包,但是对包有一些限制
核心步骤
1.在根目录中 初始化项目
npm init -y 创建package.json
2.安装依赖
npm i 包
//举例
npm i dayjs
3.构建 npm
在微信开发者工具中 点击 ‘工具’ -> ‘构建npm’
4.代码中使用
import 包名 from '包'
//举例
import dayjs from 'dayjs'
console.log(dayjs().format('YYYY-MM-DD HH:mm:ss'))
2.自定义方式
默认情况下项目目录的最外层是小程序的根目录,通过 project.config.json 可以指定小程序的根目录,这样做的好处是能够优化目录结构,更好的管理项目的代码
{
"setting": {
...
"packNpmManually": true, // 启用 npm 构建手动配置
"packNpmRelationList": [ // 手动构建 npm 配置详情
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./src" // 自定义小程序根目录,自己随意起名字
}
],
...
},
"libVersion": "2.19.4",
"miniprogramRoot": "src/", // 自定义小程序的根目录
}
十六、小程序中使用组件库
步骤
1.npm init && npm安装
2.修改app.json去掉"style":“v2”
3.构建npm
4.在app.json和页面.json中注册
5.在页面使用
Vant-Weapp组件库官网:https://vant-contrib.gitee.io/vant-weapp/#/quickstart
十七、自定义组件
自定义组件可理解为允许我们创造自己想要的某些效果的标签。如image是小程序指定的图片标签, border-image 可以是我们自己创造的标签
自定义组件还具有简化页面结构、封装复用代码的功能。
组件化开发是目前前端开发项目的主流方式。
1.使用方法
步骤
1.创建
通常习惯将组件放到独立的目录 components 当中,这个目录需要我们手动进行创建。
组件和页面的结构是一致的,但也是有区别的:
1.组件的配置文件中配置项 component: true
//components\组件名\index.json
{
"component": true,
"usingComponents": {}
}
- 组件的 .js 文件中调用 Component 函数,页面的.js文件中调用Page函数
//components\组件名\index.js
Component({
...
})
2.注册
页面注册
在使用组件的页面配置中通过 usingComponents 进行注册,只能在当前页面中使用该组件
全局注册
在 app.json 文件中通过 usingComponents 对自定义组件进行注册,注册的组件可以任意页面中使用全局注册的组件
"usingComponents": {
...
"组件名": "/components/组件名/index"
},
3.使用
<组件名></组件名>
2.组件样式
默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。
举例
- 组件A的样式不会影响组件B的样式
- 组件A的样式不会影响页面的样式
- 页面的样式不会影响组件A和B的样式
样式隔离注意点
- app.wxss中的全局样式对组件无效
- 只有class选择器具有样式隔离效果,id选择器、属性选择器、标签选择器不受样式隔离的影响。建议:在组件和引用组件的页面中建议使用class选择器,不要使用id、属性、标签选择器
样式隔离文档: https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html
3.数据、属性和方法
data数据
在小程序中,用于组件模板渲染的私有数据,需要定义到data中,示例如下:
Component({
data: {
num: 1
}
...
});
methods方法
在小程序中,事件处理函数和自定义方法需要定义到methods中,示例如下:
Component({
...
methods: {
handleAdd() {
this.setData({
num: this.data.num + 1
});
},
handleSub() {
this.setData({
num: this.data.num - 1
});
}
}
...
});
properties属性
在小程序中,properties是组件的对外属性,用于接收外界传递到组件中的数据,示例如下:
Component({
...
properties: {
min: Number,
max: {
type: Number,
value: 10 // value用于指定默认值
}
}
...
})
注意:小程序组件中data和properties是完全相等的
console.log(this.data === this.properties)// true
4.组件生命周期
5.组件插槽
概念
在自定义组件的wxml结构中,我们可以提供一个<slot>
节点,用于承载组件使用者提供的wxml结构。插槽可以方便开发者将不确定的、或者希望由用户去确定的交给用户。如自己封装的弹框组件底部不确定用户会放一个按钮还是两个按钮,就可以放过插槽,交给用户自己定。
单个插槽
在小程序中,默认每个自定义组件中只允许使用一个<slot>
进行占位。
<!--components/MyTest2/index.wxml-->
<view>
<text>components/MyTest2/index.wxml</text>
<!-- 对于不确定的内容,可以使用slot进行占位,具体内容交给使用者确定 -->
<slot></slot>
</view>
<my-test2>
<!-- 这里的内容将被放到组件中<slot>的位置 -->
<view>
这里是slot里的内容
</view>
</my-test2>
多插槽(具名插槽)
默认情况下,一个组件的 wxml 中只能有一个 slot 。需要使用多 slot 时,可以在组件 js 中声明启用。
Component({
...
options: {
multipleSlots: true // 在组件定义时的选项中启用多 slot 支持
},
...
})
此时,可以在这个组件的 wxml 中使用多个 slot ,以不同的 name 来区分。
<view>
<text>components/MyTest2/index.wxml</text>
<!-- 对于不确定的内容,可以使用slot进行占位,具体内容交给使用者确定 -->
<!-- <slot></slot> -->
<slot name="before"></slot>
<view>
---------这里是分割线--------
</view>
<slot name="after"></slot>
</view>
<my-test2>
<!-- 这里的内容将被放到组件中<slot>的位置 -->
<!-- <view>
这里是slot里的内容
</view> -->
<view slot="before">
这里是before slot里的内容
</view>
<view slot="after">
这里是after slot里的内容
</view>
</my-test2>
6.父子组件间通讯
父子组件间的基本通信方式有以下3种
1.自定义属性
用于父组件向子组件传递数据,只能传递JSON兼容的数据
2.自定义事件
用于子组件向父组件传递数据,可以传递任意数据
3.获取组件实例
父组件可以通过this.selectComponent()获取子组件实例对象
这样可以直接访问子组件的任意数据和方法
自定义属性
核心步骤
1.父组件通过自定义属性传递
<my-test3 num="{{num}}" />
// 父组件(页面中)num的值为{{num}}
Page({
data: {
num: 1,
},
});
2.子组件通过定义自定义属性接收
<text>components/MyTest3/index.wxml</text>
<view>
子组件内num的值为:{{num}}
</view>
<button type="primary">点我+1</button>
Component({
properties: {
num: Number,
},
})
自定义事件
核心步骤
1.给子组件上某个元素绑定事件
<text>components/MyTest3/index.wxml</text>
<view>
子组件内num的值为:{{num}}
</view>
<button type="primary" bindtap="handleAdd">点我+1</button>
2.在事件回调中通过triggerEvent触发自定义事件并传参
// components/MyTest3/index.js
Component({
properties: {
num: Number,
},
methods: {
handleAdd() {
this.setData({
num: this.properties.num + 1,
});
// 触发自定义事件并传参
this.triggerEvent("add", this.properties.num);
},
},
});
3.父组件监听自定义事件
<my-test3 num="{{num}}" bind:add="add" />
父组件(页面中)num的值为{{num}}
4.在回调函数中通过事件对象的detail属性接参
Page({
data: {
num: 1,
},
add(ev) {
// console.log(ev);
const value = ev.detail;
this.setData({
num: value,
});
},
});
获取组件实例
<my-test3 class="test3" num="{{num}}" bind:add="add" />
父组件(页面中)num的值为{{num}}
<button bindtap="getChild">获取子组件实例</button>
Page({
data: {
num: 1,
},
add(e) {
// console.log(e);
const value = e.detail;
this.setData({
num: value,
});
},
getChild() {
const child = this.selectComponent(".test3");
console.log(child);
// 获取子组件里的数据
const num = child.properties.num;
// 调用子组件里的方法
child.handleAdd();
},
});
十八、分包
小程序限制每个包代码量不超过2M,如果我们的小程序确实很复杂,代码量操过2M,就需要用到分包
1.配置
参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
定义 将小程序拆分成若干个部分叫做分包。 作用:
1.解决项目体积过大
2.提高启动效率
3.方便协同开发
分类:
主包
每个小程序必定含有一个主包。
默认启动页面、TabBar 页面,以及公共资源/JS 脚本必须放在主包;
普通分包
1.普通非独立分包
- 进入普通非独立分包时,主包会被下载
- 可以使用主包里面的公共资源/JS脚本
2.独立分包
- 一种特殊类型的分包,可以独立于主包和其他分包运行。
- 从独立分包中页面进入小程序时,不需要下载主包。不可使用主包里的资源。
配置参考代码
// json
"pages": {}, // 和pages同级
"subPackages": [
{
"root": "goods_pkg",
"pages": [
"pages/goods_list/index",
"pages/goods_detail/index"
]
}
]
一个分包可以理解就是一个文件夹
2.预加载
参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/preload.html
分包预加载
概念
在打开小程序启动的时候只下载主包代码,分包并不会下载,因此能够提升小程序启动时的打开速度,但是分包的代码只有在访问到分包的页面时才去下载,这样用户就需要有一定时间的等待(一般不太影响),通过分包预加载技术可以实现提前去下载分包的代码,这样分包页面的访问速度也会得到提升。
小程序通过 preloadRule 配置需要预加载的分包,在 app.json 中进行配置:
- 指定某个页面路径做为 key,含义是当访问这个页面时会去预加载一个分包
- network 预加载分包的网络条件,可选值为 all、wifi,默认为 wifi
- packages 指定要预下载的分包名或根路径
{
"preloadRule": {
"pages/index/index": {
"network": "wifi",
"packages": ["goods_pkg"]
}
},
}
//上述的代码代表的含义是当用户访问到 pages/index/index 时,在 wifi 网络前提下预先下载 goods_pkg 分包的代码。
分包只能提高主包的下载速度,也就是小程序的启动速度。分包预下载可以提高分包的加载速度。
十九、框架接口
框架接口指的是小程序提供的一些全局函数
1.getApp
概念
getApp 是一个全局的函数,调用该函数可以获取小程序应用实例,通过小程序应用实例可实现数据或方法的共享。
示例
// App.js
App({
// 读取本地存储的token数据
token: wx.getStorageSync('token'),
onLaunch() {
// 生命周期
},
http(params) {
// 举例封装网络请求
wx.request({
...params,
header: {},
})
}
})
在任意页面和组件中调用 getApp 就可以获取小程序的实例
// 获取小程序实例
const app = getApp()
Page({
onLoad() {
// 能够读取到全局实全名定义的 token 数据
console.log(app.token)
// 调用全局实例中定义的方法
app.http({
url: '',
method: 'GET'
})
},
})
注意:getApp()能实现类似web中vuex的效果,但getApp()的数据不是响应式的。
2.getCurrentPages
概念 getCurrentPages 获取当前页面栈,页面栈中包含的是页面的实例,数组中第一个元素为首页,最后一个元素为当前页面。
onUnload() {
const pages = getCurrentPages();
console.log(pages);
pages[0].onLoad();
}
注意:不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成
3.Behavior
参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html
概念
能够将一些公共的逻辑抽离到单独的模块当中。(类似 Vue 的 mixin 的功能)
每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior
示例
// pages/index/my-behavior.js
// 注册一个 behavior
export default Behavior({
// 定义初始数据:与 Page 中定义的 data 含义一致
data: {
version: 'v1.0.0'
},
// 定义方法:与 Page 中定义方法含义一致
methods: {
getVersion() {
return this.data.version
}
}
})
上述代码在 data 中初始了一个数据 version,在 methods 中定义了一个方法 getVersion,接下来将这个 Behavior 对象注入到页面中,在页面中就能够调用 this.getVersion() 就可以获取 version 对应的数据了:
// pages/index/index.js
import myBehavior from './my-behavior'
Page({
// 将 myBehavior 注入到页面当中
behaviors: [myBehavior],
onLoad() {
// 该方法来自于 myBehavior 当中
this.getVersion()
// 可以访问到在 myBehavior 中初始的数据
console.log(this.data.version)
}
})
二十、获取用户信息
1.获取用户头像
通过<button open-type="chooseAvatar" />
获取用户头像方式。
步骤
1.设置 button 的属性 open-type 值为 chooseAvatar
<button open-type="chooseAvatar" bindchooseavatar="getAvatar">点击获取头像</button>
<image src="{{avatarUrl}}" mode="widthFix"></image>
2.监听 button 的 chooseavatar 事件
getAvatar(ev) {
console.log(ev);
this.setData({
avatarUrl: ev.detail.avatarUrl,
});
},
注意:open-type 的属性值 chooseAvatar (有大写字母),事件类型 chooseavatar (全部小写字母)。
2.获取用户昵称
通过<input type="nickname">
获取用户昵称方式。
参考代码
<input style="border: 1px solid #ccc;" type="nickname" />
<!--注意:需要在真实手机中操作 -->
注意:开发者工具中,有时触发blur事件不一定能获取到用户昵称,多点击几次即可。