// 头像组件逻辑 Component({ properties: { // 头像URL avatarUrl: { type: String, value: '' }, // 头像尺寸(rpx) size: { type: Number, value: 120 }, // 占位符文本 placeholderText: { type: String, value: '👤' }, // 占位符文本大小 textSize: { type: Number, value: 40 }, // 是否可编辑 editable: { type: Boolean, value: false }, // 头像形状:circle(圆形)或 square(方形) shape: { type: String, value: 'circle' }, // 是否显示边框 bordered: { type: Boolean, value: false }, // 是否显示阴影 shadow: { type: Boolean, value: false } }, data: { showAvatarModal: false // 是否显示头像选择弹窗 }, methods: { // 头像点击事件 onAvatarTap() { if (this.properties.editable) { this.showAvatarModal(); } this.triggerEvent('tap', { avatarUrl: this.properties.avatarUrl }); }, // 显示头像选择弹窗 showAvatarModal() { this.setData({ showAvatarModal: true }); }, // 隐藏头像选择弹窗 hideAvatarModal() { this.setData({ showAvatarModal: false }); }, // 拍照 takePhoto() { this.hideAvatarModal(); wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: ['camera'], camera: 'front', success: (res) => { if (res.tempFiles && res.tempFiles.length > 0) { this.processImage(res.tempFiles[0].tempFilePath); } }, fail: (err) => { console.error('拍照失败:', err); wx.showToast({ title: '拍照失败', icon: 'none' }); } }); }, // 从相册选择 chooseImage() { this.hideAvatarModal(); wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: ['album'], success: (res) => { if (res.tempFiles && res.tempFiles.length > 0) { this.processImage(res.tempFiles[0].tempFilePath); } }, fail: (err) => { console.error('选择图片失败:', err); wx.showToast({ title: '选择图片失败', icon: 'none' }); } }); }, // 使用默认头像 useDefaultAvatar() { this.hideAvatarModal(); // 触发默认头像选择事件 this.triggerEvent('change', { avatarUrl: '', isDefault: true }); }, // 处理图片 processImage(tempFilePath) { wx.showLoading({ title: '处理中...' }); // 压缩图片 wx.compressImage({ src: tempFilePath, quality: 80, success: (res) => { // 裁剪图片为正方形 this.cropImage(res.tempFilePath); }, fail: (err) => { console.error('图片压缩失败:', err); wx.hideLoading(); wx.showToast({ title: '图片处理失败', icon: 'none' }); } }); }, // 裁剪图片 cropImage(tempFilePath) { // 获取图片信息 wx.getImageInfo({ src: tempFilePath, success: (infoRes) => { const { width, height } = infoRes; const size = Math.min(width, height); const x = (width - size) / 2; const y = (height - size) / 2; // 创建画布进行裁剪 const ctx = wx.createCanvasContext('avatar-canvas'); // 绘制圆形裁剪区域 ctx.save(); ctx.beginPath(); ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI); ctx.clip(); // 绘制图片 ctx.drawImage(tempFilePath, x, y, size, size, 0, 0, size, size); ctx.restore(); // 将画布内容导出为图片 ctx.draw(false, () => { wx.canvasToTempFilePath({ canvasId: 'avatar-canvas', success: (canvasRes) => { wx.hideLoading(); // 触发头像改变事件 this.triggerEvent('change', { avatarUrl: canvasRes.tempFilePath, isDefault: false }); }, fail: (err) => { console.error('画布导出失败:', err); wx.hideLoading(); wx.showToast({ title: '头像处理失败', icon: 'none' }); } }); }); }, fail: (err) => { console.error('获取图片信息失败:', err); wx.hideLoading(); wx.showToast({ title: '图片处理失败', icon: 'none' }); } }); }, // 生成头像缩略图 generateThumbnail(avatarUrl, size = 60) { return new Promise((resolve, reject) => { if (!avatarUrl) { resolve(''); return; } wx.getImageInfo({ src: avatarUrl, success: (infoRes) => { const ctx = wx.createCanvasContext('thumbnail-canvas'); // 绘制圆形缩略图 ctx.save(); ctx.beginPath(); ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI); ctx.clip(); ctx.drawImage(avatarUrl, 0, 0, size, size); ctx.restore(); ctx.draw(false, () => { wx.canvasToTempFilePath({ canvasId: 'thumbnail-canvas', destWidth: size, destHeight: size, success: (res) => { resolve(res.tempFilePath); }, fail: (err) => { reject(err); } }); }); }, fail: reject }); }); } } });