一、小程序的API
1.API的概念
- API应用程序编程接口,是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力
- 小程序开发框架提供丰富的微信原生 API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。
2.API的三种分类
-
事件监听API
以
on
开头的API
用来监听某个事件是否触发 -
同步API
以
Sync
结尾的API
都是同步API
-
异步API
- 通常需要指定回调函数接受调用的结果
- 小程序中,大多数的
API
都是异步API
3.组件和 API
的异同点
- 相同点
- 组件和
API
都是微信官方给提供的 - 组件和
API
的目的,都是为了方便小程序的快速开发
- 组件和
- 不同点
- 组件以
UI
结构布局为主, 一般不需要处理业务逻辑 API
以纯业务逻辑为主,一般没有对应的UI
结构
- 组件以
二、小程序的项目结构
├── pages ······································ 【目录】存放所有的小程序页面
│ │── index ···································· 【目录】index 页面
│ │ ├── index.wxml ······························· 【文件】 index 页面的结构
│ │ ├── index.js ································· 【文件】 index 页面的逻辑
│ │ ├── index.json ······························· 【文件】 index 页面的配置
│ │ └── index.wxss ······························· 【文件】 index 页面的样式
│ └── logs ····································· 【目录】 logs 页面
│ ├── logs.wxml ································ 【文件】 logs 页面的结构
│ └── logs.js ·································· 【文件】 logs 页面的逻辑
└── utils ······································ 【目录】 存放小程序中用到的工具函数
├── app.js ····································· 【文件】 小程序逻辑
├── app.json ··································· 【文件】 小程序的公共配置
├── app.wxss ··································· 【文件】小程序公共样式表
├── project.config.json ························ 【文件】 开发工具配置文件
1.说明:
app.js
是小程序的入口文件,运行小程序,第一个被运行的就是app.js
app.json
是小程序的全局配置文件,对小程序每个页面生效app.wxss
是小程序的全局样式文件,对小程序每个页面生效
2.注意:
- 对于小程序运行而言,
app.js
和app.json
是必不可少的 - 对于小程序页面而言,
.js
和.html
文件是必不可少的
3.小程序页面中每个文件的作用
.wxml
: 用来描述当前这个页面的标签结构,同时提供了类似于Vue
中指令的语法.js
: 用来定义当前页面中用到的数据、交互逻辑和响应用户的操作.json
: 用来定义当前页面的个性化配置,例如,为每个页面单独配置顶部颜色、是否允许下拉刷新等.wxss
: 用来定义样式来美化当前的页面
4.创建小程序页面
- 在
pages
目录上右键,选择 “新建目录”,输入目录名称 - 在新建的目录上,再次右键,选择 “新建
page
” ,输入page
名称
注意:
- 输入
page
名称以后,会自动创建四个文件
5.修改小程序项目的默认首页
- 打开
app.json
全局配置文件,找到pages
节点。这个 pages 节点是一个数组,存储了项目中所有页面的访问路径。其中,pages
数组中第一个页面路径,就是小程序项目的默认首页。 - 所以只需要修改 pages 数组中路径的顺序,就可以可修改小程序的默认首页。
三、基本组件
-
text文本组件
-
属性
属性 类型 默认值 必填 说明 selectable boolean false 否 文本是否可选 space string . 否 显示连续空格,可选参数: ensp
、emsp
、nbsp
decode boolean false 否 是否解码 - 注: text 组件详细文档
text
组件相当于行内标签、在同一行显示- 除了文本节点以外的其他节点都无法长按选中
- 注: text 组件详细文档
-
代码案列
<view> <!-- 长按文本是否可选 --> <text selectable='true'>web</text> </view> <view> <!-- 显示连续空格的方式 --> <view> <text space='ensp'>H a c k</text> </view> <view> <text space='emsp'>H a c k</text> </view> <view> <text space='nbsp'>H a c k</text> </view> </view> <view> <text>skyblue</text> </view> <view> <!-- 是否解码 --> <text decode='true'> < > & '    </text> </view>
-
-
view视图容器组件
View 视图容器, 类似于 HTML 中的 div
-
属性
属性 类型 默认值 必填 说明 hover-class string none 否 指定按下去的样式类。当hover-class="none"时,没有点击效果 hover-stop-propagation boolean false 否 指定是否阻止本节点的祖先节点出现点击态 hover-start-time number 50 否 按住后多久出现点击态,单位毫秒 hover-stay-time number 400 否 手指松开后点击态保留时间,单位毫秒 -
代码案例
<view hover-class='box1'> <view hover-stop-propagation='true' hover-class='box' hover-start-time='2000' hover-stay-time='3000'> box1 </view> </view>
-
-
button按钮组件
-
属性
属性名 类型 默认值 说明 size String default 按钮的大小 type String default 按钮的样式类型 plain Boolean false 按钮是否镂空,背景色透明 disabled Boolean false 是否按钮 loading Boolean false 名称是否带 loading t图标 - 注:Button 组件的详细文档
button
组件默认独占一行,设置size
为mini
时可以在一行显示多个
-
代码案例
<button size='mini' type='primary'>前端</button> <button size='mini' type='default' disabled='true'>前端</button> <button size='mini' type='warn' loading='true'>前端</button>
-
-
input文本输入框组件
-
属性
属性名 类型 默认值 说明 value String . 输入框的初始内容 type String ‘text’ input 的类型 password Boolean false 是否是密码类型 placeholder Sting . 输入框为空时占位符 disabled Boolean false 是否禁用 maxlength Number 140 最大输入长度,设置 -1 时不限制最大长度 -
代码案例
<input placeholder='111' type='idcard' placeholder-style="color: skyblue" />
-
-
image图片组件
-
常用属性
src
– 支持本地和网络上的图片mode
– 指定图片的裁剪、缩放的模式- image 组件默认的宽度是
300px
、高度是225px
- image组件中二维码/小程序码图片不支持长按识别
- 注意:image 图片组件详细文档
-
代码案例
<image src='/assets/5.jpg' mode='aspectFit'></image> <image src='https://wx.qlogo.cn/mmhead/Q3auHgzwzM7teJKyb7Oicw6x2rDiaD5BkDPFP2kccFO6a566TzzUyUgA/0' mode='widthFix'></image>
-
四、wxss 中常用的样式选择器
- 标签选择器
- id选择器
- class选择器
- 伪类选择器
- data-*属性选择器
- :nth-of-type() 等常用的 css3 选择器
-
rpx
与px
之间的换算以
iPhone6
为例,iPhone6
的屏幕宽度为375px
,共有 750 个物理像素,则750rpx
=375px
=750
物理像素也就是
1rpx
=0.5px
=1 物理像素
设备 rpx
换算px
(屏幕宽度/750)px
换算rpx
(750/屏幕宽度)iPhone5
1rpx
= 0.42px
1px
=2.34rpx
iPhone6
1rpx
=0.5px
1px
=2rpx
iPhone6 Plus
1rpx
=0.552px
1px
=1.81rpx
-
rpx
和iPhone6
设计稿的关系开发微信小程序时设计师可以用
iPhone6
作为视觉稿的标准。官方建议:
开发微信小程序时,设计师可以用
iPhone6
作为视觉稿的标准。如果要根据
iPhone6
的设计稿,绘制小程序页面,可以直接把单位从px
替换为rpx
。例如,假设
iPhone6
设计稿上,要绘制一个 宽高为200px
的盒子,换算为rpx
为200rpx
。 -
@import
样式导入001 - 语法解释
- 使用
@import
语句可以导入外联样式表 - 语法格式:
@import "wxss 样式表文件的相对路径"
002 - 案例代码
@import "/assets/common/common.wxss"; /* @import "../../assets/common/common.wxss"; */ .box { width: 375rpx; height: 375rpx; background-color: skyblue; }
- 使用
五、app.json 配置文件
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置,
它决定了页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
在 app.json
配置文件中,最主要的配置节点是:
pages
数组:配置小程序的页面路径window
对象:用于设置小程序的状态栏、导航条、标题、窗口背景色tabBar
对象:配置小程序的tab栏效果
注:全局配置详细文档
-
pages
数组的用法app.json
中的pages
数组,用来配置小程序的页面路径001 - 基础配置
pages
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径+文件名 信息。- 文件名不需要写文件后缀,框架会自动去寻找对应位置的
.json
、.js
、.wxml
和.wxss
四个文件进行处理。
002 - 创建页面的另一种方式
- 打开
app.json
-->pages
数组节点 --> 新增页面路径并保存 --> 自动创建路径对应的页面
003 - 设置项目的首页
- 打开
app.json
->pages
数组节点 - 按需调整数组中路径的顺序,即可修改默认首页
注意事项:
- 数组的第一项代表小程序的小程序的初始页面也就是首页
- 小程序中新增/减少页面,都需要对 pages 数组进行修改,否则在运行小程序时就会报错
-
设置导航栏标题文字内容
app.json
-->window
-->navigationBarTitleText
- 将属性值修改即可
-
设置导航栏背景色
app.json
-->window
-->navigationBarBackgroundColor
- 将属性值修改为指定的颜色就可以
-
设置导航栏标题颜色
app.json
-->window
-->navigationBarTextStyle
- 将属性值修改为指定的颜色就可以
-
全局开启下拉刷新功能
通过手指在屏幕上的下拉滑动操作,从而重新加载页面数据的行为
app.json
-->window
--> 把enablePullDownRefresh
的值设置为 true
-
设置下拉刷新窗口的背景色
当全局开启下拉刷新功能之后,默认的窗口背景为白色
app.json
->window
->backgroundColor
-
设置下拉loading的样式
当全局开启下拉刷新功能之后,默认窗口的loading样式为白色
app.json
-->window
-->backgroundTextStyle
-
设置上拉触底的距离
手指在屏幕上的上拉滑动操作,从而加载更多数据的行为
app.json
-->window
-->onReachBottomDistance
注意: 默认距离为
50px
,如果没有特殊需求,建议使用默认值即可
六、tabBar的概念
tabBar
是移动端应用常见的页面效果,用于实现多页面的快速切换;小程序中通常将其分为底部 tabBar
和顶部 tabBar
注意:tabBar
中,只能配置最少2个、最多5个 tab 页签,当渲染顶部 tabBar
的时候,不显示 icon
,只显示文本
1.tabBar的组成部分
backgroundColor
:导航条背景色selectedIconPath
:选中时的图片路径borderStyle
:tabBar
上边框的颜色iconPath
:未选中时的图片路径selectedColor
:tab
上的文字选中时的颜色color
:tab
上的文字默认(未选中)颜色
2.tabBar 节点的配置项
- tabBar 节点的配置项
属性 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
color | HexColor | 是 | . | tab 上的文字默认颜色,仅支持十六进制颜色 |
selectedColor | HexColor | 是 | . | tab 上的文字选中时的颜色,仅支持十六进制颜色 |
backgroundColor | HexColor | 是 | . | tab 的背景色,仅支持十六进制颜色 |
borderStyle | string | 否 | black | tabBar 上边框的颜色, 仅支持 black / white |
list | Array | 是 | . | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab |
position | string | 否 | bottom | tabBar 的位置,仅支持 bottom / top |
custom | boolean | 否 | false | 自定义 tabBar |
-
list 节点的配置项
属性 类型 必填 说明 pagePath string 是 页面路径,必须在 pages 中先定义 text string 是 tab 上按钮文字 iconPath string 否 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px selectedIconPath string 否 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px 注意:
- 都不支持网络图片
- 当 position 为 top 时,不显示 icon。
七、页面配置
1.页面配置和局部配置的关系
app.json
中的window
节点,可以全局配置小程序中每个页面的窗口表现;- 如果某些小程序页面,想要拥有特殊的窗口表现,此时,“页面级别的
.json
配置文件”就可以实现这种需求;
注意:页面级别配置优先于全局配置生效
2.页面配置属性
注: 页面配置详细文档
八、小程序的生命周期
- 小程序的启动,表示生命周期的开始
- 小程序的关闭,表示生命周期的结束
- 中间小程序运行的过程,就是小程序的生命周期
1.小程序生命周期的两种类型
- 应用生命周期:特指小程序从启动 --> 运行 --> 销毁的过程;
- 页面生命周期:特指小程序中,每个页面的加载 --> 渲染 --> 销毁的过程;
注意:页面的生命周期范围较小,应用程序的生命周期范围较大
2.小程序的生命周期函数
小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行
-
生命周期函数的作用:
允许程序员在特定的生命周期时间点上,执行某些特定的操作。例如,页面刚加载的时候,在生命周期函数中自动发起数据请求,获取当前页面的数据;
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
3.应用生命周期函数
app.js
是小程序执行的入口文件,在app.js
中必须调用App()
函数,且只能调用一次。其中,App()
函数是用来注册并执行小程序的。App(Object)
函数接收一个Object
参数,可以通过这个Object
参数,指定小程序的生命周期函数。
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () { },
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) { },
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () { },
/**
* 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
*/
onError: function (msg) { }
})
4.页面生命周期函数
- 每个小程序页面,必须拥有自己的
.js
文件,且必须调用Page()
函数,否则报错。其中Page()
函数用来注册小程序页面。 Page(Object)
函数接收一个Object
参数,可以通过这个Object
参数,指定页面的生命周期函数。
//index.js
//获取应用实例
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: { },
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) { },
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () { },
/**
* 生命周期函数--监听页面显示
*/
onShow: function () { },
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () { },
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () { },
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () { },
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () { },
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () { }
})
九、数据绑定
- 小程序每个页面,是由 4 部分组成,其中
.js
文件内可以定义页面的数据、生命周期函数、其他业务逻辑 - 如果要在
.js
文件内定义页面的数据,只需把数据定义在data
节点下即可
<!-- 页面结构 -->
<!-- 绑定内容和属性 -->
<view id="item-{{id}}">{{ info }}</view>
<!-- 算数运算 -->
<view>{{ 1 + 1 }}</view>
<!-- 三元表达式 -->
<view>{{ id == 10 ? "正确" : "错误" }}</view>
// 页面数据
Page({
data: {
info: 'i miss you',
id: 10,
arr: [1, 2, 3]
}
})
十、小程序中的事件
1.bindtap绑定触摸事件
在小程序中,不存在网页中的onclick鼠标点击事件,而是通过tap事件来响应触摸行为
2.bindinput绑定输入事件
在小程序中,可以通过 input 事件来响应文本框内的输入事件
data 和 文本框之间的数据同步
- 在文本框的 input事件处理函数中,通过事件参数 event,能够访问到文本框的最新值
- 语法结构 event.detail.value
- 通过 this.setData(dataObject)方法,可以把页面中的 data 数据重新赋值
<!-- 页面结构 -->
<button bindtap='handle' type='warn'>我是按钮</button>
<input bindinput='inputHandle' value='输入框'></input>
<input bindinput='datasync' value='{{ msg }}'></input>
// 页面逻辑
Page({
data: {
msg: ''
},
handle: function (event) {
console.log('按钮绑定的事件')
console.log(event)
},
inputHandle: function (e) {
console.log(e)
},
// 数据同步演示
datasync: function (e) {
console.log(e.detail.value)
this.setData({
msg: e.detail.value
})
}
})
3.小程序中的事件传参
1.不能再绑定事件的同时传递参数
- 小程序的事件传参比较特殊,不能在为组件绑定事件的同时,为事件处理函数传递参数
- 小程序会把 bindtap后指定的值,统一当做事件名称来处理
// 错误做法
<button bindtap='eventHandle(123)' type='primary' data-info='info'>传递参数</button>
2.通过 data-*
自定义属性传参
- 如果要在组件触发事件处理函数的时候,传递参数,可以为组件提供 data-* 自定义属性传参
3.获取data-*自定义属性中传递的参数
- 通过事件参数 event-target-dataset.参数名,能够获取 data-*自定义属性传递到事件处理函数中的参数
<!-- 页面结构 -->
<button bindtap='eventHandle' type='primary' data-info='info'>传递参数</button>
// 页面逻辑
Page({
data: {},
eventHandle: function (e) {
console.log(e.target.dataset.info)
}
})
4.WXS脚本
1.什么是wxs
- wxs是小程序的一套脚本语言,结合wxml,可以构建出页面的结构
2.wxs的注意事项
- 没有兼容性
- 与 javascript不同
- 隔离性
- 不能作为事件回调
- iOS设备上比 javascript运行快
3.wxs遵循CommonJS模块化规范
- module对象
- 每个wxs都是独立的模块,每个模块均有一个内置的 module 对象,每个模块都有自己独立的作用域。
- module.exports
- 由于wxs拥有独立作用域,所以在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见,
- 通过module.exports属性,可以对外共享本模块的私有变量与函数。
- require函数
- 在wxs模块中引用其他wxs文件模块,可以使用 require函数。
4.wxs基础语法
a - 使用module.exports向外共享成员
- 通过 module.exports 属性,可以对外共享本模块的私有变量与函数
var foo = “‘hello world’ from wxs”; // 定义私有变量 foo
var bar = function (d) { // 定义私有函数 bar
return d
}
// 通过 modules.exports 向外共享私有成员
module.exports = {
FOO: foo, // 向外共享私有变量 foo
bar: ba, // 向外共享私有函数 bar
};
// module.exports 中挂载 msg 变量
module.exports.msg = “some msg”
b - 使用require引入其它wxs模块 以及注意事项
- 在wxs模块中引用其他wxs文件模块,可以使用 require 函数。
// 使用 require 导入 tools.wxs 脚本
var tools = require("./tools.wxs")
// 得到的 tools 对象,可以直接访问到 tools.wxs 中向外暴露的变量和方法
console.log(tools)
注意事项 :
- 只能引用 wxs文件模块,且必须使用相对路径
- wxs模块均为单例
- wxs模块在第一次被引用时,会自动初始化为单例对象。
- 多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象。
- 如果一个 wxs模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
c- 支持的数据类型
- WXS语言目前共有以下8种数据类型:
- number数值类型
- string字符串类型
- boolean布尔类型
- object对象类型
- function函数类型
- array数组类型
- date日期类型
- regexp正则
注意事项
注意:由于wxs与javascript是不同的语言,有自己的语法,并不和javascript一致,
所以在使用以上8种数据类型的时候,一定要先翻阅官方文档,再进行使用!
参考文档: 数据类型
5.内嵌wxs脚本
a - 使用规则
- wxs代码可以编写在 wxml文件中的
<wxs></wxs>
标签内,就像 javascript代码可以编写在html文件中的<script></script>
标签内一样。 - wxml文件中的每个
<wxs></wxs>
标签,必须提供一个 module属性,用来指定当前<wxs></wxs>
标签的模块名。在单个wxml文件内,建议其值唯一。 - module 属性值的命名必须符合下面两个规则:
- 首字符必须是:字母(a-z A-Z),下划线(_)
- 剩余字符可以是:字母(a-z A-Z),下划线(_), 数字(0-9)
b - 案例代码
<view>{{ info.msg }}</view>
<wxs module='info'>
var msg = '我在等风来'
module.exports = {
msg: msg
}
</wxs>
6.外联wxs脚本文件
a - 使用规则
- wxs代码可以编写在以 .wxs为后缀名的文件内,就像 javascript代码可以编写在以 .js为后缀名文件中一样。
- 在wxml中如果要引入外联的 wxs脚本,必须为
<wxs></wxs>
标签添加 module和 src属性。- module用来为
<wxs></wxs>
标签指定模块名,作为当前页面访问这个模块的标识名称; - src用来指定当前
<wxs></wxs>
标签要引入的脚本路径,必须是相对路径;
- module用来为
b - 案例代码
// .wxs 文件
var msg = '风铃响,故人归'
var handle = function (params) {
return params
}
module.exports = {
msg: msg,
handle: handle
}
<wxs src='./ling.wxs' module='feng'></wxs>
<view>{{ feng.msg }}</view>
<view>{{ feng.handle('我在等风') }}</view>
注意:在wxs中不要使用高级的JS语法
5.条件渲染
a - wx:if
- 在小程序中,使用 wx:if="{{condition}}"来判断是否需要渲染该代码块
- 也可以用wx:elif和wx:else 来添加一个 else 块
<view wx:if='{{id < 10}}'>JavaScript</view>
<view wx:elif='{{id == 10}}'>HTML</view>
<view wx:else='{{id > 10}}'>CSS</view>
b - block wx:if
- 因为wx:if是一个控制属性,需要将它添加到一个标签上。
- 如果要一次性判断多个组件标签,可以使用一个
<block></block>
标签将多个组件包装起来,并在上边使用 wx:if控制属性。 <block/>
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
<block wx:if='{{ id == 10 }}'>
<view>JavaScript</view>
<view>HTML</view>
<view>CSS</view>
</block>
c - hidden
- 使用hidden="{{condition}}"也能控制元素的显示与隐藏
<view hidden='{{ id > 10 }}'>前端三板斧</view>
d - hidden和wx:if的区别
- 被wx:if控制的区域,框架有一个局部渲染的过程,会根据控制条件的改变,动态创建或销毁对应的UI结构。
- wx:if是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
- 相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
- **总结:**wx:if有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则wx:if较好。
6.列表渲染
a - wx:for
- 在组件上使用wx:for控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
- 默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item。
<view wx:for='{{ arr }}' wx:key='index'>
我是{{ item }} -- 索引是 {{ index }}
</view>
b - block wx:for
- wx:for可以用在
<block></block>
标签上,以渲染一个包含多节点的结构块。
<block wx:for='{{ arr }}' wx:key='index'>
<view>值:{{item}} -- 索引{{index}}</view>
</block>
c - 指定索引和当前项的变量名
- 使用wx:for-item可以指定数组当前元素的变量名
- 使用wx:for-index可以指定数组当前下标的变量名,
<view wx:for='{{ arr }}' wx:for-item='foritem' wx:for-index='forindex' wx:key='index'>
我是{{ foritem }} -- 索引是 {{ forindex }}
</view>
d - 列表渲染中的wx:key
- wx:key的作用说明
- 如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如
<input/>
中的输入内容,<checkbox/>
的选中状态),需要使用wx:key
来指定列表中项目的唯一的标识符。 - 当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
- 如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如
- wx:key的注意事项
- key值必须具有唯一性,且不能动态改变
- key的值必须是数字或字符串
- 保留关键字this代表在for循环中的item本身,它也可以充当key值,但是有以下限制:需要item本身是一个唯一的字符串或者数字。
- 如不提供wx:key,会报一个warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
7.下拉刷新
a - 下拉刷新的概念以及场景
- 概念:下拉刷新是移动端更新列表数据的交互行为,用户通过手指在屏幕上自上而下的滑动,可以触发页面的下拉刷新,更新列表数据。
- 应用场景:在移动端,数据列表是常见的页面效果,更新列表数据是最基本的页面需求,相比于按钮刷新、定时刷新来说,下拉刷新的用户体验方便友好,已经成为移动端刷新列表数据的最佳解决方案。
b - 如何启动下拉刷新
- 在app.json的window选项中或页面配置中开启enablePullDownRefresh。
- 可以通过wx.startPullDownRefresh()触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
注意: 一般情况下,推荐在页面配置中为需要的页面单独开启下拉刷新行为
c - 设置下拉刷新窗口的样式
- 在app.json的window选项中或页面配置中修改backgroundColor和backgroundTextStyle选项。
- backgroundColor用来配置下拉刷新窗口的背景颜色,仅支持16进制颜色值
- backgroundTextStyle用来配置下拉刷新loading的样式,仅支持dark和light
d - 监听下拉刷新事件
需要先开启下拉刷新
- 为页面添加onPullDownRefresh()函数,可以监听用户在当前页面的下拉刷新事件。
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
console.log('触发下拉刷新啦')
}
e - 停止下拉刷新
- 处理完下拉刷新后,下拉刷新的 loading 效果会一直显示,不会主动消失,
- 因此需要手动隐藏下拉刷新的 loading 效果,调用
wx.stopPullDownRefresh()
可以停止当前页面的下拉刷新。
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
console.log('触发下拉刷新啦')
wx.stopPullDownRefresh()
}
8.上拉刷新
a - 上拉刷新的概念以及场景
- 概念:在移动端,随着手指不断向上滑动,当内容将要到达屏幕底部的时候,页面会随之不断的加载后续内容,直到没有新内容为止,我们称之为上拉加载更多。上拉加载更多的本质就是数据的分页加载。
- 应用场景:在移动端,列表数据的分页加载,首选的实现方式就是上拉加载更多。
b - 设置上拉刷新的距离
- 在app.json的window选项中或页面配置中设置触底距离onReachBottomDistance。单位为px,默认触底距离为50px。
- 为页面添加onReachBottom()函数,可以监听用户在当前页面的上拉触底事件,从而实现上拉加载更多列表数据的效果。
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
console.log('触发上拉刷新啦')
},
9.其他事件
a - 页面滑动事件onPageScroll
- 监听用户滑动页面事件
- 得到 scrollTop,页面在垂直方向已滚动的距离(单位px)
onPageScroll: function (e) {
console.log(e)
}
b - 分享事件onShareAppMessage
- 监听用户点击页面内转发按钮(
<button> 组件 open-type="share"
) - 右上角菜单“转发”按钮的行为,并自定义转发内容。
参数 | 类型 | 说明 |
---|---|---|
from | String | 转发事件来源。button:页面内转发按钮;menu:右上角转发菜单 |
target | Object | 如果 from 值是 button,则 target 是触发这次转发事件的 button,否则为 undefined |
webViewUrl | String | 页面中包含组件时,返回当前的url |
- 自定义转发内容, return 一个 Object 就可以
字段 | 说明 | 默认值 |
---|---|---|
title | 转发标题 | 当前小程序名称 |
path | 转发路径 | 当前页面 path ,必须是以 / 开头的完整路径 |
imageUrl | 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4。 | 使用默认截图 |
Page({
onShareAppMessage: function (res) {
if (res.from === 'button') {
// 来自页面内转发按钮
console.log(res.target)
}
return {
title: '自定义转发标题',
path: '/page/user?id=123'
}
}
})
c - 点击 tab 时触发事件onTabItemTap
参数 | 类型 | 说明 |
---|---|---|
index | String | 被点击tabItem的序号,从0开始 |
pagePath | String | 被点击tabItem的页面路径 |
text | String | 被点击tabItem的按钮文字 |
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
}
十一、小程序导航
1.声明式导航
1.导航到非tabBar页面
非tabBar页面指的是没有被当作tabBar进行切换的页面。
<navigator url="/pages/about/about">跳转到 about 页面</navigator>
- 注意事项
- url属性设置需要跳转的路径
- 页面路径应该以 / 开头,
- 路径必须提前在app.json的pages节点下声明
2.导航到tabBar页面
navigator组件单纯使用url属性,无法导航到tabBar页面,必须需要结合open-type属性进行导航。
<navigator url="/pages/person/person" open-type="switchTab">跳转到 tabBar 页面</navigator>
3.后退导航
小程序如果要后退到上一页面或多级页面,需要把open-type设置为navigateBack,同时使用delta属性指定后退的层数
<navigator open-type='navigateBack' delta='1'> 返回上一页 </navigator>
<navigator open-type='navigateBack' delta='2'> 返回上上一页 </navigator>
2.编程式导航
1.导航到非tabBar页面
通过wx.navigateTo(Object object)方法,可以跳转到应用内的某个页面。
但是不能跳到tabbar页面。
// 跳转到非导航页面
handle: function () {
wx.navigateTo({
url: '/pages/about/about',
success: function () {
console.log('Hello about')
}
})
},
2.导航到tabBar页面
通过wx.switchTab(Object object)方法,可以跳转到tabBar页面,
并关闭其他所有非tabBar页面
// 跳转到 tabBar 页面
tabBarHandle: function () {
wx.switchTab({
url: '/pages/person/person',
success: function() {
console.log('Hello Person')
}
})
},
3.后退导航
通过wx.navigateBack(Object object)方法,关闭当前页面,返回上一页面或多级页面。
handle: function () {
wx.navigateBack({
delta: 1
})
},
twoHandle: function () {
wx.navigateBack({
delta: 2
})
},
3.导航传参
1.声明式导航传参
navigator组件的url属性用来指定导航到的页面路径,同时路径后面还可以携带参数,参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔。
<navigator url="/pages/about/about?age=18&name=shuji">跳转到 about 页面</navigator>
2.编程式导航传参
- wx.navigateTo(Object object)方法的object 参数中,url属性用来指定需要跳转的应用内非tabBar的页面的路径, 路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔。
// 跳转到非导航页面
handle: function () {
wx.navigateTo({
url: '/pages/about/about?age=18&name=shuji',
success: function () {
console.log('Hello about')
}
})
},
- switchTab跳转如果携带参数
//switchTab跳转是不能直接携带参数的,需要声明一个全局变量
const app = getApp()
//Page({
// 跳转到 tabBar 页面
tabBarHandle: function () {
app.globalData.workType = {name: 'lili',age: "11"}//workType需在app.js中定义
wx.switchTab({
url: '/pages/person/person',
success: function() {
console.log('Hello Person')
}
})
},
//到跳转的页面取
onShow: function () {
console.log(app.globalData.workType)//app需在Page({上方定义或者getApp()代替
},
3.接受传递的参数
不论是声明式导航还是编程式导航,最终导航到的页面可以在 onLoad
生命周期函数中接收传递过来的参数。
onLoad: function (options) {
// 打印传递出来的参数
console.log(options)
},
十二、网络数据请求
get 与 Post 请求
小程序发送请求使用 wx.request()
方法,
- Get 案例代码
getData: function () {
wx.request({
url: 'xxxx',
method: 'get',
success: function (res) {
console.log(res)
}
})
},
- Post 代码案例
postData: function () {
wx.request({
url: 'https://www.liulongbin.top:8082/api/post',
method: 'post',
data: {
name: 'shuji'
},
success: function (res) {
console.log(res)
}
})
},
注意: method 如果不进行配置,默认参数是 get 请求方式
十三、小程序组件
1.创建与引用
1.组件的创建
- 在项目的根目录中,鼠标右键,创建 components 文件夹 --> test
- 在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”
- 为新建的组件命名之后,会自动生成组件对应的 4 个文件,后缀名分别为 .js,.json, .wxml和 .wxss
注意:应当尽量将不同的组件,存放到单独的文件夹中,从而保证清晰的目录结构
2.组件的引用
- 在需要引用组件的页面中,找到页面的.json配置文件,新增usingComponents节点
- 在usingComponents中,通过键值对的形式,注册组件;键为注册的组件名称,值为组件的相对路径
- 在页面的.wxml文件中,把注册的组件名称,以标签形式在页面上使用,即可把组件展示到页面上
{
"usingComponents": {
"first-com": "../../component/com01/com01"
}
}
注册组件名称时,建议把组件名称使用中横线进行连接,例如 vant-button 或 custom-button
2.组件的样式
- 组件对应wxss文件的样式,只对组件wxml内的节点生效。编写组件样式时,需要注意以下几点:
- 组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。
- 组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。
- 子元素选择器(.a>.b),只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。
- 继承样式,如 font、 color,会从组件外继承到组件内。
- 除继承样式外,app.wxss中的样式、组件所在页面的样式对自定义组件无效。
注意:以上语法不推荐死记硬背,建议使用 class 选择器
3.数据与方法
使用 data 定义组件的私有数据
- 小程序组件中的data与小程序页面中的data用法一致,区别是:
- 页面的data定义在Page()函数中
- 组件的data定义在Component()函数中
- 在组件的.js文件中:
- 如果要访问data中的数据,直接使用this.data.数据名称即可
- 如果要为data中的数据重新赋值,调用this.setData({ 数据名称: 新值 })即可
- 在组件的 .wxml 文件中
- 如果要渲染 data 中的数据,直接使用 {{ 数据名称 }} 即可
2.使用 methods 定义组件的事件处理函数
- 和页面不同,组件的事件处理函数,必须定义在 methods 节点中
methods: {
handle: function () {
console.log('组件的方法要定义在 methods 中')
this.setData({
num: this.data.num + 1
})
console.log(this.data.num)
}
}
4.properties
1.properties 简介
组件的对外属性,用来接收外界传递到组件中的数据。 类似于Vue中的props
- 组件的properties和data的用法类似,它们都是可读可写的,只不过:
- data更倾向于存储组件的私有数据
- properties更倾向于存储外界传递到组件中的数据
2.properties 语法结构
properties: {
a: { // 属性名
type: String, // 属性的数据类型
value: '' // 默认值
}
}
注意:type 的可选值为 Number,String、Boolean、Object、Array、null(表示不限制类型)
3.向组件传递 properties 的值
使用数据绑定的形式,向子组件的属性传递动态数据
<second-com prop-price="{{ priceData }}"></second-com>
注意:
- 在定义 properties 时,属性名采用驼峰写法(propertyName);
- 在 wxml 中,指定属性值时,则对应使用连字符写法(property-name=“attr value”),
- 应用于数据绑定时,采用驼峰写法(attr="{{propertyName}}")。
// 组件 com02.js
properties: {
propPrice: {
type: Number,
value: 1
}
},
<!-- 引用组件的页面 -->
<second-com prop-price="{{ priceData }}"></second-com>
<!-- 组件 com02.html -->
<view>{{ propPrice }}</view>
4.组件内修改 properties
properties 的值是可读可写的,可以通过 setData
修改 properties
中任何属性的值,
methods: {
handle: function () {
this.setData({
propPrice: this.properties.propPrice + 1
})
console.log(this.properties.propPrice)
}
}
5.数据监听器
1.基本使用方法
数据监听器可以用于监听和响应任何属性和数据字段的变化,从而执行特定的操作数据监听详细文档
observers: {
'propPrice, num': function (newPropPrice, newNum) {
console.log(newPropPrice)
console.log(newNum)
}
},
2.监听子数据字段语法
// 监控某个子数据的代码
Component({
observers: {
'some.subfield': function (subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
},
'arr[12]': function (arr12) {
// 使用 setData 设置 this.data.arr[12] 时触发
// (除此以外,使用 setData 设置 this.data.arr 也会触发)
}
}
})
// 使用通配符 ** 监听所有子数据字段的变化
Component({
observers: {
'some.field.**': function (field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
}
}
})
6.组件的生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
- 最重要的生命周期是created, attached, detached,包含一个组件实例生命流程的最主要时间点。
- 组件实例刚刚被创建好时, created生命周期被触发。此时还不能调用setData。 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。
- 在组件完全初始化完毕、进入页面节点树后, attached生命周期被触发。此时,this.data已被初始化完毕。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。
- 在组件离开页面节点树后,detached生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached会被触发。
1.定义生命周期方法
生命周期方法可以直接定义在 Component
构造器的第一级参数中。
自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。
可用的全部生命周期如下表所示。
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error | 每当组件方法抛出错误时执行 | 2.4.1 |
2.组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size | 组件所在的页面尺寸变化时执行 | 2.4.0 |
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
7.小程序插槽的使用
1.默认插槽
在组件的wxml中可以包含slot节点,用于承载组件使用者提供的wxml结构。
- 默认情况下,一个组件的wxml中只能有一个slot。需要使用多slot时,可以在组件js中声明启用。
- 注意:小程序中目前只有默认插槽和多个插槽,暂不支持作用域插槽。
- 案例代码
// 组件模板
<view>
<view>我是组件</view>
<slot></slot>
</view>
// 引用组件的页面模板
<second-com>
<view>你好,我是引用组件</view>
</second-com>
2.多个插槽
1.在组件中,需要使用多 slot
时,可以在组件 js
中声明启用。
Component({
options: {
multipleSlots: true
}
})
2.在组件的 wxml 中使用多个 slot 标签,以不同的 name 来区分不同的插槽
// 引用组件的页面模板
<second-com prop-price="{{ priceData }}">
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</second-com>
3.使用多个插槽
// 组件插槽
<view>
<view>我是组件</view>
<slot name="name"></slot>
<slot name="age"></slot>
</view>
8. 组件间的通信
1.组件之间的三种基本通信方式
- WXML数据绑定:用于父组件向子组件的指定属性传递数据,仅能设置JSON兼容数据
- 事件:用于子组件向父组件传递数据,可以传递任意数据。
- 父组件通过this.selectComponent方法获取子组件实例对象,便可以直接访问组件的任意数据和方法。
2.this.selectComponent使用
父组件的.js文件中,可以调用this.selectComponent(string)函数并指定id或class选择器, 获取子组件对象调用 ,可以返回指定组件的实例对象
// 使用组件的页面模板
<second-com class="second" id="second" prop-price="{{ priceData }}">
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</second-com>
// 使用组件的 .js 文件,使用方法触发
changeData: function () {
// console.log(this.selectComponent('#second'))
console.log(this.selectComponent('.second'))
},
- 注意事项
- 不能传递标签选择器(component-a),不然返回的是null
3.通过事件监听实现子向父传值
事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。
- 实现步骤
- 在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
- 在父组件的wxml中,通过自定义事件的形式,将步骤一中定义的函数引用,传递给子组件
- 在子组件的js中,通过调用this.triggerEvent(‘自定义事件名称’, { /* 参数对象 */ }),将数据发送到父组件
- 在父组件的js中,通过e.detail获取到子组件传递过来的数据
// 使用组件的页面模板自定义 myEvent 事件,接收 getCount 方法
<second-com bind:myEvent="getCount" class="second" id="second" prop-price="{{ priceData }}">
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</secondcom>
// 使用组件页面 js,生命 getCount 方法
getCount: function (e) {
console.log(e.detail)
},
// 组件页面
this.triggerEvent('myEvent', {
count: this.data.num
})
.使用多个插槽
// 组件插槽
<view>
<view>我是组件</view>
<slot name="name"></slot>
<slot name="age"></slot>
</view>
8. 组件间的通信
1.组件之间的三种基本通信方式
- WXML数据绑定:用于父组件向子组件的指定属性传递数据,仅能设置JSON兼容数据
- 事件:用于子组件向父组件传递数据,可以传递任意数据。
- 父组件通过this.selectComponent方法获取子组件实例对象,便可以直接访问组件的任意数据和方法。
2.this.selectComponent使用
父组件的.js文件中,可以调用this.selectComponent(string)函数并指定id或class选择器, 获取子组件对象调用 ,可以返回指定组件的实例对象
// 使用组件的页面模板
<second-com class="second" id="second" prop-price="{{ priceData }}">
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</second-com>
// 使用组件的 .js 文件,使用方法触发
changeData: function () {
// console.log(this.selectComponent('#second'))
console.log(this.selectComponent('.second'))
},
- 注意事项
- 不能传递标签选择器(component-a),不然返回的是null
3.通过事件监听实现子向父传值
事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。
- 实现步骤
- 在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
- 在父组件的wxml中,通过自定义事件的形式,将步骤一中定义的函数引用,传递给子组件
- 在子组件的js中,通过调用this.triggerEvent(‘自定义事件名称’, { /* 参数对象 */ }),将数据发送到父组件
- 在父组件的js中,通过e.detail获取到子组件传递过来的数据
// 使用组件的页面模板自定义 myEvent 事件,接收 getCount 方法
<second-com bind:myEvent="getCount" class="second" id="second" prop-price="{{ priceData }}">
<view slot="name">你好,这是 name 插槽 </view>
<view slot="age">你好,这是 age 插槽</view>
</secondcom>
// 使用组件页面 js,生命 getCount 方法
getCount: function (e) {
console.log(e.detail)
},
// 组件页面
this.triggerEvent('myEvent', {
count: this.data.num
})