微信小程序入门

小程序的文件结构

app.js: 设置一些项目的全局变量

app.json: 每一个新页面都必须在这个页面注册

app.wxss: 项目全局样式

project.config.json: 项目配置文件

一个页面主要是包含以下四个文件,这四个文件的名字应该都是一样的,最好以页面所在的文件夹名字为标准:

xxx.wxml: 页面结构

xxx.wxss: 页面样式

xxx.json: 页面配置文件

xxx.js: 页面脚本文件

通过新建目录,新建 component.可以快速建立上述同名称文件.

页面可以嵌套,但不能超过 5 个层级.

app.jsontabBar可以设置导航栏颜色背景,下属的list中可以设置下标按钮的信息.

设备分辨率和 RPX

pt: 视觉单位.与屏幕的物理尺寸有关系,也叫做逻辑分辨率,与移动端的栅格渲染有关.

px: 像素点,物理分辨率.随着屏幕变化不会变化.一般设计稿以 px 为单位.iphone6 的分辨率是 375,设计稿一般是 750,那么

rpx : px = 2:1.

rpx 是响应式像素,可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx.

当需要的元素大小适应屏幕尺寸,就选择 rpx 作为单位,否则使用 px 作为单位。

小程序的事件

冒泡事件: 当一个组件上的事件被触发,该事件会向父节点传递.

非冒泡事件: 与之相反,不向父节点传递.

事件绑定

key 以 bind 或者 catch 开头,然后跟上事件的类型,如bindtap,catchtouchstart.

value 是一个字符串,需要在对应的 page 中定义同名的函数,不然当触发时会报错.

区别: bind 事件绑定不会阻止冒泡事件向上冒泡,catch 事件绑定可以阻止.

下拉刷新

监听用户下拉刷新事件

  1. 在 app.json 的 window 选项或者页面配置中开启enablePullDownRefresh.
  2. 可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画.
  3. 当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新.

小程序更新数据的值

函数用于将数据从逻辑层更新到视图层(异步)

1
this.setData(object data, function callback)

data: 传一个 object,是这次要改变的数据

callback: 传一个 function,是 setData 引起页面更新渲染完毕后的回调函数

//赋值的方式

1
this.setData({ arr: this.data.arr });

小程序中 push 方法基本失效.

改变 object 中的值

1
this.setData({ "obj.text": "message2" });

小程序的路由方式

打开新页面: wx.navigateTo 或使用组件<navigator open-type="navigateTo" />

页面重定向: wx.redirectTo 或使用组件<navigator open-type="redirectTo"/>

压面返回: wx.navigateBack 或使用组件<navigator open-type="navigateBack"/>

Tab 切换: wx.switchTab或使用组件<navigator open-type="switchTab"/>

重启动: wx.reLauch或使用组件<navigator open-type="reLauch"/>

小程序请求接口方式

HTTPS 请求: wx.request

上传文件: wx.uploadFile

下载文件: wx.downloadFile

webSocket 通信: wx.connectSocket

小程序的生命周期

onLoad: 页面加载时触发.一个页面只会调用一次.可以在onLoad的参数中获取打开当前页面路径中的参数

onShow: 页面显示/切入前台时触发

onReady: 页面初次渲染时触发.一个页面只调用一次.

onHide: 页面隐藏/切入后台时触发.如navigateTo或底部 tab 切换到其他页面,小程序切入后台.

onUnload: 页面卸载时触发.如navigateTonavigateBack时触发.

组件通信

父传子: properties

子传父: triggerEvent('自定义事件名', {})

AppID(小程序 ID)

也是开发者 ID,路径:

微信公众平台-小程序-开发-开发设置

标签

微信小程序采用自有的标签,但是基本和 h5 标签有对应

小程序标签 h5 标签
view div
text span
scroll-view 可以滚动的 div

数据绑定

数据绑定采用双大括号语法.

1
<view>{{ message }}</view>

数据来自对应Page的 data 中.

1
2
3
4
5
Page({
data: {
message: "hello world",
},
});

组件属性(需要在双大括号内)

1
<view id="item-{{id}}"></view>
1
2
3
4
5
Page({
data: {
id: 0,
},
});

条件判断

wx: if="{{判断传入的文本用双括号}}"

wx: else="{{判断传入的文本用双括号}}"

wx: ifhidden

类似于v-ifv-show,hidden是始终渲染的,wx: if只有为true才渲染.

列表渲染

wx: for

在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。

默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item

1
2
3
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
1
2
3
4
5
6
7
8
9
10
11
12
Page({
data: {
array: [
{
message: "foo",
},
{
message: "bar",
},
],
},
});

