UNPKG

v-avatar-cropper

Version:

Support cutting of avatars of PC and mobile phones.

356 lines (270 loc) 7.77 kB
# V Avatar Cropper ![演示动图](https://github.com/varjay/avatar-crop/raw/master/public/img/demo.gif) 一个支持 PC 端和移动端的 Vue 3 头像裁剪组件,提供直观的拖拽、缩放和裁剪功能。 ## ✨ 特性 - 🖱️ **直观操作** - 支持鼠标拖拽和触摸手势 - 🔍 **灵活缩放** - 双指缩放和滑块缩放 - 📱 **响应式设计** - 自适应不同屏幕尺寸 - 🎨 **现代 UI** - 简洁美观的用户界面 - 📦 **轻量级** - 无外部依赖,体积小巧 - 🔧 **易于集成** - 简单的 API 设计 ## 📦 安装 ```bash npm install v-avatar-cropper --save ``` ## 🚀 快速开始 ### 全局注册 ```javascript import {createApp} from 'vue' import avatar from 'v-avatar-cropper' import App from './App.vue' const app = createApp(App) app.use(avatar) app.mount('#app') ``` ### 局部引入 ```javascript import VAvatarCropper from 'v-avatar-cropper' export default { components: { VAvatarCropper, }, } ``` ### 基础用法 ```vue <template> <div> <!-- 文件选择 --> <input type="file" @change="handleFileChange" accept="image/*" /> <!-- 头像裁剪组件 --> <v-avatar-cropper v-if="selectedFile" :file="selectedFile" @cancel="handleCancel" @done="handleDone" /> </div> </template> <script setup> import {ref} from 'vue' const selectedFile = ref(null) function handleFileChange(event) { selectedFile.value = event.target.files[0] } function handleCancel() { selectedFile.value = null } function handleDone(result) { console.log('裁剪完成:', result) // result.base64 - base64格式图片 // result.img - Blob格式图片 // result.url - Blob URL地址 selectedFile.value = null } </script> ``` ## 📖 API 文档 ### Props | 参数 | 类型 | 默认值 | 说明 | | ---- | -------------- | ------ | ---------------------------------- | | file | File \| String | null | 要裁剪的图片文件或图片 URL | | edit | Boolean | true | 是否显示编辑界面(操作按钮和滑块) | ### Events | 事件名 | 参数 | 说明 | | ------ | -------------- | ---------------------- | | cancel | - | 用户点击取消按钮时触发 | | done | result: Object | 用户确认裁剪时触发 | | touch | - | 用户触摸图片时触发 | ### Done 事件返回值 ```javascript { base64: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...', // base64格式图片 img: Blob, // Blob格式图片对象 url: 'blob:http://localhost:3000/xxx-xxx-xxx' // Blob URL地址 } ``` ## 🎮 使用示例 ### 完整示例 ```vue <template> <div class="avatar-demo"> <!-- 上传区域 --> <div v-if="!currentFile" class="upload-area"> <label for="file-input" class="upload-button"> 选择头像图片 </label> <input id="file-input" type="file" @change="selectFile" accept="image/*" style="display: none;" /> </div> <!-- 裁剪组件 --> <v-avatar-cropper v-if="currentFile" :file="currentFile" @cancel="cancelCrop" @done="completeCrop" @touch="onImageTouch" /> <!-- 结果展示 --> <div v-if="croppedResult" class="result-area"> <h3>裁剪结果</h3> <img :src="croppedResult.url" alt="裁剪后的头像" class="result-image" /> <div class="result-actions"> <button @click="downloadImage">下载图片</button> <button @click="resetDemo">重新选择</button> </div> </div> </div> </template> <script setup> import {ref} from 'vue' const currentFile = ref(null) const croppedResult = ref(null) // 选择文件 function selectFile(event) { const file = event.target.files[0] if (file) { currentFile.value = file } } // 取消裁剪 function cancelCrop() { currentFile.value = null } // 完成裁剪 function completeCrop(result) { croppedResult.value = result currentFile.value = null // 可以在这里上传到服务器 // uploadToServer(result.img) } // 图片触摸事件 function onImageTouch() { console.log('用户触摸了图片') } // 下载图片 function downloadImage() { if (croppedResult.value) { const link = document.createElement('a') link.download = 'avatar.jpg' link.href = croppedResult.value.url link.click() } } // 重置演示 function resetDemo() { croppedResult.value = null // 清空文件输入 const input = document.getElementById('file-input') if (input) input.value = '' } </script> <style scoped> .avatar-demo { max-width: 500px; margin: 0 auto; padding: 20px; } .upload-area { text-align: center; padding: 40px; border: 2px dashed #ddd; border-radius: 8px; } .upload-button { display: inline-block; padding: 12px 24px; background: #007bff; color: white; border-radius: 6px; cursor: pointer; transition: background 0.3s; } .upload-button:hover { background: #0056b3; } .result-area { text-align: center; margin-top: 20px; } .result-image { width: 200px; height: 200px; border-radius: 50%; object-fit: cover; border: 3px solid #007bff; } .result-actions { margin-top: 15px; } .result-actions button { margin: 0 10px; padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; } </style> ``` ### 仅预览模式 ```vue <template> <v-avatar-cropper :file="imageUrl" :edit="false" /> </template> <script setup> const imageUrl = 'https://example.com/avatar.jpg' </script> ``` ## 🎯 操作指南 ### PC 端操作 - **拖拽移动**: 鼠标按住图片拖拽 - **缩放调节**: 使用底部滑块调节缩放比例 - **确认裁剪**: 点击"确认"按钮完成裁剪 - **取消操作**: 点击"取消"按钮退出裁剪 ### 移动端操作 - **单指拖拽**: 单指触摸拖拽移动图片位置 - **双指缩放**: 双指捏合/展开调节图片大小 - **滑块缩放**: 使用底部滑块精确调节缩放 - **触摸确认**: 点击"确认"按钮完成裁剪 ## ⚙️ 技术特性 ### 核心功能 - **智能适配**: 自动适配图片尺寸和屏幕大小 - **边界检测**: 防止图片移出裁剪区域 - **平滑动画**: 流畅的交互动画效果 - **内存管理**: 自动清理 Blob URL,防止内存泄漏 ### 兼容性 - **Vue 版本**: Vue 3.x - **浏览器**: 现代浏览器 (Chrome, Firefox, Safari, Edge) - **移动端**: iOS Safari, Android Chrome - **触摸支持**: 完整的触摸手势支持 ## 🔧 开发指南 ### 本地开发 ```bash # 克隆项目 git clone https://github.com/varjay/avatar-crop.git # 安装依赖 cd avatar-crop npm install # 启动开发服务器 npm run dev # 构建项目 npm run build # 代码检查 npm run lint ``` ### 项目结构 ``` avatar-crop/ ├── lib/ # 组件源码 │ ├── index.js # 入口文件 │ └── components/ │ └── avatar.vue # 主组件 ├── src/ # 示例代码 │ ├── App.vue # 示例应用 │ └── main.js # 入口文件 ├── public/ # 静态资源 └── package.json # 项目配置 ``` ## 🤝 贡献指南 欢迎提交 Issue 和 Pull Request 来帮助改进这个项目! ### 提交 Issue - 详细描述问题和复现步骤 - 提供浏览器和设备信息 - 如果可能,请提供最小复现示例 ### 提交 PR - Fork 项目并创建特性分支 - 确保代码通过 ESLint 检查 - 添加必要的测试用例 - 更新相关文档 ## 📄 许可证 [ISC License](LICENSE) ## 👨‍💻 作者 **virjay** - [GitHub](https://github.com/varjay) --- 如果这个项目对你有帮助,请给个 ⭐️ 支持一下!