vue3+ts 使用VueCropper實現剪切圖片

效果圖:?

?參考文檔:

Vue-Cropper 文檔Vue-Cropper 文檔

安裝VueCropper

//npm安裝
npm install vue-cropper@next -d --save//yarn安裝
yarn add vue-cropper@next

引入組件

?在main.ts中全局注冊:

import VueCropper from 'vue-cropper'; 
import 'vue-cropper/dist/index.css';const app = createApp(App);
app.use(VueCropper);
app.mount('#app');

局部:

import 'vue-cropper/dist/index.css';
import { VueCropper } from 'vue-cropper';

代碼層:

頁面(父組件)
<template><div class="p-4"><imgv-if="photo":src="photo"class="avatar"@click="handleClick"/><el-icon v-else class="avatar-uploader-icon" @click="handleClick"><Plus/></el-icon><ImageCropperv-model="visible"@onSuccess="onSuccess":image="photo"></ImageCropper></div>
</template><script setup lang="ts">
import ImageCropper from "@/components/imageCropper.vue";//裁剪圖片組件
import { uploadPicturesApi } from "@/api/common/index";
import { ElMessage } from "element-plus";
import { ref } from "vue";
const visible = ref<boolean>(false); //上傳圖片彈框
const photo=ref<string>('')
// 打開彈框
const handleClick = (img: string) => {console.log(img);visible.value = true;
};const handleClickImgUrl = () => {console.log(formInfo.value);
};/*** 上傳圖片成功* @param data File*/
const onSuccess = async (data: File) => {console.log(data);try {
//接口上傳為formDataconst res = await uploadPicturesApi(data);if (res.code == 200) {formInfo.value.photo = res.data;//接口返回圖片地址ElMessage.success("上傳成功");visible.value = false;}console.log(res);} catch (error) {ElMessage.error("上傳失敗");}
};
</script><style lang="scss" scoped>
.avatar {width: 160px;height: 160px;display: block;/* border: 1px dashed #8c939d; */border-radius: 6px;
}.el-icon.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 160px;height: 160px;text-align: center;border: 1px dashed #8c939d;border-radius: 6px;
}
</style>
?封裝剪切圖片組件(子組件):
<template><el-dialogappend-to-body:close-on-click-modal="false"v-model="visible"title="圖片裁剪"width="800px"@close="handleClose"><div class="cropper-cut"><div class="picUpload-wraper"><div class="pic-left-wraper"><VueCropperref="cropperRef":img="option.img":outputType="option.outputType":info="true":full="option.full":canMove="option.canMove":canScale="option.canScale":canMoveBox="option.canMoveBox":fixed="option.fixed":fixedBox="option.fixedBox":original="option.original":autoCrop="option.autoCrop":autoCropWidth="cropWith || option.autoCropWidth":autoCropHeight="cropHeight || option.autoCropHeight":centerBox="option.centerBox":high="option.high":infoTrue="option.infoTrue":enlarge="option.enlarge"@realTime="realTime"></VueCropper></div><div class="pic-right-wraper"><div class="title">圖片預覽</div><div :style="previewStyle" class="previewImg" v-show="option.img"><div :style="previews.div"><img :src="previews.url" :style="previews.img" /></div></div></div></div><div class="pic-operate"><inputstyle="display: none"@change="handleChange"ref="fileRef"type="file"name=""id=""/><el-button @click="fileRef?.click()">選擇圖片</el-button><el-button @click="changeScale(1)" :icon="Plus"> </el-button><el-button @click="changeScale(-1)" :icon="Minus"> </el-button><el-button @click="rotateRight()" :icon="RefreshRight"> </el-button></div></div><template #footer><div class="dialog-footer"><el-button @click="$emit('update:modelValue', false)">取消</el-button><el-button @click="saveHeadPic">保存</el-button></div></template></el-dialog>
</template><script setup lang="ts">
import { reactive, ref, watch } from "vue";
import { VueCropper } from "vue-cropper";
import "vue-cropper/dist/index.css";
import { Plus, Minus, RefreshRight } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";const props = defineProps({// 窗口modelValue: {type: Boolean,default: false,},//   大小limitSize: {type: Number,default: 100,},//   寬cropWith: {type: String,default: "350px",},//   高cropHeight: {type: String,default: "350px",},accept: {type: Array<String>,default: () => [],},//   校驗regExp: {type: RegExp,default: /\.(jpg|jpeg|png)$/i,},
});const emit = defineEmits(["update:modelValue", "onSuccess"]);const visible = ref<boolean>(false);const option = reactive({img: "",outputSize: 1, // 裁剪生成圖片的質量 1 0.1 - 1outputType: "png", //  裁剪生成圖片的格式 jpg (jpg 需要傳入jpeg)  jpeg || png || webpinfo: true, //  裁剪框的大小信息  true  true || falsecanScale: true, // 圖片是否允許滾輪縮放  true  true || falseautoCrop: true, //是否默認生成截圖框 false true || falseautoCropWidth: 240, //默認生成截圖框寬度 容器的80%  0~maxautoCropHeight: 300, //默認生成截圖框高度  容器的80%  0~maxfixed: false, //是否開啟截圖框寬高固定比例  true  true | false// fixedNumber: [1, 1], //截圖框的寬高比例 [1, 1]  [寬度, 高度]full: false, //是否輸出原圖比例的截圖  false true | falsefixedBox: true, //固定截圖框大小 不允許改變  false true | falsecanMove: false, //上傳圖片是否可以移動  true  true | falsecanMoveBox: true, //截圖框能否拖動 true  true | falseoriginal: false, //上傳圖片按照原始比例渲染 false true | falsecenterBox: false, //截圖框是否被限制在圖片里面  false true | falsehigh: false, //是否按照設備的dpr 輸出等比例圖片  true  true | falseinfoTrue: false, //true 為展示真實輸出圖片寬高 false 展示看到的截圖框寬高 false true | falsemaxImgSize: 2000, //限制圖片最大寬度和高度 2000  0-maxenlarge: 1, //圖片根據截圖框輸出比例倍數 1 0-max(建議不要太大不然會卡死的呢)mode: "contain", //圖片默認渲染方式  contain contain , cover, 100px, 100% auto
});const previewStyle = ref<any>({});
const previews = ref<any>({});const fileRef = ref<HTMLInputElement>();
const cropperRef = ref<typeof VueCropper>();
let _file: File | null = null;watch(() => props.modelValue,(val) => {visible.value = val;}
);/*** 選擇圖片* @param e*/
const handleChange = (e: Event) => {const _target = e.target as HTMLInputElement;// console.log(_target)if (_target.files && _target.files.length > 0) {_file = _target.files[0];if (_file.size / 1024 / 1024 > props.limitSize) {ElMessage.warning(`圖片大小不能超過${props.limitSize}MB`);return;}// const type = _file.name.split('.')[1]if (!props.regExp.test(_file.name)) {ElMessage.warning(`請上傳jpg、jpeg、png格式圖片`);return;}const reader = new FileReader();reader.readAsDataURL(_file);reader.onload = (e) => {option.img = e.target?.result as string;};}
};
/***  實時預覽事件* @param data*/
const realTime = (data: any) => {previews.value = data;previewStyle.value = {width: data.w + "px",height: data.h + "px",overflow: "hidden",margin: "0",zoom: 160 / data.w,};
};
/*** 放大縮小* @param num*/
const changeScale = (num: number) => {num = num || 1;cropperRef.value?.changeScale(num);
};
/*** 旋轉圖片*/
const rotateRight = () => {cropperRef.value?.rotateRight();
};/*** 取消清空*/
const handleClose = () => {// console.log('close')option.img = "";fileRef.value && (fileRef.value.value = "");previews.value = {};previewStyle.value = {};cropperRef.value?.clearCrop();_file = null;emit("update:modelValue", false);
};/***上傳保存圖片*/
const saveHeadPic = () => {if (!option.img) return ElMessage.warning("請先上傳圖片");cropperRef.value?.getCropBlob((blob: Blob) => {// blob 轉 fileif (_file) {const file = new File([blob], _file.name, { type: _file.type });emit("onSuccess", file);} else {ElMessage.error("獲取圖片失敗");}});
};
</script><style lang="scss" scoped>
.picUpload-wraper {height: fit-content;display: flex;justify-content: space-between;.pic-left-wraper {width: 540px;height: 360px;border: 1px solid #ddd;}.pic-right-wraper {padding: 20px;width: 200px;max-height: 360px;border: 1px solid #ddd;background: #fafafa;.title {margin-bottom: 10px;font-size: 14px;font-weight: 600;}.previewImg {max-height: 360px !important;overflow: hidden;}}
}
.pic-operate {margin-top: 10px;
}
</style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84992.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84992.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84992.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

el-table特殊表頭樣式

el-table特殊表頭樣式 實現表頭是按鈕 <el-table-column align"center"><template slot"header"><el-buttonsize"mini"type"primary"icon"el-icon-plus"circleclick"addData"></el-button&g…

el-tree的屬性render-content自定義樣式不生效

需求是想要自定義展示el-tree的項&#xff0c;官網有一個:render-content屬性&#xff0c;用的時候發現不管是使用class還是style&#xff0c;樣式都沒有生效&#xff0c;還會報一個錯&#xff0c;怎么個事呢&#xff0c;后來發現控制臺還會報一個錯“vue.js:5129 [Vue warn]: …

銀杏書簽里的春天

春末的細雨沾濕了舊書扉頁&#xff0c;我在泛黃的《飛鳥集》里發現那枚銀杏書簽時&#xff0c;窗外的梧桐樹正抖落最后一片枯葉。深褐色的葉脈間夾著張字條&#xff0c;娟秀的字跡被歲月暈染&#xff1a;"給永遠在奔跑的人。" 十年前的我在舊書店打工&#xff0c;每天…

spring-ai 1.0.0 學習(十四)——向量數據庫

向量數據庫是AI系統中常用的工具&#xff0c;主要用來存儲文檔片段及進行語義相似度查找 與傳統數據庫不同&#xff0c;它執行的是相似度查找而不是精確匹配 最小化樣例 首先在application.properties中&#xff0c;根據所用Embedding模型&#xff0c;添加一個嵌入式模型型號…

Spring Boot 的Banner的介紹和設置

Spring Banner 是指在 Spring Boot 應用啟動時,控制臺上顯示的那一段 ASCII 藝術字(通常是 Spring 的 logo),以及一些應用信息。 Banner 是 Spring Boot 提供的一個小但有趣的功能,可以讓應用程序啟動時更具個性也顯得更高級。 默認 Banner Spring Boot 內置了一個默認…

魅族“換血”出牌:手機基本盤站不穩,想靠AI和汽車“改命”

撰稿|何威 來源|貝多財經 被吉利收購后&#xff0c;魅族逐漸轉向在AI領域躬身耕作。 自2024年2月以“All in AI”正式宣告轉型、喊出不再推出傳統智能手機的豪言開始&#xff0c;這家曾以設計見長的手機廠商&#xff0c;將下半場押注在AI終端、AR眼鏡與智能座艙系統上&#…

力扣熱題100之將有序數組轉換為二叉搜索樹

題目 給你一個整數數組 nums &#xff0c;其中元素已經按 升序 排列&#xff0c;請你將其轉換為一棵 平衡 二叉搜索樹。 代碼 使用遞歸的方法 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # s…

mac隱藏文件現身快捷鍵

在 macOS 系統中&#xff0c;?顯示/隱藏隱藏文件? 有兩種常用方法&#xff0c;以下是詳細說明&#xff1a; ? 方法一&#xff1a;使用快捷鍵&#xff08;最簡單&#xff09; 打開 ?訪達&#xff08;Finder&#xff09;?。 進入任意文件夾&#xff08;如桌面或文檔&#x…

IAR Workspace 中 Debug 與 Release 配置的深度解析

IAR Workspace 中 Debug 與 Release 配置的深度解析 一、配置的本質區別 1. 核心目標對比 特性Debug 配置Release 配置優化目標調試友好性性能/尺寸優化代碼優化無或低優化 (-O0/-O1)高級優化 (-O2/-O3/-Oz)調試信息包含完整符號信息無或最小化符號斷言檢查啟用通常禁用輸出…

Ubuntu下安裝python3

一、下載python3源碼 以要安裝的是python3.13.5為例&#xff0c;在 Index of /ftp/python/3.13.5/ 下載Python-3.13.5.tgz&#xff1a; 將壓縮包上傳到Ubuntu系統中&#xff0c;解壓&#xff1a; tar -zxvf Python-3.13.5.tgz 二、安裝 進入解壓后的源碼目錄&#xff1a; c…

計算機基礎和Java編程的練習題

1. 計算機的核心硬件是什么&#xff1f;各自有什么用&#xff1f; 中央處理器&#xff08;CPU&#xff09;&#xff1a;負責執行程序中的指令&#xff0c;進行算術和邏輯運算&#xff0c;是計算機的“大腦”。 內存&#xff08;RAM&#xff09;&#xff1a;臨時存儲CPU正在處…

橋頭守望者

趙阿姨在324國道邊的便利店守了八年柜臺&#xff0c;她的記賬本里藏著特殊的日歷——那些標著KLN字母的運輸單據總在固定日期出現&#xff0c;精確得像是節氣。"比氣象臺還準"&#xff0c;她指著玻璃窗上凝結的水珠說。去年寒潮來襲時&#xff0c;她親眼看見送貨員小…

C語言函數的參數傳遞和C++函數的參數傳遞

文章目錄 C語言值傳遞地址傳遞 C引用傳遞 C語言 值傳遞 這種方式使用變量、數組元素作為函數參數&#xff0c;實際是將實參的值復制到形參相應的存儲單元中&#xff0c;即形參和實參分別占用不同的存儲單元&#xff0c;這種傳遞方式稱為“參數的值傳遞”。在調用結束后&#…

設計模式-三大工廠

工廠模式有三種&#xff0c;分別是簡單工廠模式、工廠方法模式、抽象工廠模式。三種模式從前到后越來越抽象&#xff0c;也更具有一般性。 設計模式 優點 缺點 簡單工廠 1.實現了對責任的分割&#xff0c;它提供了專門的工廠類用于創建對象。 1.違背了開閉原則。 2.使用了…

在 AI 工具海洋中掌舵:Cherry Studio 如何成為你的統一指揮中心

01 被 AI 工具包圍的知識工作者現狀 在這個 AI 爆發的時代&#xff0c;知識工作者的工具庫正經歷前所未有的擴容。以我為例&#xff0c;按平臺類型梳理日常使用的 AI 工具&#xff0c;已然形成三層矩陣&#xff1a; 「云端智能助手」&#xff1a;Kimi、豆包、ChatGPT、Gemini…

Java 線程池技術深度解析與代碼實戰

為什么線程池總在深夜崩潰&#xff1f; 昨天我這項目又經歷了一次爆破——路由推送服務突然崩潰&#xff0c;排查發現線程池隊列堆積了幾萬任務直接把內存撐爆。早上起來看見人都麻了&#xff0c;線程池用不好&#xff0c;分分鐘變系統炸彈。今天我們就來系統梳理線程池的實戰…

Gradio可視化構建聊天機器人

Gradio是一個Python庫&#xff0c;專門用于快速構建和部署機器學習模型的Web界面。它的名字來源于"Gradient"&#xff08;梯度&#xff09;&#xff0c;最初是為了讓機器學習開發者能夠快速展示他們的模型而設計的。 1. Gradio是什么&#xff1f; 核心概念 快速原…

selenium如何識別條形驗證碼,自動輸入驗證碼

在自動化測試或網頁爬取中&#xff0c;識別驗證碼是常見的難點。Selenium 本身不具備直接識別驗證碼的能力&#xff0c;但可以通過結合第三方工具、OCR 技術或人工介入等方式解決。以下是多種可行方案的詳細實現思路及代碼示例&#xff1a; 一、方案一&#xff1a;使用第三方驗…

SAP將指定EXCEL工作SHEET的數據上傳到內表

SAP將指定EXCEL工作SHEET的數據上傳到內表 本文描述了一個SAP ABAP類方法upload_excel_2internaltab&#xff0c;用于將Excel文件數據上傳到內部表。主要功能包括&#xff1a; 驗證Excel行列范圍有效性&#xff0c;若起始值大于結束值則拋出異常檢查文件是否存在&#xff0c;支…

Spring Boot(九十三):Springboot 整合cfx實現webservice接口

1 服務端 最近項目改造,有一些老項目接口協議是webservice soap1.1,這就需要我們提供webservice服務接口。在Spring Boot中整合CFX(CXF框架)以實現Web服務客戶端與服務端的功能,可以分為幾個步驟。下面我將詳細介紹如何在Spring Boot中設置一個Web服務端點,使用Apache CX…