使用 wx:for-item 可以指定数组当前元素的变量名,

使用 wx:for-index 可以指定数组当前下标的变量名:

1
2
3
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>

注意: 当 wx:for 的值为字符串时,会将字符串解析成字符串数组.

花括号和引号之间如果有空格,将最终被解析成为字符串.

wx:key

wx:key 的值以两种形式提供

  1. 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。

key 是字符串,所以不用双大括号.item是默认值,可以不加.

  1. 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

组件中的样式

组件对应 wxss 文件的样式,只对组件 wxml 内的节点生效。编写组件样式时,需要注意以下几点:

组件和引用组件的页面不能使用 id 选择器(#a)、属性选择器([a])和标签名选择器,请改用 class 选择器。

组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。

子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。

继承样式,如 font 、 color ,会从组件外继承到组件内。

除继承样式外, app.wxss 中的样式、组件所在页面的的样式对自定义组件无效(除非更改组件样式隔离选项)。

1
2
3
4
#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b { } /* 除非 .a 是 view 组件节点,否则不一定会生效 */

除此以外,组件可以指定它所在节点的默认样式,使用 :host 选择器(需要包含基础库 1.7.2 或更高版本的开发者工具支持)。

1
2
3
4
/* 组件 custom-component.wxss */
:host {
color: yellow;
}
1
2
<!-- 页面的 WXML -->
<custom-component>这段文本是黄色的</custom-component>

模板

WXML 提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。

##定义模板

使用 name属性,作为模板的名字。然后在<template/>内定义代码片段,如:

1
2
3
4
5
6
7
8
9
<template name="msgItem">
<view>
<text>
{" "}
{{ index }}: {{ msg }}{" "}
</text>
<text> Time: {{ time }} </text>
</view>
</template>

使用模板

使用is属性,声明需要的使用模板,然后将模板所需要的 data 传入,

1
<template is="msgItem" data="{{..item}}">
1
2
3
4
5
6
7
8
9
Page({
data: {
item: {
index: 0,
msg: "this is a template",
time: "2019-11-11",
},
},
});

is属性可以用双大括号,来动态决定渲染哪个模板.

1
2
3
4
5
6
7
8
9
10
<template name="odd">
<view> odd</view>
</template>
<template name="even">
<view> even </view>
</template>

<block wx:for="{{[1,2,3,4,5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>

模板的作用域

模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs /> 模块。

WXS语法(WeiXin Script)

  1. WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
  2. WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
  3. WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的 API。
  4. WXS 函数不能作为组件的事件回调。
  5. 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异

封装小程序 wx.request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 官方例子
wx.request({
url: "test.php", //仅为示例,并非真实的接口地址
data: {
x: "",
y: "",
},
header: {
"content-type": "application/json", // 默认值
},
success: function (res) {
console.log(res.data);
},
});

Promsie 封装

1
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
const baseUrl = "https://api.it120.cc";

const http = ({ url = "", param = {}, ...other } = {}) => {
wx.showLoading({
title: "请求中,请耐心等待..",
});
let timeStart = Date.now();
return new Promise((resolve, reject) => {
wx.request({
url: getUrl(url),
data: param,
header: {
"content-type": "application/json", // 默认值 ,另一种是 "content-type": "application/x-www-form-urlencoded"
},
...other,
complete: (res) => {
wx.hideLoading();
console.log(`耗时${Date.now() - timeStart}`);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
reject(res);
}
},
});
});
};

const getUrl = (url) => {
if (url.indexOf("://") == -1) {
url = baseUrl + url;
}
return url;
};

// get方法
const _get = (url, param = {}) => {
return http({
url,
param,
});
};

const _post = (url, param = {}) => {
return http({
url,
param,
method: "post",
});
};

const _put = (url, param = {}) => {
return http({
url,
param,
method: "put",
});
};

const _delete = (url, param = {}) => {
return http({
url,
param,
method: "put",
});
};
module.exports = {
baseUrl,
_get,
_post,
_put,
_delete,
};

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const api = require("../../utils/api.js");

// 单个请求
api
.get("list")
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});

// 一个页面多个请求
Promise.all([api.get("list"), api.get(`detail/${id}`)])
.then((result) => {
console.log(result);
})
.catch((e) => {
console.log(e);
});

登录

