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

前言

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

注册

  • 微信公众平台

  • 邮箱要填写未被微信公众平台注册,未被微信开放平台注册,未被个人微信号绑定的邮箱

登录

  • 设置找到AppID(小程序ID)记下

安装

新建项目

  • 如果只是测试,可以不写AppID(小程序ID),如果开发后发布,要写AppID(小程序ID)

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ pages // 存放每个页面文件的目录
+ index // 存放首页模块的目录
- index.js // 首页逻辑
- index.json // 首页配置
- index.wxml // 首页结构
- index.wxss // 首页样式
+ logs // 存放日志模块的目录
- logs.js // 日志逻辑
- logs.json // 日志配置
- logs.wxml // 日志结构
- logs.wxss // 日志样式
+ utils // 存放第三方插件(可以删除)
- util.js
- app.js // 程序执行的入口
- app.json // 全局配置
- app.wxss // 全局样式
- project.config.json // 全局详情
- sitemap.json // 是否可以被微信索引配置

页面组件

页面样式

  • WXSS书写规则与CSS一致

单位换算

  • rpx是小程序特有的长度单位,会随着屏幕宽度的变化而变化
  • 750px宽的屏幕下,px和rpx的比例是1:1
  • 公式:屏幕宽rpx = 750rpx * 元素宽度 / 屏幕宽px

页面函数

page.js

1
2
3
4
5
6
7
8
const app = getApp(); // 调用app.js文件

Page({
data: {}, // 页面初始数据
bindViewTap: {}, // 事件处理函数
onLoad: {}, // 生命周期函数
...: {} // 用户定义的函数
})

页面配置

全局函数

app.js

1
2
3
4
5
6
App({
onLaunch() {}, // 小程序初始化时执行的生命周期函数
onShow() {}, // 小程序从后台进入前台时执行的生命周期函数
onHide() {}, // 小程序从前台进入后台时执行的生命周期函数
globalData: function() {} // 用户自定义属性,在获取实例对象时可以获取到
})
  • getApp()获取小程序实例对象

app.js

1
const app = getApp();

全局配置

navigationBar:顶部导航栏区域
background:下拉加载区域
page:正文区域

app.json

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
{
"pages": [
"pages/index/index", // 第一行为默认页
"pages/logs/logs"
], // 页面路径
"window":{
"backgroundTextStyle":"light", // 下拉loding的样式:dark或light
"navigationBarBackgroundColor": "#fff", // 导航栏背景颜色
"navigationBarTitleText": "Weixin", // 导航栏标题
"navigationBarTextStyle":"black", // 导航栏字体颜色
"enablePullDownRefresh": true, // 启动下拉刷新
"backgroundColor": "#fff" // 下拉刷新位置的背景颜色
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index", // 定义页面跳转路径
"text": "首页", // 定义标签文本信息
"iconPath": "./icons/_zhuye.png", // 图标路径(未选择)
"selectedIconPath": "./icons/zhuye.png" // 图标路径(已选择)
}, // 定义每一个标签的配置
{
"pagePath": "pages/logs/logs",
"text": "日志"
}
] // 定义标签的数组,标签最少2个,最多5个
}, // 底部TabBar配置
"style": "v2",
"sitemapLocation": "sitemap.json"
}

project.config.json项目配置文件

sitemap.json微信搜索配置

页面路由

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

navigateTo:打开新页面。只可以跳转非tabBar页面(当前页面在栈中保留,新页面进栈)
navigateBack:页面返回。页面返回设定的url需要改为原页面路径。在返回的过程中,不会触发onLoad(),因为它已经在页面栈中保存了,但是会触发onShow()(将当前页面移出页面栈,)
switchTab:打开新页面。只可以跳转tabBar页面(将所有页面移出页面栈,保留要跳转的tabBar页面)
reLaunch:打开新页面。可以跳转任意页面
rediirect:页面重定向。(当前页面出栈,新页面进栈)

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

page.wxml

1
<navigator open-type="navigateTo" url="../logs/logs"></navigator>

模块化

  • 采用nodejs的方式,exports或module.exports进行暴露,require进行获取

视图层

数据绑定

  • 采用插值表达式(胡子语法)

