vue3实现图片裁剪上传功能

news2024/10/6 6:52:40

1、安装引入vue-cropper(可参考:https://www.npmjs.com/package/vue-cropper)

        npm install vue-cropper@next
        import 'vue-cropper/dist/index.css'
        import { VueCropper }  from "vue-cropper";
2、组件完整代码
<template>
  <div class="avatar-container" @click="editImage()">
    <img :src="options.img" title="点击上传" class="img-box" />
    <el-dialog title="裁剪图片" v-model="dialogVisible" width="800px" append-to-body @opened="openDialog" @close="closeDialog">
      <el-row>
        <el-col :span="12" style="height: 300px;">
          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            :outputType="options.outputType"
            @realTime="realTime"
            v-if="showCropper"
          />
        </el-col>
        <el-col :span="12" style="height: 300px;">
          <div class="preview-box">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>
      </el-row>
      <el-row style="margin-top: 12px;">
        <el-col :span="12">
          <el-row>
            <el-col :span="8">
              <el-upload
                action="#"
                :http-request="() => {}"
                :before-upload="beforeUpload"
                :show-file-list="false"
              >
                <el-button>选择</el-button>
              </el-upload>
            </el-col>
            <el-col :span="4">
              <el-button :icon="Plus" @click="changeScale(1)"></el-button>
            </el-col>
            <el-col :span="4">
              <el-button :icon="Minus" @click="changeScale(-1)"></el-button>
            </el-col>
            <el-col :span="4">
              <el-button :icon="RefreshLeft" @click="rotateLeft()"></el-button>
            </el-col>
            <el-col :span="4">
              <el-button :icon="RefreshRight" @click="rotateRight()"></el-button>
            </el-col>
          </el-row>
        </el-col>
        <el-col :span="4" :offset="8">
          <el-button type="primary" @click="uploadImg()">提 交</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { Plus, Minus, RefreshLeft, RefreshRight } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { uploadImage } from "@/api/target/manage";
import "vue-cropper/dist/index.css";
import { VueCropper } from "vue-cropper";

const { proxy } = getCurrentInstance();
const props = defineProps({
	dataInfo: {
		type: Object,
		default: {}
	}
})
const dialogVisible = ref(false);
const showCropper = ref(false);
// cropper配置  更多配置可参考 https://www.npmjs.com/package/vue-cropper
const options = reactive({
  img: props.dataInfo.img, // 裁剪图片的地址
  autoCropWidth: 200, // 默认生成截图框宽度 默认容器的 80%
  autoCropHeight: 200, // 默认生成截图框高度 默认容器的 80%
  outputType: "png", // 裁剪生成图片的格式 jpeg, png, webp
  autoCrop: true, // 是否默认生成截图框
  fixedBox: false, // 固定截图框大小
});
const previews = ref({
  url: ''
})

watch(
	() => props.dataInfo,
	() => {
    options.img = props.dataInfo.img;
	},
	{ deep: true, immediate: true }
)

// 编辑图片
const editImage = () => {
  dialogVisible.value = true;
}

// 打开裁剪弹窗
const openDialog = () => {
  showCropper.value = true;
}
// 修改图片大小 正数为变大 负数变小
const changeScale = (num: number) => {
  num = num || 1;
  proxy.$refs.cropper.changeScale(num);
}
// 向左边旋转90度
const rotateLeft = () => {
  proxy.$refs.cropper.changeScale();
}
// 向右边旋转90度
const rotateRight = () => {
  proxy.$refs.cropper.rotateRight();
}
// 上传图片处理
const beforeUpload = (rawFile: any) => {
  if (rawFile.type.indexOf("image/") == -1) {
    ElMessage.error('请上传图片类型文件!')
    return false
  }
  if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('文件大小不能超过2MB!')
    return false
  }
  const reader = new FileReader();
  reader.readAsDataURL(rawFile);
  reader.onload = () => {
    options.img = reader.result;
  };
}
// 上传图片
const uploadImg = () => {
  proxy.$refs.cropper.getCropBlob((data: any) => {
    let formData = new FormData();
    formData.append("file", data);
    let params = {
      id: 1
    }
    uploadImage(params, formData).then((res: any) => {
      if(res.code == 200) {
        options.img = res.data;
        props.dataInfo.img = options.img;
        showCropper.value = false;
        dialogVisible.value = false;
        ElMessage.success("上传成功!");
      } else {
        ElMessage.error(res.message || '上传失败!')
      }
    });
  });
}
// 实时预览事件
const realTime = (data: any) => {
  previews.value = data;
}
// 关闭弹窗
const closeDialog = () => {
  options.img = props.dataInfo.img;
}
</script>