1
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//app.js
App({
onLaunch: function () {
console.log("App onLaunch");
var that = this;
// 获取商城名称
wx.request({
url:
"https://api.it120.cc/" +
that.globalData.subDomain +
"/config/get-value",
data: {
key: "mallName",
},
success: function (res) {
wx.setStorageSync("mallName", res.data.data.value);
},
});
this.login();
this.getUserInfo();
},
login: function () {
var that = this;
var token = that.globalData.token;
// 如果有token
if (token) {
// 检查token是否有效
wx.request({
url:
"https://api.it120.cc/" +
that.globalData.subDomain +
"/user/check-token",
data: {
token: token,
},
success: function (res) {
// 如果token失效了
if (res.data.code != 0) {
that.globalData.token = null;
that.login(); // 重新登陆
}
},
});
return;
}

// 【1】调用微信自带登陆
wx.login({
success: function (res) {
// 【2】 拿到code去访问我们的后台换取其他信息
wx.request({
url:
"https://api.it120.cc/" +
that.globalData.subDomain +
"/user/wxapp/login",
data: {
code: res.code,
},
success: function (res) {
// 如果说这个code失效的
if (res.data.code == 10000) {
// 去注册
that.registerUser();
return;
}
// 如果返回失败了
if (res.data.code != 0) {
// 登录错误
wx.hideLoading();
// 提示无法登陆
wx.showModal({
title: "提示",
content: "无法登录,请重试",
showCancel: false,
});
return;
}

// 【3】 如果成功后设置token到本地
that.globalData.token = res.data.data.token;
// 保存用户信息
wx.setStorage({
key: "token",
data: res.data.data.token,
});
},
});
},
});
},
// 注册?? [这个看需求]
registerUser: function () {
var that = this;
wx.login({
success: function (res) {
var code = res.code; // 微信登录接口返回的 code 参数,下面注册接口需要用到
wx.getUserInfo({
success: function (res) {
var iv = res.iv;
var encryptedData = res.encryptedData;
// 下面开始调用注册接口
wx.request({
url:
"https://api.it120.cc/" +
that.globalData.subDomain +
"/user/wxapp/register/complex",
data: { code: code, encryptedData: encryptedData, iv: iv }, // 设置请求的 参数
success: (res) => {
wx.hideLoading();
that.login();
},
});
},
});
},
});
},
// 获取用户信息
getUserInfo: function () {
wx.getUserInfo({
success: (data) => {
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: "userInfo",
data: data.userInfo,
});
return this.globalData.userInfo;
},
});
},
globalData: {
userInfo: null,
subDomain: "34vu54u7vuiuvc546d",
token: null,
},
});

授权

1
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
getUserInfo: function () {
// 先调用wx.getSetting 获取用户权限设置
wx.getSetting({
success(res) {
console.log('1');
if (!res.authSetting['scope.userInfo']) {
wx.authorize({
scope: 'scope.userInfo',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.getUserInfo接口不会弹窗询问
wx.getUserInfo({
success: (data) => {
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: 'userInfo',
data: data.userInfo
})
return this.globalData.userInfo;
}
})
}
})
} else {
console.log(2);
}
}
})

},

小程序的双向绑定和 vue 哪里不一样

小程序直接this.data的属性不可以直接同步到视图,必须调用this.data

data 和 params 的区别

哪些方法可以用来提高微信小程序的应用速度

  1. 提高页面加载速度
  2. 用户行为预测
  3. 减少默认 data 的大小
  4. 组件化方案

番茄闹钟的问题

  1. 组件内 css 选择器不能有 id,target,attr 选择器,一律使用 class 选择器.
  2. wx:key后跟字符串,不能是双大括号.
  3. 页面 wxss 样式名不要和app.wxss重复,容易使设置样式失效.
  4. 没有出现登录页的情况是需要在app.json中将pages/login/login放在最前面.
  5. 登录页面中跳转时,使用wx.reLaunch并未跳转,使用wx.switchTab可以.
1
2
3
4
//原因:reLaunch必须写相对路径才能正确跳转
wx.reLaunch({ url: "../../pages/home/home" });
//wx.switchTab可以直接跳转绝对路径
wx.switchTab({ url: "/pages/home/home" });
  1. 登录验证中的encrypted_data,event返回的是encryptedData.注意
  2. 请求头里的设置't-app-id': t_app_id,注意横线.
  3. 登录存储 storage 时,wx.setStorageSync('me', response.res.data.resource),注意是response.res
  4. 创建任务时,第一个按照后端 api 文档写的报错,第二个正确
1
2
3
4
5
6
req.post("/todos", {
todo: {
completed: false,
description,
},
});
1
2
3
4
req.post("/todos", {
completed: false,
description,
});
  1. 创建时多一个空白,并且没有 id 和 index.原因:将 resource 写成 resources.有些有 s,有些没有.

11.登录时显示 500 报错,解决方法: 清缓存,全部清除,编译.即可.