小程序的官方开发文档日新月异,要想不踩坑则必须时刻关注官方文档!!!
# 小程序登录流程
简单来说就是:1.先 wx.login()拿到 code,2.把 code 传给后端,后端拿到 code 后跟微信服务器通信,获得用户的 openid 和 sessionkey 等信息,3.再进行自定义登录流程即可。
每个用户的 openid 是固定。后端跟微信服务器通信时也需要这个小程序的 appkey、appsecret 等信息,这是固定的不会变化。
# 获取用户设置然后获取授权拿到用户信息
Taro.getSetting({
success(res) {
if (!res.authSetting["scope.userInfo"]) {
Taro.authorize({
scope: "scope.userInfo",
success() {
console.log("getSetting", res);
},
});
} else {
// 必须是在用户已经授权的情况下调用
Taro.getUserInfo({
success(result) {
console.log("getUserInfo", result);
const userInfo = result.userInfo;
setUserInfo({ ...userInfo });
Taro.navigateTo({ url: "/pages/index/index" });
},
});
}
},
fail(err) {
Taro.showToast({
title: `获取用户信息失败,请授权 ${err}`,
icon: "none",
duration: 2000,
});
},
});
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
# 获取写入图片权限
Taro.getSetting({
success(res) {
if (!res.authSetting["scope.writePhotosAlbum"]) {
Taro.authorize({
scope: "scope.writePhotosAlbum",
success() {
console.log("writePhotosAlbum", res);
},
});
} else {
// 必须是在用户已经授权的情况下调用
// TODO save picture
save2album();
}
},
fail(err) {
Taro.showToast({
title: `获取用户信息失败,请授权 ${err}`,
icon: "none",
duration: 2000,
});
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 绘制 Canvas
- 使用 Painter
<Painter
palette={palette}
onImgOK={onImgOK}
onImgErr={onImgErr}
customStyle="position:fixed; left:-9999rpx;"
/>;
/**
* 保存图片到本地相册
*/
const save2album = () => {
if (filePath !== "") {
Taro.saveImageToPhotosAlbum({
filePath,
success(res) {
Taro.showModal({
title: "图片保存成功",
content: "图片成功保存到相册了,快去发朋友圈吧~",
showCancel: false,
confirmText: "确认",
});
},
fail(err) {
Taro.showModal({
title: "图片保存失败",
content: "请重新尝试!",
showCancel: false,
confirmText: "确认",
});
},
});
} else {
Taro.showToast({
title: "获取图片地址失败",
duration: 2000,
});
}
};
/**
* Painter绘制canvas成功后的回调
*/
const onImgOK = (e) => {
setFilePath(e.path);
};
/**
* Painter绘制canvas失败后的回调
*/
const onImgErr = (e) => {
Taro.showToast({
title: "生成图片失败",
duration: 2000,
});
};
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
# Taro 保存图片
const saveCard = async () => {
// 将Canvas图片内容导出指定大小的图片
const res = await Taro.canvasToTempFilePath({
x: 0,
y: 0,
width: 750,
height: 1980,
destWidth: 750,
destHeight: 1980,
canvasId: "cardCanvas",
fileType: "png",
});
const saveRes = await Taro.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
});
if (saveRes.errMsg === "saveImageToPhotosAlbum:ok") {
Taro.showModal({
title: "图片保存成功",
content: "图片成功保存到相册了,快去发朋友圈吧~",
showCancel: false,
confirmText: "确认",
});
} else {
Taro.showModal({
title: "图片保存失败",
content: "请重新尝试!",
showCancel: false,
confirmText: "确认",
});
}
};
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
# SCSS/SASS/Less/Stylus/CSS 互相转换
- eg.
bg-image($url)
background-image: url($url + '@2x.png')
@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3)
background-image: url($url + '@3x.png')
2
3
4
@mixin bg-image($url) {
background-image: url($url + "@2x.png");
@media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
background-image: url($url + "@3x.png");
}
}
2
3
4
5
6
# 字体转换工具
- 字体库转 base64
# iPhone X+ 机型适配
最简单的方案即使用 Apple 官方推出的 css 函数 env()、constant()来适配,对于底部空白的部分可以自行加个 view。
/*兼容 IOS<11.2*/
padding-bottom: calc(108px + constant(safe-area-inset-bottom));
/*兼容 IOS>11.2*/
padding-bottom: calc(108px + env(safe-area-inset-bottom));
2
3
4
- 配合 js 判断机型
import Taro from "@tarojs/taro";
// iphone X
const IPHONE_X = /iphone x/i;
// >= iPhone11
const IPHONE_X_11 = /iphone 1\d/i;
// 未适配机型-新机型
const IPHONE_UNKNOWN = /unknown\(iphone\)/i;
// 方法一:使用model判断是否是IPhoneX及其他包含安全区域的机型手机
export const isIpx = () => {
const model = Taro.getSystemInfoSync().model;
return (
model.search(IPHONE_X) > -1 ||
model.search(IPHONE_X_11) > -1 ||
model.search(IPHONE_UNKNOWN) > -1
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 按需注入
- 降低小程序的启动时间和运行时内存
{
"lazyCodeLoading": "requiredComponents"
}
2
3
# 全局注册组件
{
usingComponents:{
'keyboard':'components/../index',
}
}
2
3
4
5
# 分享对话、朋友圈
useShareAppMessage(() => {
return {
title: "啦啦啦啦",
imageUrl:
"https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eraEeftaBoduGGBHx3noVp5XQ8aYKwWAN74LqWR26mMhD8rTdXbGDxf3LpdYhO0BVtMZhHsg2VIBA/132",
path: `/pages/index`,
};
});
useShareTimeline(() => {
return {
title: "啦啦啦啦",
imageUrl:
"https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eraEeftaBoduGGBHx3noVp5XQ8aYKwWAN74LqWR26mMhD8rTdXbGDxf3LpdYhO0BVtMZhHsg2VIBA/132",
};
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Taro3.x 版本中接入 Painter,实现图片导出功能
目前我在 Taro3.x+React+TypeScript 项目中通过如下方式可以使用,应该有更好的方法,该方法只是应急:
- 通过 submodule 把核心模块引入到项目中
git submodule add https://github.com/Kujiale-Mobile/PainterCore.git components/drawer
- 在 app.config.ts 中全局注册 Painter
usingComponents: {
'my-painter': 'components/drawer/painter',
}
2
3
- 之后在.tsx 文件中直接可以使用
<my-painter
palette={palette}
onImgOK={onImgOK}
onImgErr={onImgErr}
customStyle={painterStyle}
use2D
/>
2
3
4
5
6
7
- 观察编译后的小程序原生代码长这样:
<my-painter
is="components/drawer/painter"
bind:img-err="eh"
bind:img-ok="eh"
id="_n_256"
>
...
</my-painter>
2
3
4
5
6
7
8
而 components/drawer/painter 里 getImageInfo(filePath)函数触发的是 imgOK,如下:
that.triggerEvent("imgOK", {
path: filePath,
});
2
3
尝试把 "imgOK" 替换为 "img-ok",可以正常触发回调 "onImgOK",所以在回调 "onImgOK"里通过 e.detail.path 获取到生成的 canvas 图片地址 filePath,然后按照正常步骤保存图片即可。
// .tsx中的回调
const onImgOK = (e) => {
console.log("onImgOK", e);
setFilePath(e.detail.path);
};
2
3
4
5
对于 customStyle,一般不需要显示这个 canvas,所以设置为:
const painterStyle = 'position:fixed; left:-9999rpx;'
;剩下的就是把 palette 写出来。
# 如何配置项目,避免开发环境 appid 和生产环境 appid 管理使用混乱
Taro 官方貌似没有配置的教程,所以要么是手动改,要么也可以参考如下方案:
我们知道 Taro 对环境的配置文件放在
config/
目录下,因此我们在config
下(其他地方也可以)新建一个updateConfig.js
文件利用
nodejs
的fs
模块对文件进行读写。updateConfig.js
代码如下:
/**
* 根据环境更新../project.config.json中的appid字段
* @env NODE_ENV=development 将config/dev.js中的appid配置设置到../project.config.json中
* @env NODE_ENV=production 将config/prod.js中的appid配置设置到../project.config.json中
*/
const fs = require("fs");
const path = require("path");
const DEV_CONFIG = require("./dev");
const PROD_CONFIG = require("./prod");
const { readFileSync, writeFileSync } = fs;
function updateProjectConfig(filePath) {
const fileOption = { encoding: "utf-8" };
const fileContent = readFileSync(filePath, fileOption);
const config = JSON.parse(fileContent.toString());
if (process.env.NODE_ENV === "production") {
config.appid = PROD_CONFIG.appid;
console.log(`[PROD] appId = ${config.appid}`);
} else {
config.appid = DEV_CONFIG.appid;
console.log(`[DEV] appId = ${config.appid}`);
}
const newConfig = JSON.stringify(config, null, 2);
writeFileSync(filePath, newConfig, fileOption);
}
updateProjectConfig(path.join(__dirname, "../project.config.json"));
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
把开发和生产的
appid
分别配置到config/dev.js
和config/prod.js
中;然后再
package.json
中配置一下启动命令即可。例:
"scripts": {
"start": "npm run dev:weapp",
"build": "npm run build:weapp",
"build:weapp": "taro build --type weapp",
"dev:weapp": "npm run precond-weapp:dev && npm run build -- --watch",
"precond-weapp:dev": "cross-env NODE_ENV=development node ./config/updateProjectConfig.js",
"precond-weapp:prod": "cross-env NODE_ENV=production node ./config/updateProjectConfig.js",
"build:dev": "npm run precond-weapp:dev && npm run build",
"build:prod": "npm run precond-weapp:prod && npm run build"
},
2
3
4
5
6
7
8
9
10
- 这样运行 npm start 即可在开发模式下进行开发,如果要在真机预览,则新建一个有
NODE_ENV=production
的命令,打包的时候压缩一下体积即可。 - 对于生产的包,运行
npm run build:prod
即可得到。 --watch
开启热更新。
# 页面跳转之前进行「简单提示」的做法
useEffect(() => {
Taro.eventCenter.once(getCurrentInstance()?.router?.onHide, () => {
console.log("onHide");
});
Taro.eventCenter.on("beforegoback", () => {
console.log("beforegoback");
});
Taro.disableAlertBeforeUnload();
Taro.enableAlertBeforeUnload({
message: "询问对话框内容询问对话框内容询问对话框内容询问对话框内容",
success(res) {
console.log(res);
Taro.navigateBack({ delta: 1 });
},
fail(e) {
console.log(e);
},
});
}, []);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Hooks in Taro
常用的除了 React 中的 hooks,还有 taro 封装的:useRouter,useReady,useDidShow,useDidHide,useShareAppMessage 等等