key:动态获取的数据

page.js

1
2
3
4
5
Page({
data: {
key: "value"
}
})

page.wxml

1
<view>{{key}}</view>

数据获取和修改

key:自定义的数据

page.js

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

this.setData({
key: ""
}); // 修改msg的值
}
})

列表渲染

arr:列表数据

page.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Page({
data: {
arr: [
{
title: "标题1"
},
{
title: "标题2"
},
{
title: "标题3"
}
]
}
})

wx:for-index="index":定义当前变量的索引值,默认值为index
wx:for-item="item":定义当前变量的变量名,默认值为item
wx:key="":指定列表中项目的唯一的标识符,如果不指定会报警告

page.wxml

1
2
3
<view wx:for="{{arr}}" id="{{index}}">
{{item.title}}
</view>

条件渲染

page.js

1
2
3
4
5
Page({
data: {
key: "a"
}
})

page.wxml

1
2
3
<view wx:if="{{key=='a'}}">a</view>
<view wx:elif="{{key=='b'}}">b</view>
<view wx:else="{{key=='c'}}">c</view>

隐藏属性

page.wxml

1
2
3
<view hidden="true"></view>

<view hidden></view>

所有组件在指定属性时,如果没有指定属性值,则默认为值true

模版

  • 使用模版组件定义代码片段,可以在任意地方调用模版

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

page.wxml

1
2
3
<template name="">
...
</template>

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

page.wxml

1
2
3
4
5
<template is="" data="">
...
</template>

<template is="" data=""/>

事件

点击事件

  • bind事件会向上冒泡

page.wxml

1
<view bindtap="method"></view>
  • catch事件不会向上冒泡

page.wxml

1
<view catchtap="method"></view>
  • 在wxs文件中定义函数主体

page.js

1
2
3
4
5
Page({
method: function(event) {
...
}
})

传递参数

data-value="value":传递参数

page.wxml

1
<view bindtap="method" data-value="value"></view>

page.js

1
2
3
4
5
Page({
method: function(event) {
console.log(event.currentTarget.dataset.value);
}
})

组件

视图容器组建

  • 类似html中的div标签

hover-class="method":鼠标点击后一闪而过的效果

page.wxml

1
<view></view>

page.wxss

1
2
3
.method {
color: red
}

文本组件

user-select="false":文本是否可选
decode="false":文本是否解码转义字符

page.wxml

1
<text></text>

图片组件

  • 默认尺寸320px*240px

src="":图片引入地址,小程序发布不允许超过2M,所以不建议图片本地化,要求使用网络地址
mode="":图片裁剪缩放模式

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

page.wxml

1
<image></image>

按钮组件

  • 默认带阴影

size="":按钮的大小

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

type="":按钮的类型

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

plain="false":按钮是否镂空,背景透明
disabled="false":按钮是否禁用
loding="false":按钮前是否带loding图标
form=type="":触发表单事件

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

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

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

page.wxml

1
<button></button>

获取用户信息

  • 需要在回调函数getuserinfo()中获取

page.wxml

1
<button open-type="getUserInfo"></button>

page.js

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

获取用户手机号

  • 需要在回调函数getnumber()中获取

page.wxml

1
<button open-type="getPhoneNumber"></button>

page.js

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

多选框组件

value="":checkbox标识,选中时触发change事件,并携带value值
disabled="false":是否禁用
checked="false:是否选中
color="rgba(255,255,255,1)":多选框颜色

page.wxml

1
2
3
<checkbox-group bindchange="changefn">
<checkbox></checkbox>
</checkbox-group>

page.js

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

单选框组件

value="":redio,选中时触发change事件,并携带value值
disabled="false":是否禁用
checked="false:是否选中
color="rgba(255,255,255,1)":单选框颜色

page.wxml

1
2
3
<redio-group bindchange="changefn">
<redio/>
</redio-group>

page.js

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

滑块视图容器(轮播图)

