小程序使用笔记
小程序开发经常遇到的业务记录。
# 小程序如何生成海报分享
小程序生成海报并分享的实现方式如下:
(1)在 canvas 中绘制海报:
小程序可以使用<canvas>
标签绘制海报,如下所示:
<canvas canvas-id="poster" style="width: 100%; height: 100%;"></canvas>
const context = wx.createCanvasContext("poster");
// 绘制文本、图片等内容
context.setFillStyle("#ffffff");
context.fillRect(0, 0, 750, 1200);
context.drawImage("/images/avatar.png", 30, 30, 300, 300);
context.setFontSize(48);
context.setFillStyle("#333333");
context.fillText("小程序海报", 360, 90);
// ...
context.draw();
2
3
4
5
6
7
8
9
10
11
(2)将 canvas 转换为图片:
通过wx.canvasToTempFilePath
方法可以将 canvas 转换成图片。具体实现如下:
wx.canvasToTempFilePath({
canvasId: "poster",
success: function (res) {
const posterPath = res.tempFilePath; // 生成的海报图片路径
// ...后续操作
},
fail: function (res) {
// 异常处理逻辑
},
});
2
3
4
5
6
7
8
9
10
(3)将图片保存到相册:
将生成的海报图片保存到相册中,可以使用wx.saveImageToPhotosAlbum
方法,代码实现如下:
wx.saveImageToPhotosAlbum({
filePath: posterPath,
success: function () {
// 保存成功处理逻辑
},
fail: function (res) {
// 保存失败处理逻辑
},
});
2
3
4
5
6
7
8
9
(4)分享海报:
将生成的海报分享到朋友圈或者好友,可以使用wx.shareAppMessage
或者wx.updateShareMenu
方法,代码实现如下:
wx.shareAppMessage({
imageUrl: posterPath,
success: function () {
// 分享成功处理逻辑
},
fail: function (res) {
// 分享失败处理逻辑
},
});
2
3
4
5
6
7
8
9
# 小程序内如何生成小程序二维码?
在小程序中生成小程序码,可以通过调用wx.createQRCode
方法来实现。具体操作如下:
在页面中引入
wx
对象:const wx = getApp().wx;
1使用
wx.createQRCode
方法生成小程序码:wx.createQRCode({ path: "pages/index/index", // 小程序页面路径 width: 280, // 二维码宽度,单位为 px // 如果需要背景色,则可以设置 backgroundColor 字段,例如:backgroundColor: '#ffffff' success: function (res) { // res.path 就是生成的小程序码图片路径 }, fail: function (res) { // 生成小程序码失败处理逻辑 }, });
1
2
3
4
5
6
7
8
9
10
11在回调函数中,可以获取到生成的小程序码图片路径,可以通过
<image>
标签来显示该图片。如果需要保存该图片,则可以使用wx.saveImageToPhotosAlbum
方法将图片保存到用户的相册中。
# 如何阻止弹窗滚动穿透
- 倘若可控制页面根元素,则在弹窗弹出时,设置页面的 overflow:hidden 样式
在弹窗区域添加 touchmove 事件,通过event.preventDefault()
方法,阻止触摸事件的默认行为,如下所示:
<view class="popup-container" bindtouchmove="preventScroll">
<!-- 弹窗内容 -->
</view>
2
3
Page({
preventScroll(event) {
// 阻止touchmove事件的默认行为
event.preventDefault();
},
});
2
3
4
5
6
倘若在 taro 组件中,可尝试:
const cathTouchMove = (e) => {
e.stopPropagation();
e.preventDefault();
};
<View catchMove catchtouchmove onTouchMove={cathTouchMove}></View>;
2
3
4
5
6
处理滚动
# 小程序如何发起订阅授权
小程序发起订阅授权需要以下步骤:
- 在小程序的
app.json
文件中设置订阅消息配置:
"subPackages": [
{
"root": "packageA/",
"name": "packageA",
"plugins": {
"wx2d8f88e869071b94": {
"version": "1.0.4",
"provider": "wx2d8f88e869071b94"
}
},
"usingComponents": {
// ...
}
}
],
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序位置接口的效果展示"
},
"scope.userInfo": {
"desc": "你的用户信息将用于小程序内部逻辑的处理,请放心授权"
}
},
"subpackages": [
{
"root": "subscribe-message/",
"name": "subscribe-message",
"pages": [
{
"path": "index",
"config": {
"navigationBarTitleText": "订阅消息"
}
}
]
}
]
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
- 在小程序的
subscribe-message
页面中引入相关的组件和方法:
<view>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">授权</button>
<button bindtap="requestMessageTemplate">订阅授权</button>
<template is="wx-subscribe-message" data="{{...templateData}}"></template>
</view>
2
3
4
5
Page({
data: {
templateData: {
subscribes: [
{
id: "A1B2C3D4E5",
title: "订阅消息标题",
desc: "订阅消息描述",
iconUrl: "https://cdn.xxx.com/xxx.jpg",
extJson: JSON.stringify({
appid: "xxx", // 小程序 id
page: "pages/home", // 路径
params: {}, // 额外参数
}),
version: 1,
},
],
subscribes2: [], // 如果有多个模板可以添加多个对象
},
},
getUserInfo: function (e) {
console.log(e.detail.userInfo);
},
requestMessageTemplate() {
wx.requestSubscribeMessage({
tmplIds: ["A1B2C3D4E5"],
success(res) {
console.log("订阅成功:", res);
},
fail(res) {
console.log("订阅失败:", res);
},
});
},
});
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
在
requestSubscribeMessage
方法中调用订阅消息接口wx.requestSubscribeMessage
来发起授权请求。需要注意的是,订阅消息接口需要在用户主动点击的事件中触发,否则会被腾讯审核拒绝。用户点击「订阅授权」按钮后,如果用户未授权订阅,则会弹出授权页面,用户点击允许后,即可成功订阅该模板消息。如果用户拒绝授权,则需要在相关页面给出提示或引导用户去设置中进行授权。
# 小程序如何实现图片裁切功能
小程序中实现图片裁剪功能需要使用canvas
来进行裁剪并生成新的图片,需要以下步骤:
- 在页面中引入
canvas
标签用于展示要裁剪的图片和裁剪后的图片:
<view class="container">
<view class="canvas-container">
<canvas
canvas-id="cropCanvas"
style="cursor: move;"
bindtouchmove="touchMove"
></canvas>
</view>
<view class="btn-container">
<button class="btn-cancel" bindtap="cancelCrop">取消</button>
<button class="btn-crop" bindtap="startCrop">裁剪</button>
</view>
</view>
2
3
4
5
6
7
8
9
10
11
12
13
- 在页面的
onLoad
或onShow
生命周期中,加载要裁剪的图片并绘制到canvas
上。图片的绘制需要在图片加载完成的回调函数中进行:
onLoad: function(options) {
this.setData({
imagePath: options.imagePath // 从上一个页面传递过来的图片路径
});
let self = this;
let ctx = wx.createCanvasContext('cropCanvas', self);
wx.getImageInfo({
src: self.data.imagePath,
success: function(res) {
let scale = res.width / res.height;
let canvasWidth = self.data.screenWidth - 20;
let canvasHeight = canvasWidth / scale;
self.setData({
canvasWidth: canvasWidth,
canvasHeight: canvasHeight
})
self.resetCanvas();
let x = 0,
y = 0,
width = res.width,
height = res.height;
if (canvasHeight < canvasWidth) {
// 竖图
height = canvasHeight;
width = height * scale;
x = -(width - canvasWidth) / 2;
} else {
// 横图
width = canvasWidth;
height = width / scale;
y = -(height - canvasHeight) / 2;
}
ctx.drawImage(self.data.imagePath, x, y, width, height);
ctx.draw();
}
})
}
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
- 实现拖动和缩放功能。拖动需要记录每次触摸移动的距离,并使用
translate
方法来移动画布。缩放功能可使用两根手指识别,记录每个手指的坐标,并计算两根手指之间的距离和角度,然后使用scale
和rotate
方法来进行缩放和旋转:
data: {
isMoving: false,
isScaling: false,
touchCount: 0,
touchHistory: [],
scale: 1,
rotate: 0,
translateX: 0,
translateY: 0,
startX: 0,
startY: 0,
screenScale: 1,
screenWidth: 1,
canvasWidth: 1,
canvasHeight: 1,
imagePath: ''
},
touchStart(e) {
let touchCount = this.data.touchCount + 1;
let touchHistory = this.data.touchHistory;
touchHistory.push({
x: e.touches[0].x,
y: e.touches[0].y
});
if (touchCount === 1) {
this.setData({
isMoving: true,
touchCount: touchCount,
touchHistory: touchHistory,
startX: e.touches[0].x,
startY: e.touches[0].y
});
} else if (touchCount === 2) {
let distance = Math.sqrt(Math.pow(touchHistory[1].x - touchHistory[0].x, 2) + Math.pow(touchHistory[1].y - touchHistory[0].y, 2));
let angle = this.computeRotateAngle(touchHistory[0], touchHistory[1]);
this.setData({
isScaling: true,
touchCount: touchCount,
touchHistory: touchHistory,
startDistance: distance,
startAngle: angle
});
}
},
touchMove(e) {
let touchHistory = this.data.touchHistory.concat();
let touchCount = touchHistory.length;
touchHistory.push({
x: e.touches[0].x,
y: e.touches[0].y
});
if (touchCount === 1) {
let distanceX = e.touches[0].x - this.data.startX;
let distanceY = e.touches[0].y - this.data.startY;
this.setData({
isMoving: true,
touchHistory: touchHistory,
startX: e.touches[0].x,
startY: e.touches[0].y,
translateX: this.data.translateX + distanceX,
translateY: this.data.translateY + distanceY
}, () => {
this.drawCanvas();
});
} else if (touchCount === 2) {
let distance = Math.sqrt(Math.pow(touchHistory[1].x - touchHistory[0].x, 2) + Math.pow(touchHistory[1].y - touchHistory[0].y, 2));
let angle = this.computeRotateAngle(touchHistory[0], touchHistory[1]);
this.setData({
isScaling: true,
touchHistory: touchHistory,
currentDistance: distance,
currentAngle: angle
}, () => {
this.drawCanvas();
});
}
},
touchEnd(e) {
if (this.data.touchCount === 1) {
this.setData({
isMoving: false,
touchCount: 0
});
} else if (this.data.touchCount === 2) {
this.setData({
isScaling: false,
touchCount: 0,
scale: this.data.scale * (this.data.currentDistance / this.data.startDistance),
rotate: this.data.rotate + (this.data.currentAngle - this.data.startAngle)
}, () => {
this.drawCanvas();
});
}
},
computeRotateAngle(p1, p2) {
let x1 = p1.x,
y1 = p1.y,
x2 = p2.x,
y2 = p2.y;
let disX = x2 - x1,
disY = y2 - y1,
angle;
if (disY === 0) {
angle = disX > 0 ? 0 : 180;
} else if (disX === 0) {
angle = disY > 0 ? 90 : 270;
} else {
angle = Math.atan(disY / disX) * 180 / Math.PI;
if (disX > 0 && disY > 0) {
// 第一象限
} else if (disX < 0 && disY > 0) {
// 第二象限
angle = 180 + angle;
} else if (disX < 0 && disY < 0) {
// 第三象限
angle = 180 + angle;
} else {
// 第四象限
angle += 360;
}
}
return angle;
}
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
- 实现裁剪功能。首先根据缩放和旋转的信息计算出裁剪的起始坐标以及裁剪区域的尺寸,然后将这些参数传递给
canvas
的drawImage
方法,并在绘制完裁剪后的图片后,将图片转化为base64
格式,方便后续的上传或保存:
cropImage() {
let self = this;
let ctx = wx.createCanvasContext('cropCanvas', self);
let canvasWidth = self.data.canvasWidth;
let canvasHeight = self.data.canvasHeight;
let scale = self.data.screenScale;
let rotate = self.data.rotate;
let scaleX = self.data.scale;
let scaleY = self.data.scale;
let translateX = self.data.translateX / scale;
let translateY = self.data.translateY / scale;
let x = 0,
y = 0,
width = canvasWidth / scaleX,
height = canvasHeight / scaleY;
// 裁剪区域超出画布的情况特殊处理
if (canvasWidth < canvasHeight && Math.abs(translateY) + height > canvasHeight / 2) {
translateY = canvasHeight / 2 - height;
} else if (canvasHeight <= canvasWidth && Math.abs(translateX) + width > canvasWidth / 2) {
translateX = canvasWidth / 2 - width;
}
ctx.translate(canvasWidth / 2 + translateX, canvasHeight / 2 + translateY);
ctx.rotate(rotate * Math.PI / 180);
ctx.scale(scaleX, scaleY);
x = (-width) / 2;
y = (-height) / 2;
ctx.drawImage(self.data.imagePath, x, y,
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