近日前端项目中,需要实现上传图片、支持自定义裁剪,生成海报的功能。该项目采用Taro(react语法)实现。具体实现步骤如下:
1、插件安装
yarn add cropperjs -S
2、引入
在项目中引入cropperjs,一定不要忘记引入样式
import Cropper from "cropperjs"
import "cropperjs/dist/cropper.css"
3、代码实现
import Taro, { Component } from "@tarojs/taro"
import { View, Image, Button } from "@tarojs/components"
import * as Api from "@/api/light"
import { to } from "@/utils/router"
import { toast } from "@/utils/feedBack"
import { lightShare } from "@/utils/share"
import "./index.less"
import Cropper from "cropperjs"
import "cropperjs/dist/cropper.css"
export default class Index extends Component {
state = {
picture_img: "",
afterImg: "", // 确认裁剪的图片
produceImg: "", // 生成图片
myCropper: null,
isUpload: false, // 是否已上传图片
isCreated: false // 是否已裁剪生成图片
}
componentDidShow() {
const { code = "" } = this.$router.params
lightShare({
link: `${window.location.href
.split("?")[0]
.replace("makePoster", "light")}?code=${code}`
})
}
componentDidMount() {
const options = {
viewMode: 1,
dragMode: "none",
initialAspectRatio: 1,
aspectRatio: 0.8, // 设置宽高比例
preview: ".before",
background: true, //显示容器的网格背景。(就是后面的马赛克)
autoCropArea: 0.6,
zoomOnWheel: false,
ready: () => {
const { width, height } = this.myCropper.getContainerData(). // 获取上传图片宽高信息
this.myCropper.setCropBoxData({ // 设置裁剪区域(初始设置最大裁剪区域)
width,
left: 0,
top: 0
})
}
}
this.myCropper = new Cropper(this.img.imgRef, options)
}
toBack = () => {
to({ name: "light" })
}
// 上传图片
onPicture = async () => {
Taro.chooseImage({
count: 1,
success: res => {
this.setState({
picture_img: res.tempFilePaths[0],
isUpload: true
})
},
fail: e => {
console.log(e)
}
})
}
// 生成海报
createPoster = async () => {
const { picture_img, afterImg, isCreated, produceImg } = this.state
if (!picture_img) return toast("请上传照片!")
const { base_url, img_url } = await Api.sharePoster({
avatar_base64: afterImg
})
this.setState({
produceImg: base_url + img_url,
isCreated: true,
isUpload: true
})
}
// 取消
onCancel = () => {
const { isUpload } = this.state
this.setState({
isUpload: false,
picture_img: ""
})
}
// 确认裁剪
onConfirm = () => {
const pic = this.myCropper
.getCroppedCanvas({
imageSmoothingQuality: "high"
})
.toDataURL("image/jpeg")
this.setState({
afterImg: pic,
isUpload: false
})
}
render() {
const {
picture_img,
isUpload,
afterImg,
isCreated,
produceImg
} = this.state
return (
<View className="container">
{!produceImg && isUpload ? (
<View className="poster-mask">
{/* 裁剪区域 */}
<View className="img-container">
<Image
className="img-area"
src={picture_img}
// src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fa%2F53f550c675dd9.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1631435691&t=8ef60ec374e799bf4cfb4f3b83b9bb9b"
ref={img => {
this.img = img
}}
/>
</View>
{/* 按钮 */}
<View className="btn-wrap">
<Button className="back btn" onClick={this.onCancel}>
取消
</Button>
<Button className="make btn" onClick={this.onConfirm}>
确认裁剪
</Button>
</View>
</View>
) : (
<View className="poster-img-container">
{produceImg && isCreated ? (
<Image src={produceImg} className="poster_img" />
) : (
<View className="make-poster-container">
{/* 上传海报 */}
<View className="poster-content">
<View className="picture-content">
<View
className="generate-img"
style={
afterImg
? { backgroundImage: `url(${afterImg})` }
: { backgroundImage: `url(${picture_img})` }
}
>
<View
className="caream-wrap"
onClick={this.onPicture.bind(this)}
>
<View className="upload-btn">
<Image
src="https://img1.halobear.com/upload_page/Fstl6Jkaul8GGuwkweGnxKq02wFs.png"
className="camera"
/>
<View className="add">
{afterImg ? "替换" : "添加"}照片
</View>
</View>
</View>
</View>
</View>
</View>
{/* 按钮 返回首页、生成海报 */}
<View className="btn-wrap">
<Button className="back btn" onClick={this.toBack}>
返回首页
</Button>
<Button className="make btn" onClick={this.createPoster}>
生成海报
</Button>
</View>
</View>
)}
</View>
)}
</View>
)
}
}
4、效果图
5、常用参数options
1、viewMode —— 定义cropper的视图模式
(https://img-blog.csdnimg.cn/8e0ab5f02ad34b298a8d72a6e58a089b.png)
类型: Number;默认:0;
0: 无限制 (3可以移动到2外)
1: 限制裁剪框不超过画布的大小。(3只能在2内移动)
2:限制最小画布大小以适合容器。如果画布和容器的比例不同,则最小画布将被维度之一的额外空间包围。(2不全部铺满1)
3:限制最小画布尺寸以填充适合容器。如果画布和容器的比例不同,容器将无法在其中一个维度中容纳整个画布。 (2整个填充1)
2、dragMode —— 定义cropper的拖拽模式。
类型: String;默认:'crop'
'crop': 创建一个新的裁剪框
'move': 移动画布
'none': 没做什么
3、aspectRatio —— 定义裁剪框的宽高比
类型: Number;默认: NaN
定义裁剪框的初始纵横比。默认情况下,它与画布(图像包装器)的纵横比相同。
4、background —— 显示容器的网格背景(就是后面的马赛克)
类型: Boolean;默认: true
5、modal —— 显示图片上方的黑色模态并在裁剪框下面。
类型: Boolean;默认: true
6、guides —— 显示在裁剪框内的虚线。
类型: Boolean;默认: true
7、autoCrop —— 当初始化时,可以自动生成图像。(就是自动显示裁剪框,改成false裁剪框自动消失)
类型: Boolean;默认: true
8、autoCropArea —— 自动裁剪区域
类型: Number;默认值:(0.8图像的 80%)
它是一个介于 0 和 1 之间的数字。定义自动裁剪区域大小(百分比)。
9、ready —— 插件准备完成执行的函数(只执行一次)
类型: Function;默认: null
5、常用方法
1、getContainerData() —— 输出容器大小数据
类型: Object
width: 容器的当前宽度 ;height: 容器的当前高度
2、getData([rounded]) —— 输出最终裁剪的区域位置和大小数据
https://img-blog.csdnimg.cn/0092151f621d4346a3081ccd6ac53321.png
rounded 类型:Boolean 默认:false;设置true可以获取其所有数据;
返回的数据类型:Object;
- x裁切框距离左边的距离
- y裁切框距离顶部的距离
- width裁切框的宽度
- height裁切框的高度
- rotate裁切框的旋转的角度
- scaleX缩放图像的横坐标
- scaleY缩放图像的纵坐标
3、setData(data) —— 用新数据改变裁切区域的位置和大小(以原始图像为基础)。
data类型: Object
4、setCropBoxData —— 输出剪切框的位置和大小数据
返回的数据类型:Object;
- left剪切框距离左边的距离
- top剪切框距离顶部的距离
- width剪切框的宽度
- height剪切框的高度
6 、结尾
以上内容为本次项目中所涉及和掌握到的常用参数和方法,更多参数和方法可以自行去cropperjs文档深入了解和学习。
文档链接:cropperjs
.