<style lang='scss' scoped>
.avatar-container {
  position: relative;
  display: flex;
  justify-content: center;
  height: 10vw;
  width: 10vw;
  &:hover {
    &::after {
      content: "+";
      position: absolute;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 30px;
      font-weight: bold;
      color: #fff;
      background: rgba(0, 0, 0, 0.5);
      cursor: pointer;
    }
  }
  .img-box {
    border-radius: 50%;
    border: 1px solid #ccc;
    width: 10vw;
    height: 10vw;
  }
}
.preview-box {
  position: absolute;
  top: 50%;
  transform: translate(50%, -50%);
  width: 200px;
  height: 200px;
  border-radius: 50%;
  border: 1px solid #ccc;
  overflow: hidden;
}
</style>

3、组件使用

<template> 
  <div class="avatar-box">
    <Avatar :dataInfo="dataInfo" />
  </div>
</template>  
  
<script setup lang="ts">  
import { ref } from 'vue';
import Avatar from '@/components/Avatar/index.vue'  
interface DataFace {
	img: string
	[propName: string]: any
}
const dataInfo = ref<DataFace>({ 
  img: 'https://img1.baidu.com/it/u=3717210657,1724010864&fm=253&fmt=auto&app=138&f=PNG?w=500&h=500'
})

</script>
<style lang="scss" scoped>
.avatar-box {
  width: 300px;
  display: flex;
  justify-content: center;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1138685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringMVC Day 03 : 处理静态资源

前言 欢迎来到第三天的 SpringMVC 学习系列&#xff01;在前两天的教程中&#xff0c;我们已经学习了如何搭建 SpringMVC 环境、创建控制器和处理请求等基础知识。今天&#xff0c;我们将继续探索 SpringMVC 的功能&#xff0c;并学习如何处理静态资源。 在现代 Web 应用程序…

CloudQuery + StarRocks:打造高效、安全的数据库管控新模式

随着技术的迅速发展&#xff0c;各种多元化的数据库产品应运而生&#xff0c;它们不仅类型众多&#xff0c;而且形式各异&#xff0c;国产化数据库千余套&#xff0c;开源数据库百余套 OceanBase 、PolarDB 、StarRocks…还有一些像 Oracle、MySQL 这些传统数据库。这些数据库产…

php+JavaScript实现callback跨域请求jsonp数据

摘要 JSONP 是 JSON with Padding 的缩写&#xff0c;是一种解决跨域数据获取的方案。由于浏览器的同源策略限制&#xff0c;不同域名之间的前端JS代码不能相互访问到对方的数据&#xff0c;JSONP通过script标签的特性&#xff0c;实现在不同域名的网页间传递数据。 其原理是…

vue3项目运行报错import zhCn from “element-plus/lib/locale/lang/zh-cn“

解决办法 import zhCn from "element-plus/lib/locale/lang/zh-cn";修改为 import zhCn from "element-plus/dist/locale/zh-cn.mjs";

MySQL 8.2 – 透明的读写分离(译)

在MySQL 8.2的版本中&#xff0c;MySQL Router能自动分辨对数据库读写/操作并把这些操作路由到正确的实例上&#xff0c;这是要革众多SQL中间件的命&#xff01;大家说这个算不算遥遥领先呢&#xff1f; 关于号主&#xff0c;姚远&#xff1a; Oracle ACE&#xff08;Oracle和…

使用wireshark的字符串过滤功能

1、打开wireshark&#xff0c;捕获一段时间的数据包 2、选中一个数据包的最下面的内容部分&#xff0c;然后右键鼠标&#xff0c;选择"as Printable Text"。 复制出的文字如下&#xff1a; 截图部分字符串(可包含换行、空格等)&#xff0c;然后复制 3、点击菜单栏…

计算机网络-应用层(2)

一、DHCP 当需要跨越多个网段提供DHCP 服务时必须使用DHCP 中继代理&#xff0c; 就是在DHCP 客户和服务器之间转发DHCP 消息的主机或路由器。 DHCP 服务端使用UDP 的67号端口来监听和接收客户请求消息&#xff0c; 保留UDP 的68号端口用于接收来自DHCP 服务器的消息回复。 在…

图的应用3.0-----拓扑排序

目录 前言 AOE网 1.相关概念 2.AOE网特征 拓扑排序 1.基本概念 2.方法步骤 3.拓扑排序的应用 拓扑排序代码实现 1.邻接矩阵的代码 2.邻接表代码 前言 今天我们学习图的应用----拓扑排序&#xff0c;说到排序&#xff0c;你们是不是会想到冒泡排序&#xff0c;插入排序…

网络安全将会是IT行业中比较容易就业的方面

当前&#xff0c;网络空间安全面临的形势复杂多变&#xff0c;对抗趋势越发凸显。以窃取敏感数据、破坏关键信息技术设施为目标的有组织网络攻击愈演愈烈&#xff0c;零日漏洞、供应链攻击、数据泄露等重大安全事件层出不穷。 回望2022年&#xff0c;国内&#xff0c;以西北工业…

OpenTiny Vue 3.11.0 发布:增加富文本、ColorPicker等4个新组件,迎来了贡献者大爆发!

你好&#xff0c;我是 Kagol。 非常高兴跟大家宣布&#xff0c;2023年10月24日&#xff0c;OpenTiny Vue 发布了 v3.11.0 &#x1f389;。 OpenTiny 每次大版本发布&#xff0c;都会给大家带来一些实用的新特性&#xff0c;8.14 我们发布了 v3.10.0 版本&#xff0c;增加了4个…

“深入探讨操作系统和虚拟化技术“

目录 引言1.操作系统1.1.什么是操作系统1.2.常见操作系统1.3.个人版本和服务器版本的区别1.4.Linux的各个版本 2.安装VMWare虚拟机1.VMWare虚拟机介绍2.VMWare虚拟机安装3.VMWare虚拟机配置 3.安装配置Windows Server 2012 R24.完成电脑远程访问电脑5.服务器环境搭建配置jdk配置…

Windows下安装Anaconda、Pycharm以及iflycode插件图解

目录 一、下载Anaconda、Pycharm以及iflycode插件 二、创建相关文件夹 三、Pycharm社区版安装详细步骤 四、Anaconda安装详细步骤 五、配置Pycharm 六、安装iflycode插件 Anaconda是一款集成的Python环境&#xff0c;anaconda可以看做Python的一个集成安装&#xff0c;安…

Go学习第十一章——协程goroutine与管道channel

Go协程goroutine与管道channel 1 协程goroutine1.1 基本介绍1.2 快速入门1.3 调度模型&#xff1a;MPG模式介绍1.4 设置cpu数1.5 协程资源竞争问题1.6 解决协程并发方案 2 管道channel2.1 基本介绍2.2 快速入门2.3 管道的关闭和遍历2.4 管道和协程的结合2.5 声明 只读/只写 的管…

竞赛 深度学习图像修复算法 - opencv python 机器视觉

文章目录 0 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs最后 0 前言 &#…

浅谈一下Vue3的TreeShaking特性

什么是Treeshaking&#xff1f; Treeshaking是一个术语,通常用于描述移除JavaScript中无用代码的过程。 在Vue3中,借助于它的编译优化,可以显著减少打包后的大小。 Vue3的Treeshaking实现 Vue3中的Treeshaking主要通过以下两点实现: 源码级的Tree-shaking Vue3源码采用ES mo…

香港服务器运行不正常原因简析

​  网站在线业务的部署需要服务器的存在。于我们而言&#xff0c;租用正规服务商(正规机房)的服务器&#xff0c;一般情况下是会很少出现问题。但&#xff0c;要知道&#xff0c;再稳定的服务器也有出现问题的时候&#xff0c;香港服务器也不例外&#xff0c;而且恰恰这个原…

【C++系列】STL容器——vector类的例题应用(12)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01;本章主要内容面向接触过C的老铁&#xff0c;下面是收纳的一些例题与解析~ 主要内容含&#xff1a; 目录 【例1] 只出现一次的数字i&#xff08;范围for与模等&#xff08;^&#xff09;)【例2]…

vscode 通过ssh 连接虚拟机vmware(ubuntu)

1.网络连接是否ping的通&#xff08;ubuntu虚拟机使用的是net 连接方式&#xff09; 2.配置环境 ubuntu 需要安装ssh server 服务 &#xff08;1&#xff09;&#xff1a; 安装&#xff08;Ubuntu安装ssh server) apt-get install openssh-server 检查是否ssh server 是否启动…

如何使用LoRA和PEFT微调 Mistral 7B 模型

一、前言 对于大模型在一些安全级别较高的领域&#xff0c;比如在金融服务领域实施人工智能解决方案时&#xff0c;面临的最大挑战之一是数据隐私、安全性和监管合规性。 因为担心数据泄露的问题&#xff0c;很多银行或机构都会回避利用人工智能的优势潜力&#xff0c;尤其是…

微信小程序学习(02)

页面导航 - 声明式导航 1. 导航到 tabBar 页面 tabBar 页面指的是被配置为 tabBar 的页面。 在使用<navigator> 组件跳转到指定的 tabBar 页面时&#xff0c;需要指定 url 属性和 open-type 属性&#xff0c;其中&#xff1a; ⚫ url 表示要跳转的页面的地址&#xff0…