微信开发者工具的使用
实验介绍
为了帮助开发者简单高效的开发和调试小程序,微信开发团队在原有的公众号网页调试工具的基础上,推出了全新的 微信开发者工具 解决方案,本节实验我们主要是学习微信开发者工具的介绍及使用。
知识点
- 开发者工具的下载、安装
- 创建、导入、删除项目
- 开发界面介绍
- 快捷键设置
开始之前
让我们简单了解一下微信开发者工具的能力:
- 使用公众号网页调试,开发者可以调试微信网页授权和微信 JS-SDK 详情
- 使用微信小程序调试,开发者可以完成小程序的 API 和页面的开发调试、代码查看和编辑、小程序预览和发布等功能。
- 代码片段的创建与导入
- 微信小游戏的开发
因本次实验主要讲解微信小程序相关知识,故公众号和小游戏相关能力不做过多的介绍。
开发者工具的下载、安装
开始之前,开发者需要先安装如下工具:
- 微信开发者工具:官方下载地址
根据自己的操作系统下载对应的安装包进行安装,打开小程序开发者工具,用微信扫码登录开发者工具,准备开发你的第一个小程序吧!
Windows
本节实验主要是使用 Windows 64 进行开发,以下是 Windows 的安装过程
笔者在这里安装的版本是稳定版 Stable Build(1.05.2105170)。
创建、管理小程序项目
- 新建项目选择小程序项目,点击红框范围。
- 给你的项目起一个好听的名字,选择代码存放的硬盘路径,填入申请到的小程序的 AppID 或使用测试号,勾选 "不使用云服务" (注意: 你要选择一个空的目录或者选择的非空目录下存在 app.json 或者 project.config.json才可以创建项目),点击新建。
对本地的项目进行单个删除或批量删除。
点击管理->选择需要删除的项目->点击删除。
删除项目实际上只会删除开发者工具项目列表中的记录,如果需要删除源文件,需要自行在项目目录下删除。
当我们从其它途径获取到了小程序的包,可以选择导入项目。
点击导入,选择非空目录下存在 app.json 或者 project.config.json 的文件夹此时项目中之前设置好的 AppID 会自动填充,你可以更换为你自己的 AppID 。
开发界面介绍
开发者工具主界面,从上到下,从左到右,分别为:菜单栏、工具栏、模拟器、目录树、编辑器、调试器六大部分。
工具栏
工具栏会根据你使用的 AppId( applicationidentification )鉴别为 测试号/注册的小程序号 展示不同的可操作项。
申请注册并配置过云开发项目工具栏(如图)。
测试号工具栏(如图)。
从左至右分别为:界面操作栏、调试及编译模式操作栏、版本管理及项目详情操作栏。
- 界面操作栏
1.用户信息
点击头像可切换账号,用于切换不同的开发者,在这里你还可以预览社区通知及订阅插件通知。
2.工具栏按钮
当我们关闭多余的操作栏,可点击界面操作栏的按钮,最少开启一项(如图)。
3.可视化
当开发者在可视化面板进行设置和操作时,代码编辑器会打开对应代码文件,并同步生成相应的代码。开发者可以点击代码的节点或者大纲,来选择对应的可视化组件。
4.云开发
小程序·云开发是微信团队联合腾讯云推出的专业的小程序开发服务。开发者可以使用云开发快速开发小程序、小游戏、公众号网页等,并且原生打通微信开放能力。开发者无需搭建服务器,可免鉴权直接使用平台提供的 API 进行业务开发。
- 调试及编辑模式操作栏
1.模式切换操作
可快速切换小程序调试模式或插件调试模式。
2.预设编译模式切换
点击普通编译下拉菜单与菜单栏中工具->编译配置所展示的列表一致,用于快速新增编译模式。
3.编译
点击后根据目前选择的模式及预设编译模式进行快速编译,并在模拟器中展示相应的结果。
4.预览
小程序将会生成一个二维码,开发者可使用微信扫码直接预览小程序(开发版)。
小程序分为开发版、体验版、正式版三个版本。
版本名称 |
简介 |
开发版 |
具有当前 AppId 开发者权限的用户在开发者工具上生成的预览版本 |
体验版 |
小程序体验版是并未上线向公众开放的版本,只是给被授权的开发人员看的,并且支持调试模式 |
正式版 |
通过小程序体验版确认小程序无误后提交代码审核,通过后需要开发者手动点击发布,小程序才会发布,成为上线小程序,并面向公众用户提供服务的版本 |
5.真机调试
在自动真机调试的情况下,微信会自动进入小程序(开发版)帮助开发者更好的定位和查找在手机上出现的问题(如图)。
6.清缓存
点击相应的清除选项,我们可以对不同的缓存进行清除。
- 调试及编译模式操作栏
1.上传
当我们需要打包体验版或发布线上版本,需要在开发者在开发者工具中点击上传按钮。
2.版本管理
打开腾讯官方代码仓库名称为 Tgit ,它的功能和我们常用的 git 功能几乎是一致的(如图),在这里,我们可以进行一系列的可视化操作代码的推送、抓取、拉取、分支的合并等。笔者在之后的课程中依然会使用命令行的形式管理课程的代码仓库,更多操作可学习实验楼的另一门课程:《 Git 与 GitHub 入门实践》。
3.详情
在这里我们可以了解项目的基本信息、本地设置、项目配置。
模拟器
模拟器可以模拟小程序在微信客户端的表现。小程序的代码通过编译后可以在模拟器上直接运行,对于绝大部分的 API 均能够在模拟器上呈现出正确的状态。
开发者可以选择不同的设备,也可以添加自定义设备来调试小程序在不同尺寸机型上的适配问题。
而底部的菜单栏,可以直观地看到当前的页面路径,场景值,页面参数。
当我们在模拟器中模拟用户的操作行为,如点击按钮 -> 跳转页面 此时可不必在目录树中翻找对应的 js 文件进行代码调试,直接点击页面路径(如图路径为 pages/index/index ),即可直接打开对应的 js 文件。
目录树
用来管理当前项目的目录结构。在目录树上右键->选择新建 Page,将自动生成页面所需要的 wxml、wxss 、js、json 文件。
编辑器
微信开发者工具目前集成了 5 种格式的文件编辑:wxml、wxss、js、json、wxs 以及图片文件的预览。
同大部分编辑器一样,工具提供了较为完善的自动补全:
- js 文件编辑会帮助开发补全所有的 API 及相关的注释解释,并提供代码模板支持
- wxml 文件编辑会帮助开发者直接写出相关的标签和标签中的属性
- json 文件编辑会帮助开发者补全相关的配置,并给出实时的提示
调试器
调试工具分为 12 大功能模块:Wxml、Console、Sources、Network、Memory、Security、Mock、AppData、Storage、Audits、Sensor、Trace:
- WXML
与浏览器中的 Elements 功能类似,用于帮助开发者开发 wxml 转化后的界面。在这里可以看到真实的页面结构以及结构对应的 wxss 属性,同时可以通过修改对应 wxss 属性,在模拟器中实时看到修改的情况(仅为实时预览,无法保存到文件)。通过调试模块左上角的选择器,还可以快速定位页面中组件对应的 wxml 代码。
- Console
Console 的意思是控制台,可以显示错误信息和打印变量的信息,除此以外你还可以在这里输入和调试代码(如图)。
- Sources
开发者可以在这里看到经过处理之后的脚本文件,代码都会被包裹在 define 函数中,并且对于 Page 代码,在尾部会有 require 的主动调用。我们也可以同浏览器一致,在这里执行相应的断点(如图)。
当代码运行到断点的时候,整个小程序都停止了,所以模拟器会出现白屏或无法操作的情况。
- Network
这个区域显示的是与网络相关的信息(如图)。
- Memory
这里体现你的代码运行时的内存占用,实际占用还包括 webview、客户端的部分,会比这个要大。
- Security
通过该面板你可以去调试当前请求的网页的安全和认证等问题并确保您已经在你的网站上正确地实现 HTTPS。
- Mock
微信开发者工具提供 API Mock 功能,可模拟如 wx.request 、 wx.downloadFile 以及 wx.getBackgroundFetchData 等 API 的调用结果,极大地降低了小程序的开发成本。
- AppData
这里为当前项目运行时的数据,实时的反应项目数据情况,你也可以在这里编辑数据,这些信息将及时同步到模拟器当中。
- Audits
对当前网页进行网络利用情况、网页性能、体验等方面的诊断,并给出一些优化建议。
- Sensor
开发者可以在这里选择模拟地理位置及模拟移动设备,调试重力感应。
- Storage
用于显示当前项目使用 wx.setStorage 或者 wx.setStorageSync 后的数据存储情况,可以直接在 Storage 上对数据进行删除(按 delete 键)、新增、修改。
- Trace
- PC 上需要先安装 adb 工具,可以参考一些主流教程进行安装,Mac 上可使用 brew 直接安装。
- 下载后直接解压 win+R 输入 CMD 开启命令提示符(如图),可以查看到版本即为安装成功
- 确定 adb 工具已成功安装后,将 Android 手机通过 USB 连接上 PC,并打开【USB 调试模式】
- 以三星(Galaxy A51 5G)为例:手机连接至电脑 -> 设置 -> 关于手机 -> 软件信息 -> 点击 7 次编译编号即可开启开发者模式 -> 重新回到设置 -> 开发者选项 -> 开启 USB 调试。
- 检验手机和电脑是否连接成功,打开刚刚的命令提示符输入命令
adb devices
在开发者工具上打开 Trace Panel,点击「Choose Devices」,选择通过电脑链接的安卓设备上传,选择连接的设备。
- 选择设备后,在手机上打开你需要调试的开发版小程序,通过右上角菜单(...)按钮 -> 点击开发者调试 -> 打开性能监控面板,重启小程序。
此时手机的页面(如图)。
点击 Choose File 再次连接手机
- 重启后,在小程序上进行模拟用户的操作,如:点击按钮、请求接口,完成操作后,通过右上角菜单(...)按钮 -> 点击开发调试 -> 导出 Trace 数据。
- 此时开发者工具 Trace Panel 上会自动拉取 Trace 文件,选择你要分析的 Trace 文件即可。
- 选中后在底部展示其具体的数据(如图)。
小程序上的性能指标说明
指标 |
说明 |
CPU |
微信小程序进程的 CPU 占用率,仅 Android 下提供 |
内存 |
微信小程序进程内存占用( Total Pss ),仅 Android 下提供 |
启动耗时 |
微信小程序启动总耗时 |
下载耗时 |
微信小程序包下载耗时,首次打开或资源包需更新时会下载 |
页面切换耗时 |
微信小程序页面切换耗时 |
帧率 / FPS |
|
首次渲染耗时 |
微信小程序首次渲染耗时 |
再次加载耗时 |
微信小程序页面再次渲染时的耗时如:开发者在页面内进行数据渲染的操作可触发( setData ) |
数据缓存 |
微信小程序通过 Storage 接口存储的缓存大小 |
快捷键设置
点击菜单栏 设置->快捷键设置,在这里你可以根据自己的使用习惯配置快捷键(如图)。
实验总结
所谓前端,也叫前台,就是小程序运行起来后,小程序使用者能看到的交互界面。
微信开发者工具主要提供的是小程序前端的开发、调试、预览环境以及代码的编译上传。
本节实验我们主要学习了开发者工具的下载、安装,创建及管理微信小程序项目,了解如何使用开发者工具在不同的场景下进行调试。在之后的实验中,我们也会反复运用到本次实验的知识。
还有一个需要注意的是,对于命令行和编辑器等软件,我们有特定的选择,你也可以使用常用的编辑器配合小程序开发者工具的使用。但是出于对完全的新手程序员的指导 —— 本次实验会选择一个最合理的一款软件,然后在所有的教程中统一使用,保持一致性,并且以后在工作中也能持续使用。
下一次实验,我们将开始编写第一行代码:”Hello World !“
第一个 Hello 小程序项目
实验介绍
这一节实验我们来编译一个 Hello world 页面,上一节的实验我们已经创建了一个名为 base-mini 的项目,请在微信开发者工具中打开它。
知识点
- 目录结构讲解
- 第一个小程序页面
- 代码结构讲解
目录结构讲解
上一次实验,我们简单介绍了开发者界面中的目录树,并以 gif 的形式创建了一组页面的 Page。
使用微信开发者工具创建项目时工具会帮我们自动创建好必要的文件及规划好目录结构,当然,我们也并不推荐开发者手动创建文件。
微信小程序包含一个描述整体程序的 app 和多个描述各自页面的 Page 。一个小程序主体部分由三个文件组成,且必须放在项目的根目录下,具体介绍如下:
文件 |
必需 |
作用 |
app.js |
是 |
小程序逻辑 |
app.json |
是 |
小程序公共配置文件 |
app.wxss |
否 |
小程序公共样式表 |
- 注册小程序( app.js )
我们可以先打开 base-mini 这个项目,并在根目录找到 app.js 文件,双击打开。
初始化的项目为我们展示了一个 logs 的存储流程,同学们可以尝试阅读并理解以下代码。
// app.js
App({
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync("logs") || []; // 创建一组数组
logs.unshift(Date.now()); // 向数组的开头添加一个或更多元素,并返回新的长度。
wx.setStorageSync("logs", logs); // 写入Storage
// 登录
wx.login({
success: (res) => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
},
});
},
globalData: {
userInfo: null,
},
});
暂时无法理解也没有关系,在接下来的实验中我们会常常遇见它们。
每个小程序都需要在 app.js 中调用 App() 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在的监听函数等。
App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。
现在来动动手吧
简单了解一下小程序的生命周期
// app.js 示例代码
App({
onLaunch() {
// 生命周期回调 —— 监听小程序初始化,全局只触发一次。
console.log("这里是onLaunch");
},
onShow() {
// 生命周期回调 —— 监听小程序启动或切换前台。
console.log("这里是onShow");
},
onHide() {
// 生命周期回调 —— 监听小程序切换后台。
console.log("点击了关闭小程序,这里是onHide");
this.test();
},
one rror() {
// 错误监听函数
console.log("这里是onError");
},
onPageNotFound(res) {
// 小程序要打开的页面不存在时触发。
wx.redirectTo({
url: "",
}); // 如果是 tabbar 页面,请使用 wx.switchTab
},
onUnhandledRejection() {
// 小程序有未处理的 Promise 拒绝时触发。
},
onThemeChange() {
// 监听系统主题变化
},
test() {
// 自定义函数 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问
console.log("这里是自定义函数");
},
});
单看注释和代码有点模糊对不对?利用 ctrl+s 快捷键保存文件,此时小程序会自动进行编译,点击一下模拟器的关闭小程序按钮,聚焦一下控制台。
此时我们可以很清楚的知道,小程序的生命周期函数调用顺序为 onLaunch()->onShow()->onHide()
- 小程序公共配置( app.json )
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、设置网络超时时间、设置多 tab 等。
完整配置项说明请参考 小程序全局配置 ,来配置更多信息。
现在,我们可以先在根目录下找到 app.json 文件,双击打开并尝试阅读并理解以下代码。
// app.json
{
// 页面路径列表
"pages": ["pages/index/index", "pages/logs/logs"],
// 全局的默认窗口表现
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle": "black"
},
// 指定使用升级后的weui样式
"style": "v2",
// 指明 sitemap.json 的位置
"sitemapLocation": "sitemap.json"
}
现在来动动手吧
菜单栏的 icon 资源文件均已上传,参考 小程序全局配置 来配置和图片一致的基础项目吧。
{
"pages": [
"pages/index/index",
"pages/module/module",
"pages/port/port",
"pages/development/development"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#2e7eee",
"navigationBarTitleText": "微信小程序基础",
"navigationBarTextStyle": "white"
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "/assets/icon/index.png",
"selectedIconPath": "/assets/icon/index-selected.png"
},
{
"pagePath": "pages/module/module",
"text": "组件",
"iconPath": "/assets/icon/module.png",
"selectedIconPath": "/assets/icon/module-selected.png"
},
{
"pagePath": "pages/port/port",
"text": "接口",
"iconPath": "/assets/icon/port.png",
"selectedIconPath": "/assets/icon/port-selected.png"
},
{
"pagePath": "pages/development/development",
"text": "拓展",
"iconPath": "/assets/icon/development.png",
"selectedIconPath": "/assets/icon/development-selected.png"
}
],
"color": "#bfbfbf",
"selectedColor": "#2e7eee"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
相关图片已上传至资源文件夹点击此处下载 Icon。
- 小程序的样式 ( app.wxss )
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
找到根目录下的 app.wxss 文件,双击并打开它。
/**app.wxss**/
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
- 如何引用
打开 pages\index\index.wxml 文件,并修改成这样
<!--pages/index/index.wxml-->
<view class="container">
<text>pages/index/index.wxml</text>
</view>
ctrl+s(保存文件),聚焦控制台。
- 如何覆盖
当盒子的 class 名称与 app.wxss 的 class 一致时引用全局样式,如果全局样式无法满足页面需求,我们也可以在全局样式的基础上增加局部样式。以 pages/index/index.wxss 为例。
/* pages/index/index.wxss */
.container {
/* 将内边距设为0 */
padding: 0;
}
保存后可以发现,全局样式中的 padding 属性已经被覆盖了。
配置完和图片一致的基础项目,我们可以发现 pages 下也多了几个文件夹。
除了上节实验右击目录创建 page 文件以外,我们又 get 了一种新的方式 —— 直接在配置文件( app.json )中新增目录。
展开 index 我们可以发现一个小程序由四个页面( Page )组成,分别是:
文件类型 |
必须 |
作用 |
js |
是 |
页面逻辑 |
wxml |
是 |
页面结构 |
json |
否 |
页面配置 |
wxss |
否 |
页面样式表 |
注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名。
第一个小程序页面
刚刚我们通过修改 app.json 的方式新建了 4 组页面。
现在来动动手吧
打开 pages/index 别用复制,写入以下代码
<!--pages/index/index.wxml-->
<view class="container">
<!-- 数据绑定 -->
<text class="blue">{{msg}}</text>
<!-- 列表渲染 -->
<view wx:for="{{array}}" wx:key="index">{{item}}</view>
<!-- 条件渲染 -->
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> 小程序 </view>
<!-- 模板 -->
<template name="tab">
<view> 菜单id: {{tabId}}, 菜单名称: {{tabName}} </view>
</template>
<template is="tab" data="{{...tabA}}"></template>
<template is="tab" data="{{...tabB}}"></template>
<template is="tab" data="{{...tabC}}"></template>
<template is="tab" data="{{...tabD}}"></template>
</view>
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
msg: "你好,蓝桥",
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
view: "MINA",
tabA: { tabId: 1, tabName: "首页" },
tabB: { tabId: 2, tabName: "组件" },
tabC: { tabId: 3, tabName: "接口" },
tabD: { tabId: 4, tabName: "拓展" },
},
/**
* 生命周期函数--监听页面加载
* @query 打开当前页面路径中的参数
*/
onl oad: function (options) {
console.log("onLoad");
this.test(options.test);
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log("onShow");
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log("onReady");
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {},
/**
* 用户点击右上角转发到朋友圈
*/
onShareTimeline: function () {},
/**
* 用户点击右上角收藏
*/
onAddToFavorites: function () {},
/**
* 页面滚动触发事件的处理函数
*/
onPageScroll: function () {},
/**
* 页面尺寸改变时触发
*/
onResize: function () {},
/**
* 当前是 tab 页时,点击 tab 时触发
*/
onTabItemTap: function () {},
/**
* 自定义函数
*/
test(options) {
console.log(options);
},
});
打开 pages/index/index.json 文件
{
"navigationBarBackgroundColor": "#2e7eee",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "首页",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": true
}
在 /assets/css 中新建公共样式文件 common.wxss
.blue {
color: #2e7eee;
}
在 pages/index/index.wxss 中使用 @import 导入公共样式
/* pages/index/index.wxss */
/* 导入公共样式 */
@import "/assets/css/common";
.container {
/* 将内边距设为0 */
padding: 0;
}
代码结构讲解
- 页面逻辑( js )
对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
* @query 打开当前页面路径中的参数
*/
onl oad: function (options) {
console.log("onLoad");
this.test(options.test);
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log("onShow");
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
console.log("onReady");
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {},
/**
* 用户点击右上角转发到朋友圈
*/
onShareTimeline: function () {},
/**
* 用户点击右上角收藏
*/
onAddToFavorites: function () {},
/**
* 页面滚动触发事件的处理函数
*/
onPageScroll: function () {},
/**
* 页面尺寸改变时触发
*/
onResize: function () {},
/**
* 当前是 tab 页时,点击 tab 时触发
*/
onTabItemTap: function () {},
/**
* 自定义函数
*/
test(options) {
console.log(options);
},
});
我们可以尝试增加编译模式,模拟打开当前页面路径并新增一个参数来了解页面生命周期。
此时我们可以看出,包含页面内的生命周期函数调用顺序为 onLaunch() -> onShow() -> onLoad() -> onShow() -> onReady()
- 页面结构( wxml )
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
在接下来的实验中,我们会详细的讲解 WXML 语法。
- 数据绑定
<!--pages/index/index.wxml-->
<view class="container">
<!-- 数据绑定 -->
<text class="blue">{{message}}</text>
· · ·
</view>
// pages/index/index.js
Page({
data: {
message: "你好,蓝桥",
// 此处省略以下代码
},
});
- 列表渲染
- <!--pages/index/index.wxml-->
- <view class="container">
- <!-- 此处省略以上代码 -->
- <!-- 列表渲染 -->
- <view wx:for="{{array}}" wx:key="index">{{item}}</view>
- </view>
// pages/index/index.js
Page({
data: {
// 此处省略以上代码
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
});
- 条件渲染
- <!--pages/index/index.wxml-->
- <view class="container">
- <!-- 此处省略以上代码 -->
- <!-- 条件渲染 -->
- <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
- <view wx:elif="{{view == 'APP'}}"> APP </view>
- <view wx:else="{{view == 'MINA'}}"> 小程序 </view>
- </view>
// pages/index/index.js
Page({
data: {
// 此处省略以上代码
view: "MINA",
},
});
- 模板
- <!--pages/index/index.wxml-->
- <view class="container">
- <!-- 此处省略以上代码 -->
- <!-- 模板 -->
- <template name="tab">
- <view> 菜单id: {{tabId}}, 菜单名称: {{tabName}} </view>
- </template>
- <template is="tab" data="{{...tabA}}"></template>
- <template is="tab" data="{{...tabB}}"></template>
- <template is="tab" data="{{...tabC}}"></template>
- <template is="tab" data="{{...tabD}}"></template>
- </view>
// pages/index/index.js
Page({
data: {
// 此处省略以上代码
tabA: { tabId: 1, tabName: "首页" },
tabB: { tabId: 2, tabName: "组件" },
tabC: { tabId: 3, tabName: "接口" },
tabD: { tabId: 4, tabName: "拓展" },
},
});
- 页面配置( json )
每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。
{
"navigationBarBackgroundColor": "#2e7eee",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "首页",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": true
}
页面中配置项在当前页面会覆盖 app.json 的 window 中相同的配置项。文件内容为一个 JSON 对象,有以下属性:
- 配置项
让我们先简单了解一下,在接下来的实验中,我们会常常遇见它们~
属性 |
类型 |
默认值 |
描述 |
最低版本 |
navigationBarBackgroundColor |
HexColor |
#000000 |
导航栏背景颜色,如 #000000 |
|
navigationBarTextStyle |
string |
white |
导航栏标题颜色,仅支持 black / white |
|
navigationBarTitleText |
string |
导航栏标题文字内容 |
||
navigationStyle |
string |
default |
导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮。参见注 1。 |
iOS/Android 微信客户端 7.0.0,Windows 微信客户端不支持 |
backgroundColor |
HexColor |
#ffffff |
窗口的背景色 |
|
backgroundTextStyle |
string |
dark |
下拉 loading 的样式,仅支持 dark / light |
|
backgroundColorTop |
string |
#ffffff |
顶部窗口的背景色,仅 iOS 支持 |
微信客户端 6.5.16 |
backgroundColorBottom |
string |
#ffffff |
底部窗口的背景色,仅 iOS 支持 |
微信客户端 6.5.16 |
enablePullDownRefresh |
boolean |
false |
是否开启当前页面下拉刷新。 详见 Page.onPullDownRefresh |
|
onReachBottomDistance |
number |
50 |
页面上拉触底事件触发时距页面底部距离,单位为 px。 详见 Page.onReachBottom |
|
pageOrientation |
string |
portrait |
屏幕旋转设置,支持 auto / portrait / landscape 详见 响应显示区域变化 |
|
disableScroll |
boolean |
false |
设置为 true 则页面整体不能上下滚动。 只在页面配置中有效,无法在 app.json 中设置 |
|
usingComponents |
Object |
否 |
页面自定义组件配置 |
|
initialRenderingCache |
string |
页面初始渲染缓存配置 |
||
style |
string |
default |
启用新版的组件样式 |
|
Object |
否 |
单页模式相关配置 |
页面配置中只能设置 app.json 中 window 对应的配置项,以决定本页面的窗口表现,所以无需写 window 这个属性。
- 注 1:关于 navigationStyle
- iOS/Android 客户端 7.0.0 以下版本,navigationStyle 只在 app.json 中生效。
- iOS/Android 客户端 6.7.2 版本开始,navigationStyle: custom 对 web-view 组件无效
- 开启 custom 后,低版本客户端需要做好兼容。开发者工具基础库版本切换到 1.7.0(不代表最低版本,只供调试用)可方便切换到旧视觉
- Windows 客户端 3.0 及以上版本,为了给用户提供更符合桌面软件的使用体验,统一了小程序窗口的导航栏,navigationStyle: custom 不再生效
- singlePage
基础库 2.11.3 及以上版本支持,目前小程序分享到朋友圈后会打开单页面模式
- 页面样式表( wxss )
在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
/* pages/index/index.wxss */
/* 导入公共样式 */
@import "/assets/css/common";
.container {
/* 将内边距设为0 */
padding: 0;
}
为降低开发门槛,微信小程序的 WXSS 具有 CSS 大部分特性,当然也对 CSS 进行了扩充及修改,与 CSS 相比,不熟悉 CSS 开发的同学可以学习蓝桥的另一门实验:CSS3 简明教程
我们还可以在 WXSS 中做以下事情
- 尺寸单位( rpx:responsive pixel )
可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx,我们可以根据不同的机型及分辨率进行换算,以便达到最好的还原效果。
- 样式导入
使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
@import "/assets/css/common"; // 可以不写文件类型
实验总结
本次的实验我们主要了解了小程序的项目结构,单页面的结构以及动手完善了导航栏和首页。
我们期望学员可以跟着实验的节奏反复练习,但是在第一次阅读本次实验的过程中,遇到一些技术话题时,不需要做到力求甚解。跟着线路走,一步步前进,慢慢地脑子里对这些新话题有了基本的印象,等最终完成所有实验后,再去对进行深度学习。不用着急。在这里可以引用一句话:刻意练习,每日精进。
下一节实验,我们将更深入的探索 WXML 语法
WXML 语法
实验介绍
这一节实验我们通过数据绑定、列表渲染、条件渲染、模板、引用 5 个方面更深入的探索 WXML ,它属于框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
知识点
- 数据绑定
- 列表渲染
- 条件渲染
- 模板
- 引用
数据绑定
WXML 中的动态数据均来自对应 Page 的 data,使用 Mustache 语法,即双大括号模式。如:pages/index/index.wxml 的数据来源,对应的是 pages/index/index.js 中 Page 的 data。
打开 base-mini 项目的 pages/index/index.js ,让我们先定义一组数据。
// pages/index/index.js
Page({
/**
* 这里就是动态数据的来源
*/
data: {
msg: '你好,蓝桥',
age: 18,
condition: true,
object: {
string: '我在学习WXML语法',
color: 'pink'
},
userInfo:{
name:'蓝桥',
age:25,
color:'red'
},
array: [1, 2, 3, 4, 5, 6, 7, 8, 9],
view: 'MINA',
tabA: {
tabId: 1,
tabName: '首页'
},
tabB: {
tabId: 2,
tabName: '组件'
},
tabC: {
tabId: 3,
tabName: '接口'
},
tabD: {
tabId: 4,
tabName: '拓展'
}
},
// 此处省略以下代码
如果想在页面上渲染它需要使用 Mustache 语法(双大括号)即数据绑定将变量包起来。
打开 pages/index/index.wxml 让我们看看 WXML 都支持哪些写法:
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 数据绑定 -->
<view class="title">数据绑定</view>
<view>常见类型的普通写法:</view>
<view class="blue">字符串:{{msg}}</view>
<view>三元运算:{{age >= 18 ? '成年啦':'还没有哦'}}</view>
<view>渲染布尔类型:<checkbox checked="{{condition}}"></checkbox> </view>
<view>直接写上布尔类型:<checkbox checked="{{false}}"></checkbox> </view>
<view>对象:{{object.string}}</view>
<view class="{{object.color}}">class名称:我是 pink Class</view>
<view style="color:{{object.color}}">样式属性:我是粉色的{{age+2}}岁</view>
<view>值得注意的写法:</view>
<!-- 不要直接写 false 会被识别为字符串,因写{{false}}或使用变量渲染 -->
<view
>我不应该被勾选:<checkbox checked="false"></checkbox>
<!-- 可以在 Mustache 内直接进行组合,构成新的对象或者数组。 -->
<view
>变量名相同,所以被覆盖了:<template
is="objectCombine"
data="{{...object, ...userInfo,age}}"
></template
></view>
<!-- 个人介绍模板 -->
<template name="objectCombine">
<view>名称:{{name}}</view>
<view>年龄:{{age}}</view>
<view>喜欢的颜色:{{color}}</view>
</template>
</view>
· · ·
把样式也一起加上,打开 pages/index/index.wxss 文件
/* pages/index/index.wxss */
/* 导入公共样式 */
@import "/assets/css/common";
.container {
/* 将内边距设为0 */
padding: 0;
}
.title {
width: 100%;
text-align: left;
font-size: 40rpx;
font-weight: bold;
}
.pink {
color: pink;
}
保存并编译,此时我们的页面展示效果如下:
太简单了是吧,只要格式写对,括号没有问题,那就没有问题。但这有何意义? 我们直接在 WXML 中写死 “你好蓝桥”,不是也能展示相同的意思吗?为什么还需要费劲的做数据绑定呢?
这是因为:前端框架的意义是让前端开发更方便、更高效,那么数据绑定肯定也是为这个目的服务的。数据绑定是为了实现一种“动态”的效果,后台的数据更新了,前端页面也自动更新;前端页面上的数据更新了,后台的数据也自动更新。
这种动态的思想可以追溯到 MVC 设计模式:
MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。
目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。
感兴趣的同学可以多找找其他学习资料了解,在这里就不深入赘述了。
列表渲染
如果你希望多次的渲染相同的组件,但每次的值都不同,在 JavaScript 我们可以使用过 for 循环,WXML 当然也可以。
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。小程序默认数组当前项的下标变量名为 index , 数组当前项的变量名为 item。
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 列表渲染 -->
<view class="title">列表渲染</view>
<view wx:for="{{array}}" wx:key="index">{{item}}</view>
<!-- 此处省略以下代码 -->
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
也就是说:在不使用 wx:key 的情况下,如果数组内的数据发生了改变,则会重新创建每个 item 对象,然后重新渲染列表降低页面性能,同时控制台会出现一个警告。(如图)在使用 wx:key 的情况下,如果数组内的数据发生了改变,只是将对应的对象重新排序。未发生变化的对象则不会重新创建。
站在性能的角度上,我们建议 wx:key 和 wx:for 是成对出现的,但如果明确了该页面的数据就是不会被改变的,可以不使用 wx:key。
这时有同学会问了,如果我有多个数组,且需要嵌套使用。怎么去改变当前元素的变量名和下标的变量名呢?
下面我们写一个经典的九九乘法表来实现元素变量名和下标变量名的改变
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 列表渲染 -->
<view class="title">列表渲染</view>
<view wx:for="{{array}}" wx:key="index">{{item}}</view>
<view>九九乘法表</view>
<!-- 循环列 -->
<view
class="row"
wx:for="{{array}}"
wx:for-index="arrayIndex"
wx:for-item="row"
>
<!-- 循环行 -->
<view wx:for="{{array}}" wx:for-item="col">
<view class="col" wx:if="{{row <= col}}">
{{row}} * {{col}} ={{row * col}}
</view>
</view>
</view>
<!-- 此处省略以下代码 -->
改变一下 CSS 让它更好看些,打开 pages/index/index.css
/* pages/index/index.css */
· · · .row {
display: flex;
justify-content: flex-start;
font-size: 18rpx;
}
.col {
border: 1rpx solid #333;
}
此时页面上的效果应为:
条件渲染
在小程序的框架中,通常使用 wx:if="" 和 hidden 来判断是否需要渲染该代码块
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 条件渲染 -->
<view class="title">条件渲染</view>
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> 小程序 </view>
<view hidden="{{false}}"> hidden小程序 </view>
<view hidden="{{true}}"> hidden小程序 </view>
<!-- 此处省略以下代码 -->
此时我们的页面上展示效果应为:
两者之间最大的区别在于性能的开销。wx:if 适合一些不经常变化的地方,因为它的每次变化都是需要重新局部渲染的,并且在此之后销毁,会占用更多的资源。而hidden 则是始终保持一个渲染效果,当条件变化时也只是切换展示与隐藏。此时我们可以看看页面的 WXML 渲染效果。
我们可以发现,5 组条件渲染判断,只渲染出了 3 组,hidden 通过添加样式的方式来切换显示display:none ,因此hidden属性不要和display一起使用。而使用 wx:if 的渲染方式,只渲染出了条件成立的 1 组。
所以 wx:if 有更高的切换消耗,而 hidden 有更高的初始化消耗。
在使用时可根据场景选用不同的渲染方式。
模板
小程序在设计时同样也遵循了目前主流框架的主要特征——组件化,在小程序中组件化的实现方式有两种:Template 模板 和 Component 组件。他们都可以在模板中定义代码片段,然后在不同的地方调用。
- Template 模板
template 模板主要用于展示,不包含事件处理,需要处理的事件逻辑需要放在调用模板的页面中。
<!--pages/index/index.wxml-->
<view class="container">
<!-- 数据绑定 -->
<!-- 此处省略以上代码 -->
<!-- 可以在 Mustache 内直接进行组合,构成新的对象或者数组。 -->
<!-- 应用个人介绍模板,并将相关数据传给它 -->
<view
>变量名相同,所以被覆盖了:<template
is="objectCombine"
data="{{...object, ...userInfo,age}}"
></template
></view>
<!-- 此处省略以上代码 -->
<!-- 模板 -->
<view class="title">模板</view>
<!-- 基础模板 -->
<template name="tab">
<view> 菜单id: {{tabId}}, 菜单名称: {{tabName}} </view>
</template>
<!--
个人介绍模板
这里创建的模板将展示 名称、年龄、喜欢的颜色
-->
<template name="objectCombine">
<view>名称:{{name}}</view>
<view>年龄:{{age}}</view>
<view>喜欢的颜色:{{color}}</view>
</template>
<template is="tab" data="{{...tabA}}"></template>
<template is="tab" data="{{...tabB}}"></template>
<template is="tab" data="{{...tabC}}"></template>
<template is="tab" data="{{...tabD}}"></template>
<!-- 此处省略以下代码 -->
</view>
使用 name 属性定义模板名称,再使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入。在模板中可以接受变量, 使用 {{}} 展示。 为变量的传递者由调用该模板的页面传递。
- Component 组件
Component 像页面一样由 wxml 、wxss 、js 和 json 4 个文件组成,且需要把这 4 个文件放在同一个目录中。与页面不一样的是,Component 中的构造函数(也可以称构造器)是 Component({}),而页面中的构造函数是 Page({})。
让我们新建一个页面:
自动创建的文件会自动配置好代码。只需在引入组件的时候,在引入组件的页面的 json 文件中配置组件的名称和组件的位置即可。
这里一定要注意我们目录结构,我们可以把项目中的业务文件放在 pages 中,资源文件放在与 pages 同级的 assets 文件中,工具类存放在 utils 文件中,同样把共用的自定义组件存放在同级的 component 文件中。这样便于管理,查找使用。
和 page 不同的是,在 test.json 中 "component": true 表示自定义组件声明,代码如下所示。
{
"component": true,
"usingComponents": {}
}
同时 js 文件也与 page 不同:
// component/test.js
Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {},
/**
* 组件的方法列表
*/
methods: {},
});
- Component 构造器可用于定义组件,调用 Component 构造器时可以指定组件的属性、数据、方法等。
- properties 是组件的对外属性,是属性名到属性设置的映射表,属性设置中可包含三个字段, type 表示属性类型、 value 表示属性初始值、 observer 表示属性值被更改时的响应函数。
- data 和普通页面的 data 一样,是组件的内部数据,和 properties 一同用于组件的模版渲染。
- methods 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用。
如果还需要其他属性、数据、方法等可查看微信小程序官方文档 Component 构造器。
引用
WXML 提供两种文件引用方式
- import 用来导入模板
- include 用来导入除模板以外的内容。
我们在上一小节”模板“中使用Template 模板在 pages/index/index.wxml 中创建了几个示例,现在可以尝试将他们抽离出来。
- import
新建 pages/template/template.wxml ,将 pages/index/index.wxml 中模板的代码块剪切过来
<!-- pages/template/template.wxml -->
<!-- 基础模板 -->
<template name="tab">
<view> 菜单id: {{tabId}}, 1菜单名称: {{tabName}} </view>
</template>
<!-- 个人介绍模板 -->
<template name="objectCombine">
<view>名称:{{name}}</view>
<view>年龄:{{age}}</view>
<view>喜欢的颜色:{{color}}</view>
</template>
ctrl+s 保存并编译,此时页面上原有的模板部分已经没有内容了。
回到 pages/index/index.wxml 页面,使用 import 声明需要使用的模板文件
<!--pages/index/index.wxml-->
<!-- 声明需要使用的模板文件 -->
<import src="/pages/template/template.wxml"></import>
<view class="container">
<!-- 数据绑定 -->
<view class="title">数据绑定</view>
<view>常见类型的普通写法:</view>
<view class="blue">字符串:{{msg}}</view>
<!-- 此处省略以上代码 -->
<!-- 模板 -->
<view class="title">模板</view>
<template is="tab" data="{{...tabA}}"></template>
<template is="tab" data="{{...tabB}}"></template>
<template is="tab" data="{{...tabC}}"></template>
<template is="tab" data="{{...tabD}}"></template>
</view>
ctrl+s 保存并编译。模板代码块的内容又出现了。
以上就是简单的 import引用方法。
值得注意的是:import 是有作用域的概念的
举个例子:我们可以在 template 目录新建一个 a.wxml 文件
<!-- pages/template/a.wxml -->
<template name="a">
<text>我是模板"a"</text>
</template>
在 pages/template/template.wxml 中引用它。
<!-- pages/template/template.wxml -->
<import src="a.wxml" />
<!-- 基础模板 -->
<template name="tab">
<view> 菜单id: {{tabId}}, 1菜单名称: {{tabName}} </view>
</template>
<!-- 个人介绍模板 -->
<template name="objectCombine">
<view>名称:{{name}}</view>
<view>年龄:{{age}}</view>
<view>喜欢的颜色:{{color}}</view>
</template>
回到 pages/index/index.wxml 页面,尝试引用 a 模板
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 条件渲染 -->
<view class="title">条件渲染</view>
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> 小程序 </view>
<view hidden="{{false}}"> hidden小程序 </view>
<view hidden="{{true}}"> hidden小程序 </view>
<!-- 模板 -->
<view class="title">模板</view>
<template is="tab" data="{{...tabA}}"></template>
<template is="tab" data="{{...tabB}}"></template>
<template is="tab" data="{{...tabC}}"></template>
<template is="tab" data="{{...tabD}}"></template>
<!-- 引用a模板 -->
<template is="a"/>
</view>
此时控制台会报出异常:
这就是 import 有作用域的概念的体现,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。
- include
小程序 wxml 中使用 include 来包含别的 wxml 文件时,如果该 wxml 文件的目录下有同名的 wxss 文件,其中的样式是不会同步包含进来的。
include可以将目标文件除了<template/>的整个代码引入,相当于是拷贝到include位置,如:
新建 page 文件 footer。
<!--pages/footer/footer.wxml-->
<view class="footer">刻意练习,每日精进</view>
修改 pages/footer/footer.wxss 样式
/* pages/footer/footer.wxss */
.footer {
background-color: #2e7eee;
color: #ffffff;
text-align: center;
}
回到 pages/index/index.wxml 中
<!--pages/index/index.wxml-->
<!-- 此处省略以上代码 -->
<!-- 引用 footer -->
<include src="/pages/footer/footer.wxml"></include>
</view>
此时样式还没有被引用进来,我们需要打开 pages/index/index.wxss 引入样式
/* pages/index/index.wxss */
/* 导入公共样式 */
@import "/assets/css/common";
@import "/pages/footer/footer";
/* 此处省略以下代码 */
ctrl+s保存并编译,页面的展示效果如下:
实验总结
本次的实验我们主要了解了 WXML 语法中的数据绑定、列表渲染、条件渲染、模板、引用。
在小程序中,WXML 充当的就是类似 HTML 的角色,在之后的实验中,我们还会深入了解更多相关能力。
组件
实验介绍
在 2.3 的实验中,我们学习了模板开发,对 component 有了一定的了解,但那通常都是自己封装的。这一节的实验我们将会了解框架为开发者提供的一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。
知识点
- 什么是组件
- 视图容器
- 基础内容
- 表单组件
- 导航
- 媒体组件
- 地图组件
- 画布组件
什么是组件
小程序官方为我们提供了各种各样的组件,截止至 v2.18.0 (2021-06-23) 按照类型来划分可以分成:视图容器组件、基础内容组件、表单组件、导航组件、媒体组件、地图组件和画布组件共七类 42 种。
因为组件繁多,在本次实验中我会根据综合案例(如图)来讲解思维导图中标注为红色的常用组件。
组件和 HTML 中的元素差不多,一个组件是指从组件开始标签到结束标签的所有代码,因为平台的差异性所以小程序中的组件可能会被转译为不同端对应的代码,所以在进行小程序开发的时候不能使用除上述组件之外的标签。
- 组件的定义
- 组件是视图层的基本组成单元。
- 组件自带一些功能与微信风格一致的样式
- 一个组件通常包括 开始标签 和 结束标签 , 用来修饰这个组件的属性,及在两个标签之内的内容
<!-- button:开始标签和接触表现 type:属性名 primary:属性值 '按钮':内容 -->
<button type="primary">按钮</button>
- 公共属性
所有组件都拥有的共同属性
属性名 |
类型 |
描述 |
注解 |
id |
String |
组件的唯一标识 |
保持整个页面唯一 |
class |
String |
组件的样式类 |
在对应的 WXSS 中定义的样式类 |
style |
String |
组件的内联样式 |
可以动态设置的内联样式 |
hidden |
Boolean |
组件是否显示 |
所有组件默认显示 |
data-* |
Any |
自定义属性 |
组件上触发的事件时,会发送给事件处理函数 |
bind* / catch* |
EventHandler |
组件的事件 |
详见事件 |
- 属性类型
类型 |
描述 |
注解 |
Boolean |
布尔值 |
组件写上该属性,不管是什么值都被当作 true;只有组件上没有该属性时,属性值才为false。 如果属性值为变量,变量的值会被转换为 Boolean 类型 |
Number |
数字 |
1, 2.5 |
String |
字符串 |
"string" |
Array |
数组 |
[ 1, "string" ] |
Object |
对象 |
{ key: value } |
EventHandler |
事件处理函数名 |
"handlerName" 是 Page 中定义的事件处理函数名 |
Any |
任意属性 |
视图容器
- swiper
滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为。所以通常swiper和swiper-item都是成对出现的
<swiper>
<swiper-item></swiper-item>
</swiper>
- swiper-item
仅可放置在swiper组件中,宽高自动设置为 100%。
- view
视图容器
让我们来动动手吧
创建 pages/module/demo 文件,打开 demo.wxml
<!--pages/module/demo.wxml-->
<view class="demo">
<view class="swiper-item">
<!--
indicator-dots:'是否显示面板指示点'
autoplay:'是否自动切换'
interval:'自动切换时间间隔'
duration:'滑动动画时长'
-->
<swiper
indicator-dots="{{indicatorDots}}"
autoplay="{{autoplay}}"
interval="{{interval}}"
duration="{{duration}}"
>
<block wx:for="{{background}}" wx:key="*this">
<swiper-item>
<view class="swiper-item {{item}}">{{index}}</view>
</swiper-item>
</block>
</swiper>
</view>
</view>
在 demo.js 里加点参数
// pages/module/demo.js
Page({
/**
* 页面的初始数据
*/
data: {
background: ["demo-text-1", "demo-text-2", "demo-text-3"],
indicatorDots: true,
vertical: false,
autoplay: true,
interval: 2000,
duration: 500,
},
// 此处省略以下代码
});
这时候的它还很丑,我们可以美化一下。
打开 demo.wxss
/* pages/module/demo.wxss */
.demo-text-1 {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background: #2e7eee;
text-align: center;
color: #ffffff;
font-size: 50rpx;
}
.demo-text-2 {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background: #43c2ad;
text-align: center;
color: #ffffff;
font-size: 50rpx;
}
.demo-text-3 {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background: #7d39aa;
text-align: center;
color: #ffffff;
font-size: 50rpx;
}
基础内容
- icon
图标。组件属性的长度单位默认为 px,2.4.0起支持传入单位(rpx/px)。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
type |
string |
是 |
icon 的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear |
||
size |
number/string |
23 |
否 |
icon 的大小 |
|
color |
string |
否 |
icon 的颜色,同 css 的 color |
- text
文本
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
selectable |
boolean |
false |
否 |
文本是否可选 (已废弃) |
|
user-select |
boolean |
false |
否 |
文本是否可选,该属性会使文本节点显示为 inline-block |
|
space |
string |
否 |
显示连续空格 |
||
decode |
boolean |
false |
否 |
是否解码 |
- space 的合法值
值 |
说明 |
ensp |
中文字符空格一半大小 |
emsp |
中文字符空格大小 |
nbsp |
根据字体设置的空格大小 |
值得注意的是:
让我们动动手吧
打开 demo.wxml,试着使用 和 实现三个不同的提示。
<!--pages/module/demo.wxml-->
<!-- 此处省略以上代码 -->
<view class="icon-box">
<view class="icon">
<icon type="success" size="50"></icon>
<text>成功</text>
</view>
<view class="icon">
<icon type="info" size="50"></icon>
<text>提示</text>
</view>
<view class="icon">
<icon type="cancel" size="50"></icon>
<text>错误</text>
</view>
</view>
</view>
修改一下样式 demo.wxss。
/* pages/module/demo.wxss */
/* 此处省略以上代码 */
.icon-box {
display: flex;
}
.icon {
flex-direction: column;
display: flex;
width: 33%;
text-align: center;
}
表单组件
- button
按钮,需要用户点击触发的如:表单提交、用户授权、打开客服会话框、获取手机号等都需要使用button按钮。
值得注意的是:
- 在 button 组件中 button-hover 默认样式为{ background-color:rgba(0,0,0,0.1); opacity:0.7; }
- bindgetphonenumber 从 1.2.0 开始支持,但是在 1.5.3 以下版本中无法使用 wx.canIUse 进行检测,建议使用基础库版本进行判断。
- 在bindgetphonenumber 等返回加密信息的回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。
- 从 2.1.0 起,button 可作为原生组件的子节点嵌入,以便在原生组件上使用 open-type 的能力。
- 目前设置了 form-type 的 button 只会对当前组件中的 form 有效。因而,将 button 封装在自定义组件中,而 form 在自定义组件外,将会使这个 button 的 form-type 失效。
- checkbox
多选项目
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
value |
string |
否 |
checkbox标识,选中时触发checkbox-group的 change 事件,并携带 checkbox 的 value |
||
disabled |
boolean |
false |
否 |
是否禁用 |
|
checked |
boolean |
false |
否 |
当前是否选中,可用来设置默认选中 |
|
color |
string |
#09BB07 |
否 |
checkbox 的颜色,同 css 的 color |
- checkbox-group
多项选择器,内部由多个checkbox组成。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
bindchange |
EventHandle |
否 |
checkbox-group中选中项发生改变时触发 change 事件,detail = {value:[选中的 checkbox 的 value 的数组]} |
- form
表单。将组件内的用户输入的switch input checkbox slider radio picker 提交。
当点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 value 值进行提交,需要在表单组件中加上 name 来作为 key。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
report-submit |
boolean |
false |
否 |
是否返回 formId 用于发送模板消息 |
|
report-submit-timeout |
number |
0 |
否 |
等待一段时间(毫秒数)以确认 formId 是否生效。如果未指定这个参数,formId 有很小的概率是无效的(如遇到网络失败的情况)。指定这个参数将可以检测 formId 是否有效,以这个参数的时间作为这项检测的超时时间。如果失败,将返回 requestFormId:fail 开头的 formId |
|
bindsubmit |
eventhandle |
否 |
携带 form 中的数据触发 submit 事件,event.detail = {value : {'name': 'value'} , formId: ''} |
||
bindreset |
eventhandle |
否 |
表单重置时会触发 reset 事件 |
- input
输入框。该组件是原生组件,使用时请注意相关限制
值得注意的是:
- confirm-type 的最终表现与手机输入法本身的实现有关,部分安卓系统输入法和第三方输入法可能不支持或不完全支持
- input 组件是一个原生组件,字体是系统字体,所以无法设置 font-family
- 在 input 聚焦期间,避免使用 css 动画
- 对于将 input 封装在自定义组件中、而 form 在自定义组件外的情况, form 将不能获得这个自定义组件中 input 的值。此时需要使用自定义组件的 内置 behaviors wx://form-field
- 键盘高度发生变化,keyboardheightchange 事件可能会多次触发,开发者对于相同的 height 值应该忽略掉
- picker
从底部弹起的滚动选择器。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
header-text |
string |
否 |
选择器的标题,仅安卓可用 |
||
mode |
string |
selector |
否 |
选择器类型 |
|
disabled |
boolean |
false |
否 |
是否禁用 |
|
bindcancel |
eventhandle |
否 |
取消选择时触发 |
除了上述通用的属性,对于不同的 mode,picker拥有不同的属性。
目前支持 5 种选择器(mode) 默认为普通选择器:普通选择器(selector)、多列选择器(multiSelector)、时间选择器(time)、日期选择器(date)、省市区选择器(region)
- radio
单选项目。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
value |
string |
否 |
radio 标识。当该radio 选中时,radio-group 的 change 事件会携带radio的 value |
||
checked |
boolean |
false |
否 |
当前是否选中 |
|
disabled |
boolean |
false |
否 |
是否禁用 |
|
color |
string |
#09BB07 |
否 |
radio 的颜色,同 css 的 color |
- radio-group
单项选择器,内部由多个 radio 组成。
属性 |
类型 |
默认值 |
必填 |
说明 |
最低版本 |
bindchange |
EventHandle |
否 |
radio-group中选中项发生改变时触发 change 事件,detail = {value:[选中的 radio 的 value 的数组]} |
让我们来动动手吧
打开 demo.wxml,试着使用 form , checkbox-group , checkbox,input,picker来实现一个简单的问卷调查。
<!--pages/module/demo.wxml-->
<!--此处省略以上代码-->
<view class="page-body">
<form bindsubmit="formSubmit">
<p class="title"></p>
<p class="title">请对本次实验进行评价</p>
<view class="page-checkbox-group">
<!--
bindchange:'选中项发生改变时触发 change 事件'
checked:'默认选中项'
-->
<checkbox-group bindchange="checkboxChange">
<label class="checkbox-label" wx:for="{{checkboxItems}}" wx:key="value">
<checkbox value="{{item.value}}" checked="{{item.checked}}">{{item.name}}</checkbox>
</label>
</checkbox-group>
</view>
<p class="title">还想告诉我们什么?</p>
<!--
type:'input 的类型'
number:'数字输入键盘'
placeholder:'输入框为空时占位符'
-->
<input type="number" placeholder="不如打个分吧!" />
<!--
bindchange:'value 改变时触发 change 事件,event.detail = {value}'
value:'表示选择了 range 中的第几个(下标从 0 开始)'
range:'mode 为 selector 或 multiSelector 时,range 有效'
-->
<p class="title">今天天气怎么样</p>
<picker bindchange="bindPickerChange" value="{{index}}" range="{{pickerArray}}">
<view class="picker">
当前选择:{{pickerArray[pickerIndex]}}
</view>
</picker>
<button type="primary">提交</button>
</form>
</view>
</view>
在 demo.js 中把参数及方法加上
// pages/module/demo.js
Page({
/**
* 页面的初始数据
*/
data: {
background: ['demo-text-1', 'demo-text-2', 'demo-text-3'],
indicatorDots: true,
vertical: false,
autoplay: true,
interval: 2000,
duration: 500,
checkboxItems: [
{value: 1, name: '本次实验很棒'},
{value: 2, name: '下节课还想学' ,checked:true},
{value: 3, name: '前端真的太美妙了'}
],
checkboxSelect:[],
pickerArray:['晴朗','多云','阴雨'],
pickerIndex:''
},
// 复选选中项发生改变,把选择的内容存起来
checkboxChange(e){
this.setData({
checkboxSelect:e.detail.value
})
},
// 选择器的值改变
bindPickerChange: function(e) {
this.setData({
pickerIndex: e.detail.value
})
},
// 此处省略以下代码
打开 demo.wxss 优化一点点样式
/* pages/module/demo.wxss */
/* 此处省略以上代码 */
.icon-box {
display: flex;
}
.icon {
flex-direction: column;
display: flex;
width: 33%;
text-align: center;
}
.page-body {
width: 95%;
margin: 0 auto;
}
.checkbox-label {
display: flex;
flex-direction: column;
margin-top: 10rpx;
}
此时运行效果如下:
导航
- navigator
它的主要用处是跳转执行,跳转可分为当前页面内跳转、前往页面外部的跳转。
open-type 的合法值
值 |
说明 |
最低版本 |
navigate |
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。 |
|
redirect |
关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。 |
|
switchTab |
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 |
|
reLaunch |
关闭所有页面,打开到应用内的某个页面 |
|
navigateBack |
关闭当前页面,返回上一页面或多级页面。 |
|
exit |
退出小程序,target="miniProgram"时生效 |
注:navigator-hover 默认为 {background-color: rgba(0, 0, 0, 0.1); opacity: 0.7;}, <navigator/> 的子节点背景色应为透明色
让我们来动动手吧
打开 pages/module/module.js , 在 data 中添加数据
// pages/module/module.js
Page({
/**
* 页面的初始数据
*/
data: {
array: [
{
name:'视图容器',
link:'/pages/module/view'
},
{
name:'基础内容',
link:'/pages/module/base'
},
{
name: '表单组件',
link: '/pages/module/form',
},
{
name:'导航',
link:'/pages/module/navigation'
},
{
name:'媒体组件',
link:'/pages/module/media'
},
{
name:'地图',
link:'/pages/module/map'
},
{
name:'画布',
link:'/pages/module/canvas'
},
{
name:'综合案例',
link:'/pages/module/demo'
}
]
},
// 此处省略以下代码
打开 module.wxml
<!--pages/module/module.wxml-->
<view class="module">
<!--
open-type:'跳转方式',
url:'当前小程序内的跳转链接'
-->
<navigator
class="cell"
wx:for="{{array}}"
wx:key="index"
open-type="navigate"
url="{{item.link}}"
>
{{item.name}}
</navigator>
</view>
再优化一下样式,因为class="cell" 我们后续会经常用到,所以打开 app.wxss
/**app.wxss**/
/** 此处省略以上代码 **/
.cell {
width: 90%;
margin: 0 auto;
height: 100rpx;
line-height: 100rpx;
text-align: center;
border-bottom: 1px solid #dddddd;
}
此时页面效果如下:
媒体组件
- image
图片。支持 JPG、PNG、SVG、WEBP、GIF 等格式,2.3.0 起支持云文件 ID。
2.10.3 版本后,微信小程序的图片即 image 组件新增了 heightFix 属性(mode),总共具有 14 种属性,满足各种情况的放置需要。14 种属性可以分为两大类,一种是完全保留的缩放属性(5 种),一种是裁剪属性(9 种)。
值得注意的是:
- image 组件默认宽度 320px、高度 240px
- image 组件中二维码/小程序码图片不支持长按识别。仅在 wx.previewImage 中支持长按识别
让我们来动动手吧
在 app.json 中创建 media 页面
注:之后的实验中,创建页面这一环节将不再重复示例
{
"pages": [
"pages/module/media"
],
打开 pages/module/media.wxml 引入一张图片(相关图片已上传至资源文件)图片地址:image-1.jpg
<!--pages/module/media.wxml-->
<view
>默认缩放属性
scaleToFill:缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image
元素
</view>
<image src="../../assets/image/image-1.jpg"></image>
<view
>保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。</view
>
<image src="../../assets/image/image-1.jpg" mode="aspectFit"></image>
<view
>保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。</view
>
<image src="../../assets/image/image-1.jpg" mode="aspectFill"></image>
<view>宽度不变,高度自动变化,保持原图宽高比不变</view>
<image src="../../assets/image/image-1.jpg" mode="widthFix"></image>
<view>高度不变,宽度自动变化,保持原图宽高比不变</view>
<image src="../../assets/image/image-1.jpg" mode="heightFix"></image>
<view>不缩放图片,只显示图片的顶部区域</view>
<image src="../../assets/image/image-1.jpg" mode="top"></image>
<view>不缩放图片,只显示图片的底部区域</view>
<image src="../../assets/image/image-1.jpg" mode="bottom"></image>
<view>不缩放图片,只显示图片的中间区域</view>
<image src="../../assets/image/image-1.jpg" mode="center"></image>
<view>不缩放图片,只显示图片的左边区域</view>
<image src="../../assets/image/image-1.jpg" mode="left"></image>
<view>不缩放图片,只显示图片的右边区域</view>
<image src="../../assets/image/image-1.jpg" mode="right"></image>
<view>不缩放图片,只显示图片的左上边区域</view>
<image src="../../assets/image/image-1.jpg" mode="top left"></image>
<view>不缩放图片,只显示图片的右上边区域</view>
<image src="../../assets/image/image-1.jpg" mode="top right"></image>
<view>不缩放图片,只显示图片的左下边区域</view>
<image src="../../assets/image/image-1.jpg" mode="bottom left"></image>
<view>不缩放图片,只显示图片的左下边区域</view>
<image src="../../assets/image/image-1.jpg" mode="bottom right"></image>
运行效果如下:
地图组件
- map
为了方便微信小程序使用地图的相关功能,微信小程序为我们提供了 map 组件,通过这个组件,我们可以很简单的引入地图,并且还可以进行个性化地图的开发
我们只需要在 wxml 中引用下面的代码,打开 pages/module/map.wxml
<!--pages/module/map.wxml-->
<!--
longitude:'中心经度'
latitude:'中心纬度'
-->
<map id="map" longitude="121.47004" latitude="31.23136"></map>
上面这个例子中,我们只是简单的为该组件传入必填的经纬度信息,当然,map 组件还包括以下常用的属性
属性 |
类型 |
说明 |
是否必填 |
longitude |
number |
中心经度 |
是 |
latitude |
number |
中心纬度 |
是 |
scale |
number |
缩放级别,取值范围为 3-20 |
否 |
markers |
Array. |
标记点 |
否 |
polyline |
Array. |
路线 |
否 |
include-points |
Array. |
缩放视野以包含所有给定的坐标点 |
否 |
enable-traffic |
boolean |
是否开启实时路况 |
否 |
bindregionchange |
eventhandle |
视野发生变化时触发 |
否 |
bindpoitap |
eventhandle |
点击地图 poi 点时触发 |
否 |
其中,longitude 和 latitude 这两个属性是必须填写的,如果没有填写,地图将无法正常显示,除了上面的属性之外,还有很多其它属性,其它属性请前往微信小程序官方文档进行查看。
画布组件
- canvas
Canvas 是由 HTML 代码配合高度和宽度属性而定义出的可绘制区域。JavaScript 代码可以访问该区域,类似于其他通用的二维 API,通过一套完整的绘图函数来动态生成图形。小程序从一开始就支持了 canvas ,但早期的 canvas 存在许多不足。因为 canvas 为原生组件,所以层级的问题一直让人十分头疼。好在目前发布了一套新的 Canvas 2D 接口,可以支持同层渲染,解决了这个”心头大患“。
探索 Canvas 2D : 从一条直线开始
打开 pages/module/canvas.wxml 引入组件
<!--pages/module/canvas.wxml-->
<!--
type:'指定 canvas 类型,支持 2d (2.9.0) 和 webgl (2.7.0)'
-->
<canvas
type="2d"
id="canvas"
style="border:10rpx solid #000; width:300rpx;height:300rpx;"
></canvas>
Canvas 标签对象本身不提供任何绘制功能,需要获取绘制上下文对象,它提供一套 API 来实现图形的绘制
打开 pages/module/canvas.js 并在 onl oad() 中添加以下代码
/**
* 生命周期函数--监听页面加载
*/
onl oad: function (options) {
let dpr = wx.getSystemInfoSync().pixelRatio; // 像素比
const query = wx.createSelectorQuery(); // 返回一个 SelectorQuery 对象实例。在自定义组件或包含自定义组件的页面中
query.select('#canvas')
.fields({
node: true,
size: true
})
.exec((res) => {
let canvasEl = res[0].node; // 获取Canvas标签节点
canvasEl.width = res[0].width * dpr; // 设置绘制区域的实际尺寸
canvasEl.height = res[0].height * dpr; // 设置绘制区域的实际尺寸
let ctx = canvasEl.getContext('2d'); // 获取绘制上下文
// 移动画笔到指定为位置(即画布上的坐标)
ctx.moveTo(100, 100);
// 移动画笔到指定为位置(即画布上的坐标),并生成一个直线轨迹
ctx.lineTo(200, 100);
// 以描边的形式绘制轨迹
ctx.stroke();
});
},
此时页面效果如图:
实验总结
本次的实验我们主要了解了视图容器,基础内容组件,表单组件,导航组件,媒体组件及画布组件中的部分常用的组件。
当然,在每次实验后,我们真诚得建议:有兴趣的同学可以对照开发文档将其他组件在业务场景中再使用几次,加深印象。
下一节实验我们将探索:小程序的 API
常用 API
实验介绍
在 2.4 组件的实验中,我们熟悉了如何利用官方提供的组件组合,快速开发页面。但页面的开发还远远不够,当我们需要使用小程序内部的功能或者获取接收外部的程序,则需要经过调用小程序的 API 来实现。
本次实验将围绕官方提供的部分常用内置 API 以及如何调用外部 API 了解微信小程序的接口。
知识点
- 什么是接口
- 调用内置 API
- 调用外部 API
什么是 API
应用程序编程接口(Application Programming Interface)也叫 API:用于提供应用程序于开发人员基于某软件或硬件得以访问一组例程的能力,而这种能力又不需要访问源码或理解内部的工作机制等细节,只需要了解如何使用即可。
小程序提供了丰富组件的同时也提供了丰富的 API 接口,让程序更加流畅,打开速度比 H5 还快,使其体验优于 Web/Web App,且接近原生 App(Native App)。
调用内置 API
在微信官方文档中【版本号:v2.18.0 (2021-06-23)】小程序的 API 共计 19 个大类,因为内容过多,本节将会挑选常用的 API 进行示例说明。
- 路由
2.4 组件小节中,我们使用 navigator 组件 进行了跳转,现在我们可以尝试使用 路由 API 进行跳转。
首先创建相关页面,本次实验配套的源码中创建了:开放接口-登录、转发、交互、调用 API 4 组页面,创建好后文件结构如下:
这里将不再赘述如何创建页面,不熟悉的同学可以回头看一下《第一个 Hello 小程序项目》有较详细的示例。 与导航组件相同,路由 API 同样也有 5 种跳转方法。
因页面都是子页面,所以可以统一使用 wx.navigateTo 进行跳转。
wx.navigateTo 的作用是保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
wx.navigateTo() 参数说明如下:
属性 |
类型 |
默认值 |
必填 |
说明 |
url |
string |
是 |
需要跳转的应用内非 tabBar 的页面的路径 (代码包路径), 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 'path?key=value&key2=value2' |
|
events |
Object |
否 |
页面间通信接口,用于监听被打开页面发送到当前页面的数据。基础库 2.7.3 开始支持。 |
|
success |
function |
否 |
接口调用成功的回调函数 |
|
fail |
function |
否 |
接口调用失败的回调函数 |
|
complete |
function |
否 |
接口调用结束的回调函数(调用成功、失败都会执行) |
打开 port.js 在 data 中新增相关数据。
/**
* 页面的初始数据
*/
data: {
array: [
{
name:'开放接口-登录',
link:'/pages/port/login'
},
{
name: '转发',
link: '/pages/port/share',
},
{
name:'交互',
link:'/pages/port/interactive'
},
{
name:'调用 API',
link:'/pages/port/request'
}
]
},
/**
*
* @param {*} e : $event
* 用于跳转页面的公共函数
*
*/
navigateTo(e){
wx.navigateTo({
url: e.currentTarget.dataset.url,
success:function(res){
console.log('页面跳转成功',res)
},
fail:function(res){
console.log('页面跳转失败',res)
}
})
},
打开 prot.wxml ,新建一个<view>创建用于点击的菜单。
<!--pages/port/port.wxml-->
<view
class="cell"
wx:for="{{array}}"
wx:key="index"
bindtap="navigateTo"
data-url="{{item.link}}"
>
{{item.name}}
</view>
此时页面展示效果如下:
细心的你们一定注意到了跳转到下一个页面的同时,页面的左上角出现了一个“<”,此时我们可以判断它存在上级页面,所以可以返回。
除了点击返回按钮进行返回,还可以使用 wx.navigateBack 来返回原页面或多级页面。
值得注意的是:wx.navigateBack 得前提是有上一级或多级页面,我们可以先使用 getCurrentPages() 来获取当前页面栈。
在 port.js 和 login.js 方法中添加以下代码,观察页面栈的变化:
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
console.log(getCurrentPages())
},
保存并编译,点击 “开放平台-登录” 按钮后观察调试器中的 Consonle
在 login 中添加以下代码,新增一个返回按钮:
<!--pages/port/login.wxml-->
<button bindtap="navigateBack">返回</button>
// pages/port/login.js
navigateBack(){
// 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
wx.navigateBack({
delta: 1, // 返回的页面数,如果 delta 大于现有页面数,则返回到首页。
})
},
保存并编译,点击 “开放平台-登录” 再点击“返回”按钮后观察调试器中的 Consonle 可以发现:页面栈堆也跟着变化了。
- 开放接口
为了帮助产品实现更多可以和微信互通的需求点,小程序团队也提供出了开放接口,目前整体开放接口包含以下 17 个大类:
此时开发者及需求者都可以根据这些开放接口进行一些功能的构思及开发,从而实现某些功能。
为了示例的连贯性,在理解开放接口的使用之前,我们可以先了解一下微信小程序中的网络及缓存的使用。
网络
在小程序中,网络被细分为以下 7 大类
其中发起请求、下载、上传被调用的最为频繁,在这里我们先简单介绍一下主要属性及注意事项,在接下来的开放接口 - 登录小节,会有实际使用示例。
- 发起请求( wx.request )
当客户端需要和服务器进行交互的时候,就需要使用wx.request()发起一个 HTTPS 网络请求,学习过 javaScript 的同学看到这里就会觉得仿佛看到了 ajax 请求。
它的主要属性有:
参数名 |
类型 |
说明 |
url |
string |
开发者服务器接口地址 |
data |
string/object/ArrayBuffer |
请求的参数 |
header |
Object |
设置请求的 header,header 中不能设置 Referer。 |
timeout |
number |
超时时间,单位为毫秒 |
method |
string |
请求方法 |
success |
function |
接口调用成功的回调函数 |
fail |
function |
接口调用失败的回调函数 |
complete |
function |
接口调用结束的回调函数(调用成功、失败都会执行) |
值得注意的是:
- 在不配置method时该属性默认为GET请求
- 默认超时时间和最大超时时间都是 60s;
- 小程序进入后台运行后,如果 5s 内网络请求没有结束,会回调错误信息 fail interrupted;在回到前台之前,网络请求接口调用都会无法调用。
- 建议服务器返回值使用 UTF-8 编码。对于非 UTF-8 编码,小程序会尝试进行转换,但是会有转换失败的可能。
- 服务器接口地址在正式环境仅支持 Https
举个例子:
wx.request({
url: "example.php", // 为示例,并非真实的接口地址
data: {
key: "", // 请求的参数
},
header: {
"content-type": "application/json", // 默认值
},
method: "POST", // 请求方法
success(res) {
console.log(res.data);
},
});
- 下载( wx.downloadFile )
下载文件资源到本地。客户端直接发起一个 HTTPS GET 请求,返回文件的本地临时路径 (本地路径),单次下载允许的最大文件为 200MB。
它的主要属性有:
参数名 |
类型 |
说明 |
url |
string |
下载资源的 url |
header |
Object |
HTTP 请求的 Header,Header 中不能设置 Referer |
timeout |
number |
超时时间,单位为毫秒 |
filePath |
string |
指定文件下载后存储的路径 (本地路径) |
success |
function |
接口调用成功的回调函数,下载成功后以 tempFilePath 的形式传给页面,res = {tempFilePath: '文件的临时路径'} |
fail |
function |
接口调用失败的回调函数 |
complete |
function |
接口调用结束的回调函数(调用成功、失败都会执行) |
值得注意的是:文件为临时路径,在小程序本次启动期间可以正常使用,如需持久保存,需再主动调用 [wx.saveFile](wx.saveFile(Object object) | 微信开放文档 (qq.com))。 在执行 wx.downloadFile 时,小程序也提供了相应的监听方法DownloadTask,便于我们监听下载进度变化事件,以及取消下载任务的对象。
举个例子:当我们想下载并持久保存地址的同时监听下载进度,我们可以这样做。
wx.downloadFile({
url: res.data[0].fileUrl, //仅为示例,并非真实的资源
success(res) {
wx.saveFile({
tempFilePath: res.tempFilePath,
success: function (res) {
const savedFilePath = res.savedFilePath;
},
fail: function (err) {
console.log("保存失败:", err);
},
});
},
});
/**
* 监听下载进度
*/
downloadTask.onProgressUpdate((res) => {
console.log("下载进度" + res.progress);
console.log("已经下载的数据长度" + res.totalBytesWritten);
console.log("预期需要下载的数据总长度" + res.totalBytesExpectedToWrite);
});
- 上传( wx.uploadFile )
将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data。
它的主要属性有:
参数名 |
类型 |
说明 |
url |
string |
开发者服务器地址 |
filePath |
string |
要上传文件资源的路径 (本地路径) |
name |
string |
文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容 |
header |
Object |
HTTP 请求 Header,Header 中不能设置 Referer |
formData |
Object |
HTTP 请求中其他额外的 form data |
timeout |
number |
超时时间,单位为毫秒 |
success |
function |
接口调用成功的回调函数 |
fail |
function |
接口调用失败的回调函数 |
complete |
function |
接口调用结束的回调函数(调用成功、失败都会执行) |
值得注意的是:当我们需要在相册选取或打开相机上传一章图片的时候,仅仅调用 wx.uploadFile 是无法满足需求的,在这里还需使用wx.chooseImage 从本地相册选择图片或使用相机拍照,将资源存储在临时文件中再进行上传。
- wx.chooseImage(从本地相册选择图片或使用相机拍照。)
参数名 |
类型 |
说明 |
count |
number |
最多可以选择的图片张数 |
sizeType |
Array. |
所选的图片的尺寸 |
sourceType |
Array. |
选择图片的来源 |
success |
function |
接口调用成功的回调函数 |
fail |
function |
接口调用失败的回调函数 |
complete |
function |
接口调用结束的回调函数(调用成功、失败都会执行) |
- 同样的,在执行 wx.uploadFile 时,也提供了相应的监听方法UploadTask,便于监听上传进度变化事件,以及取消上传任务的对象。
- 示例代码:
d. wx.chooseImage({
- e. count: 1,
- f. sizeType: ["original", "compressed"],
- g. sourceType: ["album", "camera"],
- h. success(res) {
- i. // res.tempFilePath可以作为上传的文件地址
- j. wx.uploadFile({
- k. filePath: res.tempFilePath, // 地址
- l. name: "name", // 文件名称
- m. url: "https://****/upload", // 上传服务器请求地址
- n. });
- o. },
p. });
q. /**
- r. * 监听上传进度
- s. */
t. downloadTask.onProgressUpdate((res) => {
- u. console.log("上传进度" + res.progress);
- v. console.log("已经上传的数据长度" + res.totalBytesSent);
- w. console.log("预期需要上传的数据总长度" + res.totalBytesExpectedToSend);
x. });
- 此时我们在开发者工具上进行调试,会默认打开本地资源文件。如果是手机,则会提示:打开相机或相册。
缓存
对当前微信小程序的本地缓存(Storage)进行增删改查的操作。目前本地缓存单个 key 允许存储的最大数据长度为 1MB,所有数据存储上限为 10MB。同时,本地缓存将是永久存储的,不会随着用户的退出而清除。
值得注意的是:
- 当用户手动删除小程序或清除微信缓存,小程序的本地缓存也会随之清除。
- 同步方法会堵塞当前任务,直到同步方法处理返回。
- wx.setStorage/wx.setStorageSync
将数据存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容。
主要属性有:
属性 |
类型 |
说明 |
key |
string |
本地缓存中指定的 key |
data |
any |
需要存储的内容。只支持原生类型、Date、及能够通过JSON.stringify序列化的对象。 |
当你想要存储一条数据时,你可以这样做:
wx.setStorage({
key: "name",
data: "lanqiao",
});
此时我们可以观察控制台:
当然你也可以直接这样做:
wx.setStorageSync("name", "lanqiao2");
- wx.getStorage/wx.getStorageSync
从本地缓存中异步获取指定 key 的内容。
主要属性有:
属性 |
类型 |
说明 |
key |
string |
本地缓存中指定的 key |
当你想要获取一条数据时,你可以这样做:
console.log(
wx.getStorage({
key: "name",
success(res) {
console.log(res.data);
},
})
);
此时我们可以观察控制台:
也可以直接这样做:
console.log(wx.getStorageSync("name"));
- wx.removeStorage/wx.removeStorageSync
从本地缓存中移除指定 key。
主要属性有:
属性 |
类型 |
说明 |
key |
string |
本地缓存中指定的 key |
当你想要移除一条数据时,你可以这样做:
wx.removeStorage({
key: "name",
success(res) {
console.log(res);
},
});
此时我们可以观察控制台,可以发现数据已被清除:
同样的,也可以这样做:
wx.removeStorageSync("name");
- wx.clearStorage/wx.clearStorageSync
清理本地数据缓存。无需指定参数,直接清除所有缓存。
wx.clearStorage()
此时观察控制台:
开放接口 - 登录
在了解了网络和缓存的处理后,以登录和用户信息作为示例:
小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。通俗来讲:我们只需要和微信做交互,就可以拿到当前用户的身份标识,并存储用户数据。官方也给出了完整的交互时序图供参考:
在微信生态中,身份标识为openId及unionId,两者都是一个用户只有一个且不重复的。区别是:openId的绑定关系是当前小程序和微信账号生成的唯一标识而unionId是当前小程序绑定的开放平台及微信账号生成的唯一标识。
值得注意的是:如果当前小程序没有绑定微信开放平台,则不会生成 unionId。当我们需要关联多个小程序的用户关系时,则可以使用 unionId 作为用户唯一标识的依据。
首先,我们需要在微信端中调用 wx.login()获取code,再使用wx.request()进行网络请求,在安全的角度和需要自定义登录态的角度上考虑,需要请求开发者服务器,由开发者服务器带着 AppId,appsecret,code信息请求微信接口服务登录凭证校验接口,校验通过后回传给开发者服务器session_key与openId等信息,再由开发者服务器返回给前端自定义登录态,前端存储之后登录步骤视为完成。之后的请求就可以携带存储的登录态进行业务数据的请求了。
值得注意的是:
- 如果绑定了微信开发平台,调用wx.login()后unionId会和code一起被返回。
- code 只能使用一次,使用过后需重新调用wx.login()请求 code
本次实验使用的是测试小程序账号,所以无法获取unionId,我们可以尝试在不考虑自定义登录态的情况下获取openId及session_key并存储openId
在 app.js 中输入以下代码:
// app.js
onLaunch() {
// 生命周期回调 —— 监听小程序初始化,全局只触发一次。
console.log('这里是app.js的onLaunch');
// 调用接口获取登录凭证(code)
wx.login({
success: res => {
// 正常情况下,这个请求是开发者服务器做,前端请求开发者服务器即可
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
appid: "wxeabXXXXXXXXX84d7", // AppID(小程序ID)
secret: "00deXXXXXXXXXXXXbeb8", // AppSecret(小程序密钥)
js_code: res.code,
grant_type: 'authorization_code'
},
method: 'GET',
header: {
'content-type': 'application/json'
},
success: (res) => {
console.log(res) // 请求成功后打印
wx.setStorageSync('openId', res.data.openid) // 存储openId
}
})
}
})
},
保存并编译,此时接口请求成功,并返回openId和session_key,同时Storage也存储了openId
以上是针对需要获取用户openId并记录自定义登录态的情况,假设需求只需要用户信息,则可以使用 wx.getUserProfile() 获取用户信息。
值得注意的是:这个接口只能绑定在 button上获取bindtap回调。
在 login.wxml 页面中使用button 组件。尝试调用 wx.getUserProfile 。
<!--pages/port/login.wxml-->
<image src="{{userInfo.avatarUrl}}"></image>
<text>{{userInfo.nickName}}</text>
<button type="primary" bindtap="getUserProfile">获取用户信息</button>
打开 login.js 调用方法
/**
* 页面的初始数据
*/
data: {
userInfo:{}
},
getUserProfile(){
wx.getUserProfile({
desc: '用于获取用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res)
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
此时点击按钮,页面反馈如下:
值得注意的是:使用 wx.getUserProfile() 每次请求都会弹出授权窗口,用户同意后返回数据
返回数据如下:
属性 |
类型 |
说明 |
userInfo |
Object |
用户信息对象 |
rawData |
string |
不包括敏感信息的原始数据字符串,用于计算签名 |
signature |
string |
使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息,详见 用户数据的签名验证和加解密 |
encryptedData |
string |
包括敏感数据在内的完整用户信息的加密数据,详见 用户数据的签名验证和加解密 |
iv |
string |
加密算法的初始向量,详见 用户数据的签名验证和加解密 |
cloudID |
string |
敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据,详细见云调用直接获取开放数据 |
值得注意的是:wx.getUserProfile 返回的加密数据中不包含 openId 和 unionId 字段。故 openId 和 unionId 的获取还是推荐使用 wx.login()
- 转发
打开 share.js 文件,如果是使用 app.json 新建的Page,底部默认存在事件处理函数:onShareAppMessage
监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容,在不做任何修改的情况下,点击右上角的 ’···‘ 即可分享当前页面。
share.js页面完整代码如下:
// pages/port/share.js
Page({
/**
* 页面的初始数据
*/
data: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {},
});
此时,分享页面会默认渲染当前小程序名称,当前页面 path 及默认截图。如果将它删除,页面则不可分享。
如果想要自定义参数,则需要在事件处理函数需要 return 一个 Object,用于自定义转发内容,支持已定义的返回内容如下:
字段 |
说明 |
默认值 |
title |
转发标题 |
当前小程序名称 |
path |
转发路径 |
当前页面 path ,必须是以 / 开头的完整路径。如:'pages/home/index' |
imageUrl |
自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持 PNG 及 JPG。显示图片长宽比是 5:4。 |
当前分享页面的截图 |
promise |
如果该参数存在,则以 resolve 结果为准,如果三秒内不 resolve,分享会使用上面传入的默认参数 |
如果我们需要自定义title,则需要return以下Object
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
return {
title: '蓝桥小程序基础',
}
}
此时分享窗口的名称已被改变。
- 交互
在用户进行界面操作后,系统通常需要给予用户交互反馈,我们可以利用交互 API 实现一些简单的界面交互,如下图所示:
- 消息提示框(wx.showToast 与 wx.hideToast)
o /**
o * 消息提示框
o * title:提示的内容 除icon:"none"外,最多显示7个汉字长度
o * icon:图标 支持"success"、"loading","error","none",默认success,当等于"none"时title 文本最多可显示两行
o * duration:提示的延迟时间,指窗口自动关闭的时间,当为0时,窗口不会自动关闭
o * mask: 是否显示透明蒙层,防止触摸穿透。默认为false,是个透明遮罩层,此时背景不可点击
o */
o wx.showToast({
o title: "消息提示框",
o icon: "success",
o duration: 2000,
o mask: true,
o success: function () {
o console.log("唤起成功");
o },
o fail: function () {
o console.log("唤起失败");
o },
o });
当我们把mask修改为 false,在请求成功后尝试主动关闭 Toast。
/**
* 关闭消息提示框
*/
hideToast() {
wx.hideToast({
success: (res) => {},
})
},
值得注意的是:toast 与 loading 同时只能显示一个。
- 模态提示框(wx.showModal)
显示模态对话框,这是一个不会自行关闭,包含确定及取消的模态对话框。
modal() {
/**
* 模态提示框
* title:提示的标题
* content:提示的内容
* showCancel:是否展示取消按钮
* cancelText:取消按钮的文字,最多4个字符
* cancelColor:取消按钮的颜色
* confirmText:确认按钮的文字
* confirmColor:确认按钮的颜色
* editable:是否显示输入框
* placeholderText:显示输入框时的提醒文本
*/
wx.showModal({
title: '提示',
content: '这是一个展示取消按钮展示输入框,改变了按钮文字及颜色的模态弹窗',
showCancel:true, // 默认为true
cancelText:'我是取消',
cancelColor:'blue',
confirmText:'我是确认',
confirmColor:'red',
editable:true, // 默认为false
placeholderText:'你好,蓝桥',
success(res) {
if (res.confirm) {
console.log('用户点击确定',res)
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
},
此时页面交互如下:
值得注意的是:当 editable 为 true 时,content 为文本输入框的内容。
调用 API
尽管官方为我们提供了众多的 API ,但在实际业务中需求都是“个性化的”,当小程序的 API 无法满足我们的需求时,就需要调用外部的 API 了。我们可以使用 [wx.request](RequestTask | 微信开放文档 (qq.com)) 来发起 HTTPS 网络请求。
这里使用的是聚合数据的天气预报 API 作为示例,在开始之前我们需要做一些准备工作:
- 配置 request 合法域名
- 使用注册小程序的同学可以在mp 后台 ,开发 -> 开发管理 -> 开发设置 -> 服务器域名中配置 request 合法域名。
- 使用测试号的同学则可以直接在测试号后台配置 request 合法域名。
值得注意的是:小程序的网络请求必须为HTTPS且做过服务器域名配置的域名,具体的配置方式请参考开发文档网络相关说明,本节实验我会将“详情”-》“本地设置”-》“不校验合法域名、web-view(业务域名)、 TLS 版本及 HTTPS 证书”进行勾选,便于调试。
打开 request.js ,新增网络请求:
// 获取天气
getWeather() {
let that = this
/**
* url:开发者服务器接口地址
* method:HTTP 请求方法
* data:请求的参数,支持:string/object/ArrayBuffer
* header:设置请求的 header,header 中不能设置 Referer。content-type 默认为 application/json
*
*/
wx.request({
url: 'https://apis.juhe.cn/simpleWeather/query',
method: 'GET',
data: {
city: 1,
key: key
},
header: {
'content-type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
},
success: function (res) {
console.log(res.data)
// 数据存储
that.setData({
weather: res.data.result
})
}
})
},
打开 request.wxml,渲染请求后的数据。
<!--pages/port/request.wxml-->
<view
>实时天气:
<text>{{weather.city}}</text>
<text>{{weather.realtime.info}}</text>
<text>{{weather.realtime.temperature}}℃</text>
</view>
<button bindtap="getWeather">查询天气</button>
当我们点击“查询天气”按钮,此时调试器中的 Network 应请求成功。
实验总结
本次实验我们主要通过如何调用官方 API 及如何调用外部 API 来了解小程序的接口。
我们的《微信小程序开发》到这里已经结束了。通过实验,相信你对微信小程序的开发已经有基本的了解,此时已经可以着手开发一些简单的项目了。期待你带着你的微信小程序项目与我们分享,江湖再见。
标签:index,微信,程序,开发,组件,页面,pages,wx From: https://www.cnblogs.com/zyybky9493/p/17342583.html