v-avatar-cropper
Version:
Support cutting of avatars of PC and mobile phones.
356 lines (270 loc) • 7.77 kB
Markdown
# V Avatar Cropper

一个支持 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)
---
如果这个项目对你有帮助,请给个 ⭐️ 支持一下!