南锋

南奔万里空,脱死锋镝余

cocosCreator导出的web工程加载本地图片

cocosCreator版本:3.7.2
在 Web 平台开发 Cocos Creator 游戏或应用时,有时候我们希望让用户上传一张本地图片用于展示、头像设置等。
但 Cocos 本身不提供原生文件选择器,这里我们借助 HTML 原生的 <input type="file">,再结合 TypeScript 实现完整的逻辑。

创建一个隐藏的图片选择器

创建一个隐藏的图片选择器,用于选择图片,并监听选择文件事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
onLoad() {
this.creatorImagePicker();
}
createImagePicker() {
this.inputElement = document.createElement('input');
this.inputElement.type = 'file';
this.inputElement.accept = 'image/*'; // 仅允许选择图片
this.inputElement.style.display = 'none'; // 隐藏 input 元素
document.body.appendChild(this.inputElement);
this.inputElement.addEventListener('change', this.handleFileChange);
}
private handleFileChange = (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
const file = target.files[0];
this.handleFileUpload(file);
}
}

触发监听事件

我这里是通过点击按钮触发的,点击按钮之后,会触发inputElementclick事件,然后inputElement会触发change事件,从而触发handleFileUpload方法。

1
2
3
HandlerBtn_selectImg(){
this.inputElement.click();
}

处理图片

这里我使用的是FileReader来读取图片,然后通过FileReaderonload事件来获取图片的base64编码。由于图片过大,可能会导致图片上传到服务器失败,所以这里对图片进行了压缩,你也可以不压缩。
下面函数中的imageUrl就是你选择图片的base64编码

1
2
3
4
5
6
7
8
9
10
11
private handleFileUpload(file: File) {
const reader = new FileReader();
// 读取文件为 DataURL
reader.onload = (e) => {
const imageUrl = e.target?.result as string;
Tool.compressImageTo200KB(imageUrl).then((compressedImageUrl) => {
console.log(compressedImageUrl);
});
};
reader.readAsDataURL(file);
}

在cocosCreator中加载图片

我这里加载图片的地方有寸尺要求,不同的地方不一样,所以在加载的时候设置了图片的尺寸。后面想想好像有点多此一举,哈哈哈哈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** 加载base64位的图片 */
public static loadTextureInCocos(node: Node, imageUrl: string, width, hight) {
let image = new Image();
image.onload = () => {
let img = new ImageAsset(image)
let texture = new Texture2D();
texture.image = img; // 设置纹理的图片
let spriteFrame = new SpriteFrame();
spriteFrame.texture = texture;
node.getComponent(Sprite).spriteFrame = spriteFrame; // 直接设置精灵帧
node.getComponent(UITransform).setContentSize(width, hight);
};
image.src = imageUrl;
}

移除 DOM 和解绑事件:

在组件销毁时,一定要手动移除 DOM 元素和解绑事件。因为在组件销毁时,DOM 节点仍然存在于 document.body 中,哪怕你的 Cocos 组件或场景已经销毁。它们不会被 GC(垃圾回收),因为:
它们仍被 document.body 引用;
事件监听器(如 addEventListener)也在引用函数闭包。
如果不移除,后面可能会导致一些意想不到的问题出现。

1
2
3
4
5
6
7
onDestroy() {
if (this.inputElement) {
this.inputElement.removeEventListener('change', this.handleFileChange);
this.inputElement.remove();
this.inputElement = null;
}
}

将图片发送给服务器

我这里是将base64编码转成Uint8Array后再转成数组number[]发送给服务器的。

这里的数组一般会非常长~

1
2
3
4
5
6
private async base64ToUint8Array(base64DataURL: string) {
const res = await fetch(base64DataURL);
const blob = await res.blob();
const arrayBuffer = await blob.arrayBuffer();
return Array.from(new Uint8Array(arrayBuffer));
}
+