使用Vue-Cropper这一组件实现头像上传,供大家参考,具体内容如下
效果展示
先看一下效果吧,如果效果不能满足你的需求,就不必再浪费时间往下看了
点击选择图片之后
然后再点击上传图片就可以上传成功,具体效果和页面布局就是这样
前端代码
使用先建议详细阅读vue-cropper官方文档,里面介绍的很详细,可以根据自己的需求进行修改:链接
补充一点:整个项目中使用了elelment-ui组件库,使用前先导入element-ui
关于解释我会在代码中添加注释,毕竟知其然要知其所以然,学习还是得有溯源精神
<template>
<div style="height: 800px;">
<el-tabs v-model="activeName" @tab-click="handleClick" class="tabs">
<el-tab-pane label="个人信息" name="first">
</el-tab-pane>
<el-tab-pane label="更换头像" name="second">
<div class="avatar_header">
<span>当前头像</span>
</div>
<div class="avatar_current">
<img :src="currentimg">
</div>
<div class="avatar_select">
<!-- 这里这样做是因为
原来的 <input type="file">标签太丑了,可以自己去尝试一下,看看有多丑
所以使用button来控制触发input来进行选择文件
-->
<input type="file" ref="uploads" id="uploads" accept="image/png, image/jpeg, image/gif, image/jpg" hidden @change="setImage($event)">
<el-button type="primary" @click="selectAvatar">选择图片</el-button>
<el-button type="success" style="margin-left:100px;" @click="uploadImg('blob')">上传图片</el-button>
</div>
<div class="cropper_box">
<div class="avatar_cropper">
<vue-cropper
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:full="option.full"
:fixedBox="option.fixedBox"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:centerBox="option.centerBox"
:height="option.height"
:infoTrue="option.infoTrue"
:maxImgSize="option.maxImgSize"
:enlarge="option.enlarge"
:mode="option.mode"
@realTime="realTime"
@imgLoad="imgLoad">
</vue-cropper>
</div>
<div class="show_preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden',
'margin': '5px'}">
<div :style="previews.div">
<img :src="option.img" :style="previews.img">
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="修改密码" name="third">
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import qs from 'qs'
import { VueCropper } from 'vue-cropper'
export default {
data() {
return {
activeName:'second',
currentimg:this.$store.getters.getAvatar, //这里我是将用户信息保存在Vuex进行管理
previews:{},
option:{
img:'', //裁剪图片的地址,
outputSize:1, //裁剪生成的图片质量可选(0,1,-1)
outputType:'jpeg', //裁剪生成图片的格式
info:true, //图片大小信息
canScale:true, //是否允许滚轮缩放
autoCrop:true, //是否默认生成截图框
autoCropWidth:240,
autoCropHeight:240, //默认生成截图框大小
fixed:true, //是否开启截图框宽高固定比例
fixedNumber:[1,1], //截图框的宽高比,
full:false, //按原比例裁剪图片,不失真
fixedBox:true, //固定截图框大小,不允许改变
canMove:false, //上传图片是否可以移动,
canMoveBox:true, //截图框是否可以拖动
original:false, //上传图片按照原始比例渲染
centerBox:false, //截图框是否被限制在图片里面
height:true, //是否按照设备的dpr,输出等比例图片
infoTrue:false, //true为展示真实输出图片宽高,false展示看到的截图框宽高,
maxImgSize:3000, //限制图片最大宽度和高度
enlarge:1, //图片根据截图框输出比例倍数
mode:'400px 300px' //图片渲染方式
}
}
},
methods: {
// 标签页切换调用方法,不重要!删掉了一些不必要的代码
handleClick(){
},
// 选择图片调用方法
selectAvatar(){
this.$refs.uploads.click();
},
// 真正的选择图片方法,姑且先这么命名吧
setImage(e){
let file = e.target.files[0];
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
// this.$message.info("图片类型不正确");
console.log("图片类型不正确");
return false;
}
//转化为blob,使用blob是为了在页面中展示上传的那张图片
let reader = new FileReader();
// 文件读取成功后触发onload方法
reader.onload = (e) => {
let data;
// 要在页面中展示,转化为url形式
if(typeof e.target.result === 'object'){
data = window.URL.createObjectURL(new Blob([e.target.result]))
}else{
data = e.target.result
}
this.option.img = data
//转化为base64
}
reader.readAsDataURL(file)
},
realTime(data){
this.previews = data;
},
//初始化函数
imgLoad(msg){
console.log("工具初始化函数====="+msg);
},
// 头像上传调用方法
uploadImg(type){
let _this = this;
if(type === 'blob'){
//获取截图的blob数据类型
this.$refs.cropper.getCropBlob(async (data) => {
let formData = new FormData();
// 发数据传递到后端,注意这里请根据自己的后端逻辑进行处理,我是将用户名保存在Vuex中,可以直接进行命名
formData.append("username",this.$store.getters.getUsername);
formData.append('file',data,this.$store.getters.getUsername+".jpg");
this.axios.post('/updateavatar',formData).then(function(response){
console.log(response);
if(response.data.code == 200){
console.log(response);
_this.currentimg = response.data.data;
_this.$store.commit('setAvatar',response.data.data); //把新头像重新保存回Vuex
_this.$router.go(0); //刷新网页
}
})
})
}
}
},
components:{VueCropper}
};
</script>
<style scoped>
.tab-create{
position: absolute;
right: 80px;
top: 115px;
margin-top: 5px;
z-index: 999;
}
.avatar_header{
width: 100%;
height: 50px;
font-size: 14;
line-height: 50px;
font-weight: 550;
padding-left: 20px;
text-align: left;
}
.avatar_current{
width: 100%;
height: 260px;
text-align: left;
}
.avatar_current img{
width: 240px;
height: 240px;
margin-left: 20px;
}
.avatar_select{
text-align: left;
}
.cropper_box{
text-align: left;
position: relative;
}
.avatar_cropper{
margin-top: 40px;
height: 350px;
width: 450px;
display: inline-block;
}
.show_preview{
display: inline-block;
position: absolute;
top:30px;
left: 500px;
}
</style>
后端代码
这里先讲述后端的处理逻辑:
1、获取到头像后,会将图片保存在云服务器上,这里我们设定的自己的静态文件目录在D盘,见static_root。
2、然后将图片在云服务器上的url保存在后端mysql数据库中。
3、返回给前端上传成功的消息,携带图片的url这样就可以通过url访问到这张图片,从而在前端进行显示。
Controller层
@ResponseBody
@PostMapping("/updateavatar")
public Result updateAvatar(@RequestParam("username") String username,@RequestParam("file") MultipartFile file) throws IOException {
return userService.uploadAvatar(username,file);
}
Service层直接上impl实现
//这是导的工具包,需要在pom.xml安装依赖
import cn.hutool.core.io.FileUtil;
//一些端口信息
@Value("${server.port}")
private String port;
private static final String ip = "http://localhost";
private static final String static_root = "D:/devplatform_files";
@Override
public Result uploadAvatar(String username, MultipartFile file) throws IOException {
//获取原文件的名称
String originalFilename = file.getOriginalFilename();
// String rootFilePath = System.getProperty("user.dir")+"/src/main/resources/files/"+originalFilename;
//获取到文件路径
String rootFilePath = static_root +"/avatar/"+ originalFilename;
//保存在文件中
FileUtil.writeBytes(file.getBytes(),rootFilePath);
//图片访问用到的url
String avatar = ip+":"+port+"/avatar/"+originalFilename;
try{
//头像信息存入数据库
userMapper.updateAvatar(avatar,username);
//自己封装的Result结果返回类
return Result.success(200,"上传成功",avatar);
}catch (Exception e){
System.out.println(e);
return Result.fail("上传失败");
}
}
mapper持久层
@Mapper
@Repository
public interface UserMapper{
String getAvatarByUsername(String username);
}
mapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.devplatform.mapper.UserMapper">
<update id="updateAvatar">
update user set avatar = #{avatar} where username = #{username}
</update>
</mapper>
关于Result结果类的封装
public class Result {
private int code; //200是正常 非200表示异常
private String msg;
private Object data;
public static Result success(Object data){
return success(200,"操作成功",data);
}
public static Result success(String msg){
return success(200,msg,null);
}
public static Result success(int code, String msg, Object data){
Result r = new Result();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
public static Result fail(String msg){
return fail(400, msg, null);
}
public static Result fail(String msg, Object data){
return fail(400, msg, data);
}
public static Result fail(int code, String msg, Object data){
Result r = new Result();
r.setCode(code);
r.setData(data);
r.setMsg(msg);
return r;
}
public int getCode() {return code;}
public void setCode(int code) {this.code = code;}
public String getMsg() {return msg;}
public void setMsg(String msg) {this.msg = msg;}
public Object getData() {return data;}
public void setData(Object data) {this.data = data;}
}
当图片保存在云服务器上后,就可以通过url直接访问到图片了,这里我本地展示这一效果,实现了这一效果,前端才能够在img标签中访问到图片。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。