indicator-dots="false":是否显示指示点
indicator-color="rgba(255,255,255,1)":指示点颜色(未选中)
indicator-active-color="rgba(255,255,255,1)":指示点颜色(已选中)
autoplay="false":是否自动切换
current="0":当前所在滑块的索引
interval="5000":自动切换时间间隔,单位毫秒
duration="500":滑动动画时长,单位毫秒
circular="false":是否采用首尾衔接滑动
certical="false":滑动方向是否为纵向
easy-function="":动画类型

default:缺省值,缓动函数
linear:线性动画
easeInCubic:缓入动画
easeOutCubic:缓出动画
easeInOutCubic:缓入缓出动画

page.wxml

1
2
3
4
5
6
7
8
9
<swiper>
<swiper-item>
<image></image>
</swiper-item>

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

索引改变事件

bindchange="":current改变时会触发的change事件

page.wxml

1
2
3
4
5
6
7
8
9
<swiper bindchange="changefn">
<swiper-item>
<image></image>
</swiper-item>

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

page.js

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

自定义属性

  • 在组件中使用自定义属性

data-:使用这个前缀的属性为自定义属性
index:自定义名称

page.wxml

1
<view data-index="0" bindtap="tapfn"><view>

page.js

1
2
3
4
5
Page({
tapfn: function(event) {
console.log(event.target.dataset.index);
}
})

自定义组件

创建组件库

  • pages目录下创建名为compomemts的目录,用于存放自定义组件

  • 右键创建好的目录->点击创建Component->创建与目录名同名的Component

配置组件

component.json

1
2
3
4
{
"component": true // 定义这是一个组件
"usingComponents": {} // 使用其他组件
}

component.js

1
2
3
4
5
Component({
properties: {}, // 组件的属性列表
data: {}, // 组件的初始数据
methods: {} // 组件的方法列表
})

引用组件

page.json

1
2
3
4
5
{
"usingComponents": {
"component": "../components/component/component" // 定义组件位置
} // 引用组件
}

page.wxml

1
<component></component>

组件传值

父组件传值给子组建

key:自定义属性名
value:需要传递的值

page.wxml

1
<component key="value"></component>

component.js

1
2
3
4
5
6
7
8
Component({
properties: {
key: { // 定义自定义属性名
type: String, // 定义自定义属性类型
value: "" // 定义自定义属性默认值
}
}
})

component.wxml

1
<view>{{key}}</view>

子组建传值给父组件

component.wxml

1
<button bindtap="click">按钮</button>

component.js

1
2
3
4
5
6
7
8
9
10
11
Component({
methods: {
click: function() {
// 使用自定义事件向父组件传值
this.triggerEvent(
"e", // 自定义事件名
"value" // 传递的数据
)
}
}
})

binde:bind+自定义事件名

page.wxml

1
<component binde="efn"></component>

page.js

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

获取标签内容

  • 通过slot组件(插槽、占位符)在自定义组件中,获取父组件定义的内容渲染在子组件

page.wxml

1
2
3
<component>
<view>value</view>
</component>

component.wxml

1
<slot></slot>

使用第三方组件

初始化项目

  • 在项目根目录执行npm初始化命令
1
npm init -y
  • 下载第三方组件(这里以vant-weapp框架)
1
npm i @vant/weapp -S --production
  • 小程序开发者工具->工具->构建npm

开启项目node支持

  • 小程序开发者工具->右上角详情->本地设置->勾选使用npm模块

project.config.json

1
2
3
4
5
{
"setting": {
"nodeModules": true
}
}

引入node模块

通过绝对路径引入

page.json

1
2
3
4
5
{
"usingComponents": {
"btn": "@vant/weapp/button
}
}

通过相对路径引入

page.json

1
2
3
4
5
{
"usingComponents": {
"btn": "../../miniprogram_npm/@vant/weapp/button"
}
}

创建第三方组件

传送门

网络请求

page.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Page({
onLoad: function() {
wx.request({
method: "GET", // 请求方式
url: "", // 请求地址
data: {}, // 请求参数
header: "application/json", // 请求头
success: function(res) { // 处理成功时的响应数据
console.log(res.data);
},
fail: function(res) {}, // 处理失败时的响应数据
complete: function(res) {} // 处理成功和失败时的响应数据
})
}
})

踩坑

  • 报错:http://127.0.0.1 不在以下 request 合法域名列表

