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'; 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); } }
|
触发监听事件
我这里是通过点击按钮触发的,点击按钮之后,会触发inputElement
的click
事件,然后inputElement
会触发change
事件,从而触发handleFileUpload
方法。
1 2 3
| HandlerBtn_selectImg(){ this.inputElement.click(); }
|
处理图片
这里我使用的是FileReader
来读取图片,然后通过FileReader
的onload
事件来获取图片的base64编码。由于图片过大,可能会导致图片上传到服务器失败,所以这里对图片进行了压缩,你也可以不压缩。
下面函数中的imageUrl
就是你选择图片的base64编码
。
1 2 3 4 5 6 7 8 9 10 11
| private handleFileUpload(file: File) { const reader = new FileReader(); 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
| 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)); }
|