01微信小程序
# 微信小程序
微信小程序,小程序的一种,英文名
Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。
# 小程序平台
1、公众平台 开发文档(项目本身是小程序、发微信公众、文档、微信小游戏)
2、开放平台 开发文档(项目本身不是小程序,但是需要用到小程序的功能)
3、开放社区 社区功能类似百度贴吧(微信发布新的版本会在这里进行通知、提问问题)
# 开发者 id
appid 项目的唯一id
openid
unionid
2
3
4
5
# 开发者工具
- 一个微信官方自带的编辑器
# 小程序项目目录

pages 项目页面
utils 工具函数
app.js 项目的唯一出口,也是全局js文件
app.json app全局配置文件
app.wxss app全局样式
project.config.json 项目配置文件
sitemap.json 项目描述文件,无意义
微信页面里面的4种文件
.js 当前页的js文件
.json 当前页面的配置文件
.wxml 当前页面的html文件
.wxss 当前页面的样式文件
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 全局配置和局部配置
全局配置是整个小程序的配置,里面的属性会作用于整个小程序
局部配置(页面配置)是当前页面的小程序配置,里面的属性只会作用于当前页面
# vscode 编辑器插件
//直接搜索对应名称下载插件
minapp 微信小程序标签、属性的智能补全
wechat-snippet 微信小程序代码片段补全
wxml 微信小程序wxml格式化以及高亮组件(高度自定义)
2
3
4
5
6
# 逻辑层
// app.js
小程序关闭后并不是真正的关闭,而是进入后台,目的是方便重新打开时候的速度。进入后台大概是十几分钟后
才是真正的关闭。
App({
onLaunch (options) {
//第一次进入小程序,或者杀掉后台之后重新进入小程序,就会执行这里的代码
},
onShow (options) {
// 小程序没被杀掉之前,重新进入小程序就会执行这里的代码
},
onHide () {
// 关闭小程序执行的代码
},
onError (msg) {
//小程序报错会执行这里的代码
},
globalData: 'I am global data'//全局数据
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 生命周期
全局生命周期
onLaunch 第一次全局执行
onShow 第一次执行,或者关闭后重新打开后执行
onHide 关闭小程序,但是没完全关闭,切换到后台
onError 小程序报错
页面生命周期
onLoad 当前页面第一次加载的时候
onShow 第一次执行当前页面,或者关闭后重新打开后执行
onReady 当渲染页(视图层-wxml)加载完毕执行
onHide 关闭当前页面,但是没完全关闭,切换到后台
onUnload 销毁当前页
onPullDownRefresh 下拉刷新
onReachBottom 页面触底时执行,一般用于做上拉加载
onShareAppMessage 分享页面执行
onPageScroll 当前页面滚动执行
onResize 放大缩小页面的时候执行
onTabItemTap 点击底部导航栏触发
组件生命周期
created 创建组件时执行
attached 被插入到父组件节点时执行
ready 渲染完后执行
moved 移动组件节点
detached 从父组件节点移除时执行
error 组件方法抛出错误时执行
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 数据渲染
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {//这里写的所有数据都会直接在wxml页面渲染
msg:{
name:"小明"
},
message:"hello 微信小程序"
}
})
<!--index.wxml-->
<view class="container">
{{msg.name}}
{{message}}
</view>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 列表渲染
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
arr:["小明","小红","小丽"]
}
})
<!--index.wxml-->
//arr是渲染的数组,item是数组里面的每一个成员,index是数组的成员的索引值
<view class="container">
<view wx:for="{{arr}}">
{{item}}
{{index}}
</view>
</view>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 列表渲染别名设置
<view wx:for="{{arr}}" wx:for-item="itemName" wx:for-index="idx">
{{ itemName }}
{{ idx }}
</view>
2
3
4
# 多层列表渲染
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
arr3: [
{
countryName: "中国",
cities: [{ cityName: "广州" }, { cityName: "深圳" }, { cityName: "上海" }]
},
{
countryName: "美国",
cities: [{ cityName: "华盛顿" }, { cityName: "纽约" }, { cityName: "洛杉矶" }]
},
{
countryName: "日本",
cities: [{ cityName: "东京" }, { cityName: "北海道" }, { cityName: "名古屋" }]
}
]
}
})
<view wx:for="{{arr3}}" wx:key="idxs" wx:for-item="items" wx:for-index="idxs">
<view wx:for="{{items.cities}}" wx:key="index">
{{item.cityName}}
</view>
</view>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 条件渲染
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
bool:false
},
fn(){
this.setData({
bool:!this.data.bool
})
}
})
<!--index.wxml-->
<view class="container">
首页
<view wx:if="{{bool}}">
内容
</view>
<button bind:tap="fn">
按钮
</button>
</view>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 事件绑定
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
},
fn(){
console.log(123)
}
})
<!--index.wxml-->
<view class="container">
<view bind:tap="fn">
内容
</view>
</view>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 事件对象
currentTarget绑定该事件的元素
target触发事件的元素
//案例中 currentTarget是container。target是test。
<view class="container" bind:tap="fn">
<view class="test" data-msg="{{msg}}">
{{msg}}
</view>
</view>
//案例中 currentTarget是test。target是test。
<view class="container">
<view bind:tap="fn" class="test" data-msg="{{msg}}">
{{msg}}
</view>
</view>
2
3
4
5
6
7
8
9
10
11
12
# 路由跳转方式
1、
wx.navigateTo打开新页面(不能打开 tab 页)
<navigator open-type="navigateTo" url="/pages/test/test">
跳转到测试页
</navigator>
2
3
2、
wx.switchTab Tab切换(只能打开 tab 页)
<navigator open-type="switchTab" url="/pages/logs/logs">
跳转到日志页
</navigator>
2
3
3、
wx.redirectTo页面重定向(没有历史记录,不能执行返回上一页这种操作)
4、
wx.navigateBack返回上一页
// pages/test/test.js
Page({
goBack() {
wx.navigateBack();
},
});
2
3
4
5
6
# 路由传参
# 非 tab 页传参数
// index.js
// 获取应用实例
const app = getApp();
Page({
go() {
let id = 2;
wx.navigateTo({
url: `/pages/index2/index2?id=${id}`,
success: (result) => {},
});
},
});
// pages/index2/index2.js
Page({
onLoad: function (options) {
console.log(options);
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# tab 页传参数
1、使用全局变量传数据
// index.js
// 获取应用实例
const app = getApp();
Page({
go() {
let id = 1;
app.globalData.id = id;
wx.switchTab({
url: "/pages/index3/index3",
});
},
});
// pages/index3/index3.js
const app = getApp();
Page({
onLoad: function () {
console.log(app.globalData.id);
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2、使用
storage存数据
// index.js
// 获取应用实例
const app = getApp();
Page({
go() {
wx.setStorageSync("id", 1);
wx.switchTab({
url: "/pages/index3/index3?id",
});
},
});
// pages/index3/index3.js
const app = getApp();
Page({
onLoad: function () {
console.log(wx.getStorageSync("id"));
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 模块化
最新版的小程序可以使用
es6语法微信小程序采用的是
node.js的语法(commonjs规范)补充知识点:
js的模块化有 4 个(commonjs\es6\amd\cmd)
// index.js
// 获取应用实例
const app = getApp();
const test = require("../../utils/test.js");
Page({
data: {},
fn(e) {},
onShow() {
test.fn();
test.fn2();
},
});
//test.js
let fn = function () {
console.log("测试");
};
let fn2 = function () {
console.log("测试2");
};
// module.exports.fn = fn
// module.exports.fn2 = fn2
// 上面的代码等价于下面这段代码
// {
// fn:function(){},
// fn2:function(){}
// }
// 简写
module.exports = {
fn,
fn2,
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 另外一种模块化
// index.js
// 获取应用实例
const app = getApp();
const test = require("../../utils/test.js");
// 上面代码的test等价于
// {fn:function(){},fn2:function(){}}
// 所以可以使用es6的结构赋值
const { fn, fn2 } = require("../../utils/test.js");
Page({
data: {},
fn(e) {},
onShow() {
fn();
fn2();
},
});
//test.js
exports.fn = function () {
console.log("测试");
};
exports.fn2 = function () {
console.log("测试2");
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 全局属性和全局方法
// app.js
App({
globalData: {
message: "hello world", //全局属性
fn: function () {
//全局方法
console.log("hi");
},
},
});
// index.js
// 获取应用实例
const app = getApp();
Page({
onShow() {
console.log(app.globalData.message);
app.globalData.fn();
console.log(app); //小程序实例
console.log(this); //打印的是当前页面对象,不是小程序实例
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
注意:在页面打印的
this不是小程序实例,所以不要使用跟vue一样的this.xxx获取全局属性和方法。
# 小程序的 promise 事件与 h5 的区别
//事件轮询机制(事件循环机制)
new Promise() 宏事件
.then() 微事件
function fn(){
return new Promise((resolve,reject)=>{
resolve()
})
}
fn().then(()=>{
})
//在小程序里面,.then()属于宏事件
//async await一样
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 小程序提供的 api 能力
所有的小程序
api都是调用wx.xxx的形式进行调用
# 本地存储
// 同步
wx.setStorageSync("msg", "hello");
console.log(wx.getStorageSync("msg"));
// 异步
wx.setStorage({
key: "msg2",
data: "hi",
success: (result) => {
console.log(1);
},
fail: () => {},
complete: () => {
console.log(2);
},
});
wx.getStorage({
key: "msg2",
success: (result) => {
console.log(result.data);
},
fail: () => {},
complete: () => {
console.log(123);
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 请求接口
wx.request({
url: "<http://vt.ossjk.com/goods/getIndexInfo>",
header: { "content-type": "application/json" },
method: "GET",
success: (result) => {
console.log(result);
},
fail: () => {},
complete: () => {},
});
2
3
4
5
6
7
8
9
10
# 请求报文
请求报文
请求行 general:Request URL 请求地址、Request Method 请求类型、Status Code状态码
1xx 请求中
2xx 发送成功
3xx 重定向
4xx 请求错误(前端错误)
404 地址错
5xx 服务端错误(也有可能是前端发送的数据错)
请求头
content-type 发送的请求文本类型
application/json JSON类型数据
application/x-www-form-urlencoded 表单类型数据
token 令牌-识别登录用户的状态
请求体
发送的数据,如果是post会在这里直接显示,如果是get会在地址栏显示。
响应报文
响应行
响应头
响应体 返回给前端的数据
http的缺陷,无法识别状态
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 接口-回调函数写法
wx.request({
url: "<http://vt.ossjk.com/goods/getDetailGoodsInfo>",
header: { "content-type": "application/json" },
data: {
goodsId: result.data.data.slides[0].goodsId,
},
method: "POST",
success: (result) => {
console.log(result);
},
fail: () => {},
complete: () => {},
});
2
3
4
5
6
7
8
9
10
11
12
13
# 接口-promise 写法
# 接口-async await 写法
# 组件
可以复用的功能模块。
原生组件,小程序自带的组件。
第三方组件库ui,elment\ant-dsign\vant
# 创建自定义组件
创建一个
button目录,在里面再创建一个component组件

//button.wxml
<button>测试按钮</button>
2
在使用的页面的 json 文件引入

//index.json
{
"usingComponents": {
"mybutton":"../../components/button/button"
}
}
<!--index.wxml-->
<view class="container">
<mybutton></mybutton>
</view>
2
3
4
5
6
7
8
9
10
# 插槽
<!--index.wxml-->
<view class="container">
<mybutton>哈哈</mybutton>
<mybutton>呵呵</mybutton>
<mybutton>嘿嘿</mybutton>
</view>
<button>
<slot></slot>
</button>
2
3
4
5
6
7
8
9
多个插槽
<!--index.wxml-->
<view class="container">
<mybutton>
<view slot="a">
李大爷
</view>
<view slot="b">
李大妈
</view>
</mybutton>
</view>
//button.wxml
<button>
<slot name="a"></slot>
内容
<slot name="b"></slot>
</button>
// components/button/button.js
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 样式隔离
默认情况下,父组件的样式无法更改子组件的样式,除非设置
styleIsolation属性。
Component({
options: {
styleIsolation: "isolated",
},
});
2
3
4
5
isolated默认属性,父组件无法影响到子组件apply-shared父组件可以影响到子组件shared父子组件可以互相影响
# 组件的 data 属性
组件的
data属性和page的data属性一模一样,但是新版的微信小程序的方法建议写在methods里面
// components/button/button.js
Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {
msg: "hello 组件",
},
/**
* 组件的方法列表
*/
methods: {
fn() {
this.setData({
msg: "hi 组件",
});
},
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 组件之间的数据传递
# 父传子
<!--index.wxml-->
<view class="container">
<mybutton a="李大爷" b="李大妈"></mybutton>
</view>
<button bind:tap="fn">
{{msg}}
{{a}}
{{b}}
</button>
// components/button/button.js
Component({
/**
* 组件的属性列表
*/
properties: {
a:String,//props校验-检查props类型
b:String
},
/**
* 组件的初始数据
*/
data: {
msg:"hello 组件"
},
/**
* 组件的方法列表
*/
methods: {
fn(){
console.log(this.data.msg)
console.log(this.properties.a)//等价于下面
console.log(this.data.a)
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 子传父
流程:
1、子组件button点击,触发fn函数
2、子组件fn函数触发triggerEvent
3、triggerEvent添加了一个childevent事件,并且带上参数,通过事件冒泡传给父组件index
4、父组件绑定childevent事件,触发自己的fathterfn函数。bind:childevent="fathterfn"
5、父组件的fathterfn获取到e.detail数据
2
3
4
5
button组件
//button.wxml
<button bind:tap="childfn">按钮</button>;
// components/button/button.js
Component({
data: {
msg: "子组件的数据",
},
methods: {
childfn() {
//通过triggerEvent提交一个childevent事件,让父组件可以直接使用childevent事件
this.triggerEvent("childevent", this.data.msg);
},
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
index页面
//index.wxml
//父组件通过子组件提交上来的childevent事件触发自己的方法,以此接收子组件提交的数据
<view class="container">
<mybutton class="btn" bind:childevent="fathterfn"></mybutton>
</view>;
// index.js
// 获取应用实例
const app = getApp();
Page({
fathterfn(e) {
console.log(e.detail);
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
# 非父子
eventBus js订阅发布模式
//utils/eventBus.js
class EventBus {
constructor() {
//构造器
this.list = []; //存书的地方
}
$on(eventName, fn) {
//订阅器-给订阅者(小明)记录他需要订阅的书籍以及他本人的信息
if (eventName) {
this.list.push({ eventName: eventName, eventHandler: fn });
}
}
$emit(eventName, data) {
//发布器-给订阅者(小明)发布他所订阅的书籍
if (eventName) {
this.list.forEach((item) => {
if (item.eventName === eventName) {
item.eventHandler(data);
}
});
}
}
$off(eventName) {
//取消发布
if (this.list.length) {
this.list.forEach((item, idx) => {
if (item.eventName === eventName) {
this.list.splice(idx, 1);
}
});
}
}
}
module.exports = new EventBus();
// components/acom/acom.js
const eventBus = require("../../utils/eventBus.js");
Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {
msg: "a组件的数据",
},
/**
* 组件的方法列表
*/
methods: {
fn() {
eventBus.$emit("aevent", this.data.msg); //发布b组件订阅的数据
},
},
});
// components/bcom/bcom.js
const eventBus = require("../../utils/eventBus.js");
Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {},
/**
* 组件的方法列表
*/
methods: {},
lifetimes: {
attached() {
eventBus.$on("aevent", (res) => {
//b组件订阅aevent事件
console.log(res);
});
eventBus.$off("aevent"); //取消订阅
},
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 获取子组件实例
// index.js
// 获取应用实例
const app = getApp();
Page({
data: {},
fn() {
let acom = this.selectComponent(".acom"); //通过选择器获取子组件的实例
acom.fn();
},
});
2
3
4
5
6
7
8
9
10
11
# 组件内数据监听
// components/acom/acom.js
Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {
num: 1,
num2: 2,
num3: 3,
},
/**
* 组件的方法列表
*/
methods: {
fn() {
this.setData({
num: 2,
});
},
},
observers: {
num: function (val) {
console.log(val);
},
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# vant-ui 安装步骤
1、通过npm安装vant
npm i @vant/weapp -S --production
2、修改 app.json
将
app.json中的"style": "v2"去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。
3、修改 project.config.json
{
...
"setting": {
...
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
4、构建npm包
打开微信开发者工具,点击 工具
->构建npm,并勾选 使用npm模块 选项,构建完成后,即可引入组件。

5、使用
// 通过 npm 安装
// app.json
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
2
3
4
5
在任意地方使用组件
<van-button type="primary">按钮</van-button>
# 小程序登录、用户和信息相关接口最新修改
1、(修改了获取unionId方式)
如果已经在微信开放平台进行绑定,
可以直接通过wx.login获取的登录凭证,
拿到unionID
旧版:
wx.login获取code
后端接口获取openid和sessionKey
微信接口获取敏感信息
调用后端获取敏感信息(unionID)
新版:
wx.login获取code
传code给后端接口,返回openid、sessionKey、unionID
2、wx.getUserInfo和
<button open-type="getUserInfo"/>
获取的是匿名数据
3、高版本7.0.9新增getUserProfile接口,
可获取用户头像、昵称、性别及地区信息,
每次用这个接口都需要用户确认,
老版本还是可以使用getUserInfo
4、wx.getUserProfile()接口可以直接获取用户信息,
每次用户授权,不需要再自己写授权
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26