解决问题

  • 微信小程序开发者工具->右上角详情->本地设置->勾选不校验合法域名、wev-view(业务域名)、TLS版本以及HTTPS证书

proect.config.json

1
2
3
4
5
{
"setting": {
"urlCheck": false
}
}

微信登录

app.js

1
2
3
4
5
6
7
8
9
App({
onLaunch() {
wx.login({
success: function(res) {
console.log(res);
}
})
}
})

用户授权

scope:指定授权的权限名

userInfo:用户信息
userLocation:地理位置
userLocationBackground:后台定位
werun:微信运动步数
record:录音功能
writePhotosAlbum:保存到相册
camera:摄像头

app.js

1
2
3
4
5
6
7
8
App({
onLaunch() {
wx.authorize({
scope: "", // 指定授权的权限名
success: function(res) {} // 授权成功后的回调函数
})
}
})

获取授权状态

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
App({
onLaunch() {
wx.getSetting({
success: function(res) {
console.log(res.authSetting);

if (res.authSetting["scope.userInfo"]) { // 判断是否有权限,进行页面路由
wx.redirectTo({
url: '/pages/page/page',
})
} else {
console.log("请授权");
}
}
})
}
})

获取用户信息

  • 获取用户所有信息案例

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
App({
onLaunch() {
wx.getSetting({
success: function(res) {
console.log(res.authSetting);

if (res.authSetting["scope.userInfo"]) { // 判断是否有权限,进行页面路由
wx.getUserInfo({
success: function(res) {
let userInfo = res.userInfo;
let nickname = userInfo.nickName;
let avatarUrl = userInfo.avatarUrl;
let gender = userInfo.gender; // 未知0,男1,女2
let province = userInfo.province;
let city = userInfo.city;
let country = userInfo.country;
console.log(nickname,avatarUrl,gender,province,city,country)
}
});
}
}
})
}
})

转发

page.wxml

1
<button open-type="share"></button>

page.js

1
2
3
4
5
6
7
8
9
10
Page({
onShareAppMessage: function(res) {
console.log(res);
return {
title: "", // 转发标题
path: "", // 转发的页面绝对路径
imageUrl: "" // 转发的图片的路径
}
}
})

定位

获取位置信息

  • 官方文档

  • 得到用户授权才可以使用,如果没有授权,会自动弹出授权提示

  • 配置弹窗说明

app.json

1
2
3
4
5
6
7
{
permission: {
"scope.userLocation": {
"desc": "" // 弹窗说明,不能超过30个字符
}
}
}

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
App({
onLaunch() {
wx.getLocation({
type: "wge84", // 定位类型,"wge84"返回GPS坐标,"gcj02"为IP定位
altitude: false, // 是否获取高度定位,开启高度定位会减慢返回速度
isHightAccuracy: false, // 是否开启高精度定位
success: functoion(res) { // 接口调用成功的回调函数
console.log(res.latitude); // 纬度,负数为南纬
console.log(res.longitude); // 经度,负数为西经
console.log(res.speed); // 速度,单位m/s
console.log(res.accuracy); // 位置的精确度
console.log(res.alititude); // 高度,单位m
},
fail: function() {}, // 接口调用失败的回调函数
complete: function() {} // 接口调用成功和失败的回调函数
})
}
})

使用内置地图标记

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
App({
onLaunch() {
wx.openLocation({
latitude: 0, // 纬度,范围为-90~90(使用gcj02国测坐标系)
longitude: 0, // 纬度,范围为-180~180(使用gcj02国测坐标系)
scale: 18, // 缩放比例,范围为5~18
name: "", // 位置名
address: "", // 地址详细说明
success: function() { // 接口调用成功的回调函数

},
fail: function() {}, // 接口调用失败的回调函数
complete: function() {} // 接口调用成功或失败的回调函数
})
}
})

媒体

视频

page.wxml

1
<video id=""></video>

page.js

1
2
3
4
5
6
7
8
9
10
Page({
onReady() {
this.videoContext = wx.createVideoContext("id");

this.videoContext.sendDanmu(
"", // 弹幕文本内容
"", // 弹幕文字颜色
);
}
})

完成

参考文献

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