图片裁切以及图片预览的过程:
1.图片裁切功能crop:(样式/更新)
网站:https://github.com/fengyuanchen/cropperjs
预览功能网站:https://fengyuanchen.github.io/cropperjs/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jcMYMTf6-1617323387035)(D:\项目笔记\732c9beeea86b44a9b7ed777a023d60.png)]
这个包是原生的js语言写的,可以用到各种语言中,包括vue,jquery,react都可以的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssuTezQi-1617323387040)(D:\项目笔记\fab9e4a479abfae73ae6f5d5f9a5979.png)]
使用步骤:
(1)打开终端,进行安装
npm install cropperjs
(2)example解释
-
Wrap the image or canvas element with a block element (container):意思是将图片或者是 canvas element(canvas元素)放到块级元素中
<!-- Wrap the image or canvas element with a block element (container) -->
<div>
<img id="image" src="picture.jpg">
</div>
代码演示:这是咱们预览图片的代码
但是要将其放到盒子中
<img width="150" :src="previewImage" alt="">
<div>
<img width="150" :src="previewImage" alt="">
</div>
2.Ensure the size of the image fit the container perfectly:确保图片的大小填充到容器中
给img设置一个样式,必须按照要求来
/* Ensure the size of the image fit the container perfectly */
img {
display: block;
/* This rule is very important, please don't ignore this */
max-width: 100%;
}
正确代码显示:
<div class="preview-image-wrap">
<img class="preview-image" :src="previewImage" alt="">
</div>
<style>
.preview-image-wrap .preview-image {
display: block;
max-width: 100%;
}
</style>
**效果显示:**图片完全填充上去了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEK8l0li-1617323387044)(D:\项目笔记\109d09eb28bd26eb25af176512b478f.png)]
(3)将下面两行代码引入到需要使用的页面
import 'cropperjs/dist/cropper.css';
import Cropper from 'cropperjs';
(4)初始化页面,还是复制代码
const image = document.getElementById('image');
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop(event) {
console.log(event.detail.x);
console.log(event.detail.y);
console.log(event.detail.width);
console.log(event.detail.height);
console.log(event.detail.rotate);
console.log(event.detail.scaleX);
console.log(event.detail.scaleY);
}
})
注意点:
(1)const image = document.getElementById(‘image’)这是获取图片的DOM节点,但是在vue中是通过ref来获取的,所以这里需要进行一下更改
const image = this.$refs['preview-image']
(2)下一步是初始化裁切器new了一个cropper,并把获取的DON当成参数给传了进去,这一步的作用是初始化裁切器
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop (event) {
console.log(event.detail.x)
console.log(event.detail.y)
console.log(event.detail.width)
console.log(event.detail.height)
console.log(event.detail.rotate)
console.log(event.detail.scaleX)
console.log(event.detail.scaleY)
}
})
(3)这串代码的位置:这串代码是等图片预览加载完之后才会起作用,这个就有讲究了
在和dialog配合使用的时候,dialog有个钩子函数opened
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%" :append-to-body="true" @opened="onDialogOpened">
<div class="preview-image-wrap">
<img class="preview-image" :src="previewImage" alt="" ref="preview-image">
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
methods: {
onDialogOpened () {
// const image = document.getElementById('image')这是获取图片的DOM节点,但是在vue中是通过ref来获取的,所以这里需要进行一下更改
const image = this.$refs['preview-image']
// 下一步是初始化裁切器new了一个cropper,并把获取的DON当成参数给传了进去,这一步的作用是初始化裁切器
const cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop (event) {
console.log(event.detail.x)
console.log(event.detail.y)
console.log(event.detail.width)
console.log(event.detail.height)
console.log(event.detail.rotate)
console.log(event.detail.scaleX)
console.log(event.detail.scaleY)
}
})
}
}
}
做到这一步出现一个问题:
就是预览的图片必须刷新一下,才可以选别的图片,接下来就是如何解决这个问题,原因是这个裁切器没有去更新
解决方法:
(1)裁切器.replace方法
首先进行一次判断
if (this.cropper) {
// replace
this.cropper.replace(this.previewImage)
return
}
onDialogOpened () {
if (this.cropper) {
// replace
this.cropper.replace(this.previewImage)
return
}
// const image = document.getElementById('image')这是获取图片的DOM节点,但是在vue中是通过ref来获取的,所以这里需要进行一下更改
const image = this.$refs['preview-image']
// 下一步是初始化裁切器new了一个cropper,并把获取的DON当成参数给传了进去,这一步的作用是初始化裁切器
this.cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop (event) {
console.log(event.detail.x)
console.log(event.detail.y)
console.log(event.detail.width)
console.log(event.detail.height)
console.log(event.detail.rotate)
console.log(event.detail.scaleX)
console.log(event.detail.scaleY)
}
})
},
(2)销毁裁切器,重新初始化
详解:关闭dialog之后,销毁这个裁切器,再次打开的时候就会重新初始化(用到dialog的一个方法closed)
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%" :append-to-body="true" @opened="onDialogOpened" @closed="onDialogClosed">
<div class="preview-image-wrap">
<img class="preview-image" :src="previewImage" alt="" ref="preview-image">
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
data () {
return {
cropper: null
}
}
methods: {
onSubmit () {
onDialogOpened () {
// const image = document.getElementById('image')这是获取图片的DOM节点,但是在vue中是通过ref来获取的,所以这里需要进行一下更改
const image = this.$refs['preview-image']
// 下一步是初始化裁切器new了一个cropper,并把获取的DON当成参数给传了进去,这一步的作用是初始化裁切器
this.cropper = new Cropper(image, {
aspectRatio: 16 / 9,
crop (event) {
console.log(event.detail.x)
console.log(event.detail.y)
console.log(event.detail.width)
console.log(event.detail.height)
console.log(event.detail.rotate)
console.log(event.detail.scaleX)
console.log(event.detail.scaleY)
}
})
},
onDialogClosed () {
// 对话框关闭,销毁裁切器
this.cropper.destroy()
}
}
}
一定要注意这两种更新方法是怎么进行的,位置放在哪里
2.裁切器的配置:
一;
(1)注释掉一些不用的代码比如crop (event)
(2) aspectRatio: 16 / 9这是用来调整裁切的比例的
onDialogOpened () {
if (this.cropper) {
// replace
this.cropper.replace(this.previewImage)
return
}
// const image = document.getElementById('image')这是获取图片的DOM节点,但是在vue中是通过ref来获取的,所以这里需要进行一下更改
const image = this.$refs['preview-image']
// 下一步是初始化裁切器new了一个cropper,并把获取的DON当成参数给传了进去,这一步的作用是初始化裁切器
this.cropper = new Cropper(image, {
// aspectRatio这是裁切器的比例 16 :9
// 当你移动裁切器的时候会触发调用方法crop方法,但是我们不怎么用,所以给注释掉了
aspectRatio: 16 / 9,
// crop (event) {
// console.log(event.detail.x)
// console.log(event.detail.y)
// console.log(event.detail.width)
// console.log(event.detail.height)
// console.log(event.detail.rotate)
// console.log(event.detail.scaleX)
// console.log(event.detail.scaleY)
// }
})
}
二;属性
(1)viewMode:限制画布和容器之间的关系
(2)dragMode:裁切区域形成的模式,一般选为none
封装好的属性:注意这些属性写的位置
onDialogOpened () {
if (this.cropper) {
// replace
this.cropper.replace(this.previewImage)
return
}
const image = this.$refs['preview-image']
this.cropper = new Cropper(image, {
// aspectRatio这是裁切器的比例 16 :9
aspectRatio: 16 / 9,
viewMode: 1,
dragMode: 'none',
// cropBoxMovable意思是不允许改变裁切器的大小,就是1:1
cropBoxMovable: true,
// background裁切器的背景
background: false
// }
})
}
3.图片裁切-获取裁切的结果
通过方法getCroppedCanvas()
此处的file是经过裁切之后获得的图片结果
this.user.photo = res.data.data.photo渲染的时候这个方法有些慢
onUpdatePhoto () {
// 获取裁切的图片对象
this.cropper.getCroppedCanvas().toBlob(file => {
const fd = new FormData()
fd.append('photo', file)
// 请求提交 fd
updateUserPhoto(fd).then(res => {
// 关闭对话框
this.dialogVisible = false
// 更新视图展示
this.user.photo = res.data.data.photo
})
})
第二种方法
this.user.photo = window.URL.createObjectURL(this)
这是本地有裁切结果,这样做速度更快一点
```javascript
onUpdatePhoto () {
// 获取裁切的图片对象
this.cropper.getCroppedCanvas().toBlob(file => {
const fd = new FormData()
fd.append('photo', file)
// 请求提交 fd
updateUserPhoto(fd).then(res => {
// 关闭对话框
this.dialogVisible = false
// 更新视图展示
this.user.photo = window.URL.createObjectURL(this)
// this.user.photo = res.data.data.photo
})
})
// 请求更新用户头像
// 关闭对话框
// 更新视图的展示
}
图片预览的操作过程
思路:通过input标签的file类型拿到图片,然后再把图片给了电脑本地,然后电脑本地再通过途径src给了img标签
(1)写出type=“file”的input标签
```javascript
<input type="file" @change="onFileChange" ref="file">
(2)在input标签下写上一个img标签
每个标签都有一个ref,这是vue操作dom的方式
<input type="file" @change="onFileChange" ref="file">
<img width="100" ref="preview-image">
(3)给input绑定一个change事件,当发生改变的时候会触发的事件
代码解释:
1.获取input的文件对象
this.
r
e
f
s
.
f
i
l
e
是
用
来
操
作
i
n
p
u
t
的
d
o
m
,
.
f
i
l
e
s
[
0
]
就
可
以
拿
到
图
片
文
件
了
c
o
n
s
t
f
i
l
e
=
t
h
i
s
.
refs.file是用来操作input的dom,.files[0]就可以拿到图片文件了 const file = this.
refs.file是用来操作input的dom,.files[0]就可以拿到图片文件了constfile=this.refs.file.files[0]
2.将图片给了电脑本地
const blob = window.URL.createObjectURL(file)
3.再将本地的电脑图片给了img的src标签
this.
r
e
f
s
[
′
p
r
e
v
i
e
w
−
i
m
a
g
e
′
]
.
s
r
c
=
b
l
o
b
4.
为
了
防
止
用
户
选
择
同
一
个
文
件
时
,
不
触
发
事
件
,
将
i
n
p
u
t
标
签
中
的
内
容
进
行
清
空
t
h
i
s
.
refs['preview-image'].src = blob 4.为了防止用户选择同一个文件时,不触发事件,将input标签中的内容进行清空 this.
refs[′preview−image′].src=blob4.为了防止用户选择同一个文件时,不触发事件,将input标签中的内容进行清空this.refs.file.value = ‘’
onFileChange () {
// 获取文件对象
const file = this.$refs.file.files[0]
// 图片预览
// window.URL.createObjectURL(file)目的是为了将文件对象传进去
const blob = window.URL.createObjectURL(file)
// this.$refs['preview-image']是为了拿到图片的dom
this.$refs['preview-image'].src = blob
// 防止用户选择同一个文件,不触发事件
// this.$refs.file这个操作拿到的input的dom
this.$refs.file.value = ''
}