【笔记】微信小程序学习笔记

前言

微信小程序,小程序的一种,英文名Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。(百度百科

注册

开发者工具

初始化项目

下载脚手架

1
npm install -g @wechat-miniprogram/miniprogram-cli

初始化项目

1
2
3
4
mkdir demo
cd demo

miniprogram init

构建项目

下载依赖

1
npm install -g gulp

构建项目

1
gulp
  • 构建完成后会在项目根目录生成miniprogram_dist目录

页面

目录结构

1
2
3
4
5
6
+ pages
+ page
- page.wxml
- page.wxss
- page.js
- page.json

组件

内置组件

容器组件

1
<view></view>

区块组件

  • 类似于Vue的<template></template>组件
1
<block></block>

文本组件

1
<text></text>

图片组件

  • 默认尺寸:320px*240px

src="":图片路径,小程序发布不允许超过2M,所以不建议图片本地化,最好使用URL
mode="":图片裁剪缩放模式

scaleToFill:填充
aspectFit:等比例缩放,同时保证长边完全显示,超出部分进行截取(谁先缩放到设定的值,谁就是长边)
aspectFill:等比例缩放,同时保证短边完全显示,超出部分进行截取(谁后缩放到设定的值,谁就是短边)
widthFix:等比例缩放,在保证不超出宽度的同时,高度自动变化
heightFix:等比例缩放,在保证不超出高度的同时,宽度自动变化

1
<image src="" />

按钮组件

  • 默认带阴影

size="":按钮尺寸

default:缺省值,默认尺寸
mini:小尺寸

type="":按钮类型

default:缺省值,白色
primarg:绿色
warn:红色

disabled="false":按钮是否禁用
form=type="":触发表单事件

submit:提交表单
reset:重置表单

open-type="":微信开放能力

contact:打开客服对话
share:触发转发功能,不能转发朋友圈
getPhoneNumber:获取用户手机号(回调函数获取)
getUserInfo:获取用户信息(回调函数获取)
openSetting:打开授权设置页(只能管理已询问的授权)
feedback:打开意见反馈

1
<button></button>
获取用户手机号
  • 只有企业开发者才能使用
  • 需要在回调函数getPhoneNumber()中获取
1
<button open-type="getPhoneNumber"></button>
1
2
3
4
5
Page({
getPhoneNumber: function (event) {
console.log(event);
}
});

输入框组件

1
<input type="text" />
双向绑定
1
<input type="text" model:value="{{ key }}" />
1
2
3
4
5
Page({
data: {
key: "value"
}
});

单选框组件

1
2
3
<redio-group bind:change="">
<redio/>
</redio-group>

多选框组件

1
2
3
<checkbox-group bind:change="">
<checkbox></checkbox>
</checkbox-group>

轮播图组件

1
2
3
4
5
6
7
8
9
<swiper bind:change="">
<swiper-item>
<image></image>
</swiper-item>

<swiper-item>
<image></image>
</swiper-item>
</swiper>

自定义模版

  • 旧版微信小程序没有自定义组件,组件化开发时只能使用自定义模板,新版微信小程序有自定义组件,组件化开发时可以使用自定义组件,自定义模板不再被需要

定义自定义模版

name="":定义模版时指定的名字

pages/page/page.wxml
1
2
3
<template name="">
...
</template>

使用自定义模版

is="":调用模版,指定对应的模版名。也可以通过三目运算,判定使用哪个模版
data="":指定需要传入的数据

pages/page/page.wxml
1
2
3
<template is="" data="">
...
</template>
pages/page/page.wxml
1
<template is="" data="" />

自定义组件

目录结构

1
2
3
4
5
6
+ components
+ component
- component.wxml
- component.wxss
- component.js
- component.json

定义自定义组件

  • 自定义组件命名不能以wx-作为前缀

component:定义是否是组件

true:组件

usingComponents:定义依赖的其他组件

compomemts/compomemt/component.json
1
2
3
4
{
"component": true,
"usingComponents": {}
}
compomemts/compomemt/component.js
1
2
3
4
5
Component({
properties: {}, // 组件的属性列表
data: {}, // 组件的初始数据
methods: {} // 组件的方法列表
});

使用自定义组件

pages/page/page.json
1
2
3
4
5
{
"usingComponents": {
"component": "../components/component/component"
}
}
pages/page/page.wxml
1
<component></component>
pages/page/page.wxml
1
<component />

组件样式隔离

styleIsolation:定义样式隔离

isolation:使用class定义的样式,页面与组件样式不会相互影响
apply-shared:使用class定义的样式,页面样式会影响组件样式
shared:使用class定义的样式,页面与组件样式会相互影响

compomemts/compomemt/component.js
1
2
3
4
5
Component({
options: {
styleIsolation: "isolation"
}
});

父子组件数据传递

父页面传递数据给子组件

  1. 子组件接收父组件可能传递的数据
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Component({
properties: {
key: {
type: String,
value: "default"
},
key2: {
type: Number
},
key3: {
type: Boolean
},
key4: {
type: Object
},
key5: {
type: Array
},
key6: {
type: null // 不限制数据类型
}
}
});
compomemts/son/son.wxml
1
<view>{{ key }}</view>
  1. 父组件引入子组件时传递数据
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.wxml
1
<son key="value" />

父页面传递样式给子组件

  • 父页面传递class给子组件,并在父页面定义对应class的样式
  1. 子组件接收父组件可能传递的类名
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.js
1
2
3
Component({
externalClasses: ["k"]
});
compomemts/son/son.wxml
1
<view class="k"></view>
  1. 父组件引入子组件时传递类名,并在父组件中定义样式
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.wxml
1
<son k="v" />
pages/father/father.wxss
1
2
3
.v {
color: red;
}

子组件传递事件给父页面

  1. 子组件发送事件给父组件
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.js
1
2
3
4
5
6
7
Component({
methods: {
fn: function () {
this.triggerEvent("sonFn", "value");
}
}
});
compomemts/son/son.wxml
1
<view bind:tap="fn"></view>
  1. 父组件监听子组件发送的事件
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.js
1
2
3
4
5
Page({
onSonFn: function (event) {
console.log(event.detail); // "value"
}
});
pages/father/father.wxml
1
<son bind:sonFn="onSonFn" />

父页面直接调用子组件的函数

  1. 子组件定义函数
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.js
1
2
3
4
5
6
7
Component({
methods: {
sonFn: function () {
...
}
}
});
  1. 父组件引入子组件,并通过选择器得到子组件对象,然后通过子组件对象调用子组件定义的函数
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.js
1
2
3
4
5
6
Page({
fn: function () {
const son = this.selectComponent(".son");
son.sonFn();
}
});
pages/father/father.wxml
1
<son bind:tap="fn" />

插槽

  1. 子组件预留插槽插入位置
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.wxml
1
2
3
4
<view>
<!-- 预留插槽插入位置 -->
<slot></slot>
</view>
  1. 父组件引入子组件时向插槽插入元素
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.wxml
1
2
3
4
<son>
<!-- 引入子组件时向指定名称的插槽插入元素 -->
<view></view>
</son>

多插槽

  1. 子组件启用多插槽,并预留多个插槽位置,通过name属性区分
compomemts/son/son.json
1
2
3
{
"component": true
}
compomemts/son/son.wxml
1
2
3
4
5
<view>
<!-- 预留多个插槽插入位置 -->
<slot name="slotName1"></slot>
<slot name="slotName2"></slot>
</view>
  1. 父组件引入子组件时向指定名称的插槽插入元素
pages/father/father.json
1
2
3
4
5
{
"usingComponents": {
"son": "../components/son/son"
}
}
pages/father/father.wxml
1
2
3
4
5
<son>
<!-- 引入子组件时向指定名称的插槽插入元素 -->
<view solt="slotName1"></view>
<view solt="slotName2"></view>
</son>

混入

定义被混入的对象

behaviors/main.js
1
2
3
4
5
6
7
8
9
10
export const main = {
data: {
key: "value"
},
methods: {
fn: function () {
console.log(this.data.key);
}
}
}

在其他组件中混入对象

components/component/component.js
1
2
3
4
5
import { main } from "../../behaviors/main"

Component({
behaviors: [main],
});

生命周期

组件的生命周期函数

  • 组件的生命周期函数全部需要在lefetimes属性中定义
components/component/component.js
1
2
3
4
5
6
7
8
9
Component({
lefetimes: {
created: function () {},
attached: function () {},
ready: function () {},
moved: function () {},
detached: function () {}
}
});

组件所在的页面的生命周期函数

components/component/component.js
1
2
3
4
5
6
Component({
pageLifetimes: {
show: function () {},
hide: function () {}
}
});

JSON

全局配置和页面配置

全局配置

pages:页面路由,第一行默认为首页

app.json
1
2
3
4
5
6
7
8
{
"pages": [
"pages/index/index",
"pages/logs/logs"
],
"style": "v2",
"sitemapLocation": "sitemap.json"
}

页面配置

pages/page/page.json
1
{}

WXML

内置指令

wx:if

  • 不符合条件时,组件不会渲染
1
2
3
<view wx:if="{{ 布尔表达式 }}"></view>
<view wx:elif="{{ 布尔表达式 }}"></view>
<view wx:else></view>

hidden

  • 不论是否符合条件,组件都会渲染
  • 不符合条件时,组件会被设置为`style=”display: none;”
1
<view hidden="{{ true }}"></view>
  • 简写

所有指令的缺省值都为true

1
<view hidden></view>

wx:for

  • wx:for指令通常在<block></block>组件中使用

wx:for-index="index":定义当前遍历的索引,缺省值为index
wx:for-item="item":定义当前遍历的元素,缺省值为item
wx:key="":定义当前遍历的元素的唯一标识符,用于加速渲染

*this:指代当前遍历的对象

1
2
3
<block wx:for="{{ 可迭代对象 }}" wx:key="*this">
{{ index }} {{ item }}
</block>
遍历数字
  • 表示遍历范围为[0,)的有序序列
1
2
3
<block wx:for="{{ 10 }}" wx:key="*this">
{{ index }} {{ item }}
</block>
遍历字符串
  • 表示遍历字符串中每个字符
1
2
3
<block wx:for="文本内容" wx:key="*this">
{{ index }} {{ item }}
</block>

WXSS

单位

  • rpx是微信小程序特有的尺寸单位,1rpx表示在屏幕为iPhone6(750px * 375px)的环境下的1px,当屏幕不为iPhone6时1rpx实际显示尺寸会跟随屏幕尺寸的改变而改变

JS

  • 用于定义回调函数,回调函数由微信小程序引擎调用,不能直接在视图层调用

全局对象和页面对象

  • 页面的生命周期函数直接定义在对象的根节点中

全局对象

app.js
1
2
3
4
5
6
7
8
9
10
App({
// 定义自定义数据
data: {},
// 定义自定义函数
fn: function () {},
// 定义生命周期函数
onLaunch: function (options) {},
onShow: function (options) {},
onHide: function () {},
});

页面对象

pages/page/page.js
1
2
3
4
5
6
7
8
Page({
// 定义页面数据
data: {},
// 定义自定义函数
fn: function () {},
// 定义生命周期函数
onLoad: function () {},
});
在页面对象中获取全局对象定义的数据
app.js
1
2
3
4
5
App({
globalData: {
key: "value"
},
});
pages/page/page.js
1
2
3
4
5
6
7
Page({
onLoad: function () {
// 获取全局对象
const app = getApp();
console.log(app.globalData.key); // "value"
},
});

WXS

  • WXS用于定义可以在视图层中直接调用的函数

    • WXS中必须通过module=""定义模块名
    • WXS中必须通过CommonJS语法将函数导出才可以在WXML中使用
    • 在WXML中通过模块名.函数名的方式调用WXS中定义的函数
    • WXS中不能使用ES6语法
    • WXS中不能调用其他JS文件定义的回调函数
    • WXS中不能调用微信小程序内置API
  • 官方文档

通过内联标签引入WXS

1
2
3
4
5
6
7
8
9
10
11
<wxs module="utils">
function sum(a, b) {
return a + b;
}

module.exports = {
sum: sum
}
</wxs>

<view> {{ utils.sum(1, 2) }} </view>

通过外部文件引入WXS

utils/utils.wxs
1
2
3
4
5
6
7
function sum(a, b) {
return a + b;
}

module.exports = {
sum: sum
}
1
2
3
<wxs module="utils" src="/utils/utils.wxs"></wxs>

<view>{{ utils.sum(1, 2) }}</view>

响应式数据

1
2
3
4
5
6
7
8
9
10
11
12
Page({
data: {
key: "value" // 定义数据
},
fn: function () {
// 获取数据
console.log(this.data.key);

// 修改数据
this.setData({ key: "" });
}
});
pages/page/page.wxml
1
2
<!-- 渲染数据 -->
<view>{{ key }}</view>

事件

事件名 备注
tap 点击事件

在JS中定义回调函数

1
2
3
4
5
Page({
fn: function (event) {
console.log(event);
}
});

在WXML中指定事件的回调函数

在捕获阶段执行回调函数

允许冒泡
1
<view capture-bind:tap="fn"></view>
阻止冒泡
1
<view capture-catch:tap="fn"></view>

在冒泡阶段执行回调函数

允许冒泡
1
<view bind:tap="fn"></view>
  • 简写,省略:
1
<view bindtap="fn"></view>
阻止冒泡
1
<view bind:catch="fn"></view>
  • 简写,省略:
1
<view bindcatch="fn"></view>

事件的参数传递

通过dataset传递参数

  • 当前事件回调函数只能拿到当前组件的dataset参数
在WXML中定义参数
  • 通过data-作为前缀的指令可以定义自定义参数
1
<view bind:tap="fn" data-key="value"></view>
在JS中接收参数
1
2
3
4
5
Page({
fn: function (event) {
console.log(event.currentTarget.dataset.key); // "value"
}
});

通过mark传递参数

  • 当前事件回调函数可以拿到当前页面所有组件的mark参数
在WXML中定义参数
  • 通过mark:作为前缀的指令可以定义自定义参数
1
<view bind:tap="fn" mark:key="value"></view>
在JS中接收参数
1
2
3
4
5
Page({
fn: function (event) {
console.log(event.mark.key); // "value"
}
});

微信小程序内置API

弹窗

1
2
3
4
wx.showToast({
title: "标题",
icon: "loading",
});
1
2
3
wx.showLoading({
title: "标题",
});
1
2
3
4
5
6
7
8
9
10
11
12
wx.showModal({
title: "标题",
content: "描述",
success: function (res) {
if (res.confirm) {
console.log("用户点击确定");
}
if (res.cancel) {
console.log("用户点击取消");
}
}
});
1
2
3
wx.showActionSheet({
itemList: [],
});

分享

1
2
3
4
5
6
7
8
9
Page({
onShareAppMessage: function () {
return {
title: "标题",
path: "/pages/page/page",
imageUrl: "/assets/logo.png",
}
}
});

获取用户信息

1
2
3
4
5
wx.getSystemInfo({
success: function (res) {
console.log(res);
}
});

获取当前位置信息

app.json
1
2
3
4
5
6
7
{
"permission": {
"scope.userLocation": {
"desc": "请求授权位置信息"
}
}
}
1
2
3
4
5
wx.getLocation({
success: function (res) {
console.log(res);
}
});

缓存

同步缓存

添加缓存
1
wx.setStorageSync("key", "value");
  • 微信小程序的缓存可以直接存储JS对象,而无需序列化
1
wx.setStorageSync("obj", {});
获取缓存
1
const value = wx.getStorageSync("key");
删除缓存
1
wx.removeStorageSync("key");
清空缓存
1
wx.clearStorageSync();

异步缓存

添加缓存

encrtpt:是否加密

false:缺省值,不加密
true:加密

1
2
3
4
5
6
7
8
wx.setStorage({
key: "key",
data: "value",
encrtpt: false,
success: function (res) {
console.log(res);
}
});
获取缓存
1
2
3
4
5
6
7
wx.getStorage({
key: "key",
encrtpt: false,
success: function (res) {
console.log(res);
}
});

请求

1
2
3
4
5
6
wx.request({
url: "<url>",
success: function (res) {
const body = res.data;
}
});

获取用户信息

1
2
3
4
5
6
wx.getUserProfile({
desc: "文本内容",
success: function (res) {
console.log(res);
}
});

获取媒体文件

1
2
3
4
5
6
wx.choseMedia({
mediaType: ["image", "video"],
success: function (res) {
console.log(res.tempFiles[0].tempFilePath);
}
});

登录

1
2
3
4
5
wx.login({
success: function (res) {
console.log(res.code); // 获取code
}
});

路由

WXML

open-type="":页面跳转方式

exit:关闭小程序
navigateTo:打开新页面。只可以跳转非tabBar页面(新页面进栈)
navigateBack:返回上一页。(将当前页面移出页面栈)
switchTab:打开新页面。只可以跳转tabBar页面(将所有页面移出页面栈,新页面进页面栈)
reLaunch:打开新页面。可以跳转任意页面(将所有页面移出页面栈,新页面进页面栈)
rediirect:页面重定向。(当前页面出栈,新页面进栈)

url="":跳转页面的路径,只能是相对路径
name="":携带自定义参数,可以在onLoad()通过options属性调用

pages/page/page.wxml
1
<navigator open-type="navigateTo" url="/pages/logs/logs?key=value"></navigator>

JS

获取所有路由

1
const pages = getCurrenPages();

页面导航

  • 保留当前页面,跳转到新页面
1
2
3
wx.navigateTo({
url: "/pages/page/page",
});
传递参数
pages/page/page.js
1
2
3
4
5
6
7
Page({
fn: function () {
wx.navigateTo({
url: "/pages/logs/logs?key=value",
});
}
});
pages/logs/logs.js
1
2
3
4
5
Page({
onLoad: function (options) {
console.log(options.key);
}
});

页面返回

delta:返回层级,缺省值为1

1
2
3
wx.navigateBack({
delta: 1
});
传递参数
直接为上一页设置数据
  • 手动获取上一页对象,向上一页对象中设置数据
pages/logs/logs.js
1
2
3
4
5
6
7
Page({
onUnload: function () {
const pages = getCurrenPages();
const prevPage = pages[pages.length - 2];
prevPage.setData({ key: "value" });
}
});
在前一页定义回调函数
  • 在前一页定义回调函数
pages/page/page.js
1
2
3
4
5
6
7
8
9
10
11
12
Page({
fn: function () {
wx.navigateTo({
url: "/pages/logs/logs",
events: {
callBack: function (data) {
console.log(data);
}
}
});
}
});
  • 在后一页调用回调函数
pages/logs/logs.js
1
2
3
4
5
6
7
Page({
onUnload: function () {
const eventChannel = this.getOpenerEventChannel();
const data = { key: "value" };
eventChannel.emit("callBack", data);
}
});

完成

参考文献

哔哩哔哩——Python小清风
哔哩哔哩——黑马程序员