最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Vue3封裝實(shí)現(xiàn)支持Base64導(dǎo)出的電子簽名組件

 更新時間:2025年03月31日 08:57:23   作者:脆  
這篇文章主要為大家詳細(xì)介紹了使用Vue3封裝實(shí)現(xiàn)支持Base64導(dǎo)出的電子簽名組件的相關(guān)知識,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下

默認(rèn)支持簽字回顯,base64壓縮,內(nèi)存釋放

傳參支持禁用簽字也就是查看,組件大小內(nèi)置'small', 'default', 'large'三個大小

效果圖

準(zhǔn)備工作

組件內(nèi)用到elementPlus,vue-esign組件,使用前提前安裝好。

組件代碼

<template>
	<!-- 簽名容器 -->
	<div class="sign-container" >
		<div class="sign-preview" :class="[sizeClass, { 'has-sign': base64Img }]" @click="openDialog">
			<img v-if="base64Img" :src="base64Img" class="preview-image" />
			<div v-else class="placeholder">
				<el-icon><EditPen /></el-icon>
				<span>點(diǎn)擊簽名</span>
			</div>
		</div>

		<!-- 簽字彈窗 -->
		<el-dialog v-model="dialogVisible" title="電子簽名" width="800px">
			<vue-esign ref="esignRef" :width="800" :height="300" :lineWidth="4" :lineColor="'#000000'" :bgColor="'#ffffff'"  :id="uuid" />

			<template #footer>
				<el-button @click="dialogVisible = false">取消</el-button>
				<el-button @click="handleReset">清空</el-button>
				<el-button type="primary" @click="handleConfirm">確認(rèn)</el-button>
			</template>
		</el-dialog>
	</div>
</template>
 
<script setup>
import { ref } from 'vue';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { generateUUID } from '/@/utils/other';

import vueEsign from 'vue-esign';

// 生成組件唯一id
const uuid = ref('id-' + generateUUID());
// 組件尺寸
const sizeClass = computed(() => `sign-size--${props.size}`);

const emit = defineEmits(['update:modelValue']);
const props = defineProps({
	modelValue: String, // v-model綁定
    disabled: {
		type: Boolean,
		default: false,
	},
	size: {
		type: String,
		default: 'default',
		validator: (v) => ['small', 'default', 'large'].includes(v),
	},
});

const dialogVisible = ref(false);
const esignRef = ref(null);
const base64Img = ref(props.modelValue);

// 打開彈窗時重置畫布
const openDialog = () => {
    if (props.disabled) return;
	dialogVisible.value = true;
	// handleReset();
};

// 清空畫布(保留二次確認(rèn))
const handleReset = async () => {
	try {
		await useMessageBox().confirm('此操作將清空簽名,確定嗎?');
		esignRef.value?.reset();
	} catch {}
};
// 生成簽名后壓縮
const compressBase64 = (base64) => {
	return new Promise((resolve, reject) => {
		const img = new Image();
		img.src = base64;

		img.onload = () => {
			// 創(chuàng)建canvas并設(shè)置縮放尺寸
			const canvas = document.createElement('canvas');
			const ctx = canvas.getContext('2d');

			// 計(jì)算壓縮后尺寸(取原圖50%)
			const targetWidth = img.width * 0.5;
			const targetHeight = img.height * 0.5;

			// 設(shè)置畫布尺寸
			canvas.width = targetWidth;
			canvas.height = targetHeight;

			// 繪制壓縮圖像
			ctx.drawImage(img, 0, 0, targetWidth, targetHeight);

			// 生成新base64(自動處理格式)
			const mimeType = base64.match(/data:(.*?);/)[1];
			canvas.toBlob(
				(blob) => {
					const reader = new FileReader();
					reader.onloadend = () => resolve(reader.result);
					reader.readAsDataURL(blob);
				},
				mimeType,
				0.6
			); // 質(zhì)量參數(shù)生效于JPEG/WebP格式
		};

		img.onerror = (e) => reject('圖片加載失敗');
	});
};
// 確認(rèn)簽名
const handleConfirm = async () => {
	esignRef.value
		.generate()
		.then(async (res) => {
			base64Img.value = await compressBase64(res);
			// 驗(yàn)證壓縮效果
			const originalSize = Math.round((res.length * 3) / 4 / 1024);
			const compressedSize = Math.round((base64Img.value.length * 3) / 4 / 1024);
			console.log(` 尺寸變化:${originalSize}KB → ${compressedSize}KB`);
			emit('update:modelValue', base64Img.value);
			dialogVisible.value = false;
		})
		.catch(() => {
			base64Img.value = '';
			emit('update:modelValue', '');
			dialogVisible.value = false;
		});
};


// watch同步
watch(
	() => props.modelValue,
	async (val) => {
		if (!val) {
			base64Img.value = '';
			esignRef.value?.reset();
		}
		console.log(val);
        base64Img.value = await compressBase64(val);

	}
);



onBeforeUnmount(() => {
	// 釋放canvas內(nèi)存
	const canvas = esignRef.value?.$el.querySelector('canvas');
	canvas.width = 0;
	canvas.height = 0;
	URL.revokeObjectURL(base64Img.value); // 釋放Blob URL
});
</script>
 
<style scoped lang="scss">
.sign-container {
	display: inline-block;
	cursor: pointer;
}
.sign-preview {
	border: 1px solid #dcdfe6;
	background: #fff;
	border-radius: 4px;

	&.sign-size--small {
		width: 120px;
		height: 60px;
	}
	&.sign-size--default {
		width: 180px;
		height: 90px;
	}
	&.sign-size--large {
		width: 240px;
		height: 120px;
	}

	&.has-sign {
		border-color: var(--el-color-primary);
	}

	.preview-image {
		width: 100%;
		height: 100%;
		object-fit: contain;
	}

	.placeholder {
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		color: #909399;

		.el-icon {
			margin-right: 8px;
			font-size: 18px;
		}
	}
}
</style>

使用組件

<el-form ref="dataFormRef" :model="form" inline :rules="dataRules">
    <el-form-item label="經(jīng)辦人簽字" prop="signatureHandler" label-width="8em">
		<!-- 簽名組件 -->
		<signature-component v-model="form.signatureHandler" />
    </el-form-item>
</el-form>

注意事項(xiàng)

使用時將組件內(nèi)的提示框替換為elementPlus官方的

generateUUID方法自行修改為生成UUID的方法,也可以去掉。

到此這篇關(guān)于使用Vue3封裝實(shí)現(xiàn)支持Base64導(dǎo)出的電子簽名組件的文章就介紹到這了,更多相關(guān)Vue3電子簽名內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Vue 路由組件傳參的 8 種方式

    詳解Vue 路由組件傳參的 8 種方式

    這篇文章主要介紹了Vue 路由組件傳參的 8 種方式,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • vue導(dǎo)出excel表格并支持樣式及行高修改

    vue導(dǎo)出excel表格并支持樣式及行高修改

    這篇文章主要為大家介紹了vue導(dǎo)出excel表格并支持樣式及行高修改,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • vue在install時node-sass@4.14.1?postinstall:node?scripts/build.js錯誤解決

    vue在install時node-sass@4.14.1?postinstall:node?scripts/buil

    最近在npm install 的時候遇到了個問題,所以給大家總結(jié)下,下面這篇文章主要給大家介紹了關(guān)于vue在install時node-sass@4.14.1?postinstall:node?scripts/build.js錯誤的解決方法,需要的朋友可以參考下
    2023-05-05
  • 使用vue-element-admin框架從后端動態(tài)獲取菜單功能的實(shí)現(xiàn)

    使用vue-element-admin框架從后端動態(tài)獲取菜單功能的實(shí)現(xiàn)

    &#8203; vue-element-admin是一個純前端的框架,左側(cè)菜單是根據(jù)路由生成的。實(shí)際開發(fā)中經(jīng)常需要根據(jù)當(dāng)前登陸人員的信息從后端獲取菜單進(jìn)行展示,本文將詳細(xì)介紹如何實(shí)現(xiàn)該功能
    2021-04-04
  • 前端vue中實(shí)現(xiàn)文件下載的幾種方法總結(jié)

    前端vue中實(shí)現(xiàn)文件下載的幾種方法總結(jié)

    這篇文章主要介紹了前端vue中實(shí)現(xiàn)文件下載的幾種方法總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Vue + Echarts頁面內(nèi)存占用高的問題解決方案

    Vue + Echarts頁面內(nèi)存占用高的問題解決方案

    點(diǎn)擊左側(cè)的菜單可以切換不同的看板,有些看板頁面中的報(bào)表比較多,用戶多次切換后頁面的內(nèi)存占用可以上升為GB級,嚴(yán)重時導(dǎo)致頁面內(nèi)存溢出,使得頁面崩潰,極大影響了用戶體驗(yàn),本文給大家介紹Vue + Echarts頁面內(nèi)存占用高的問題解決方案,感興趣的朋友一起看看吧
    2024-02-02
  • 深入了解Vue3組件傳值方式

    深入了解Vue3組件傳值方式

    學(xué)習(xí)過?vue2?的寶子們肯定知道,組件傳值是?vue?項(xiàng)目開發(fā)過程中必不可少的功能場景,在?vue2?里面有很多傳值的方式。今天就來和大家講講Vue3的組件傳值方式,需要的可以參考一下
    2022-07-07
  • vue中使用微信公眾號js-sdk踩坑記錄

    vue中使用微信公眾號js-sdk踩坑記錄

    這篇文章主要介紹了vue中使用微信公眾號js-sdk踩坑記錄,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • vue 2.1.3 實(shí)時顯示當(dāng)前時間,每秒更新的方法

    vue 2.1.3 實(shí)時顯示當(dāng)前時間,每秒更新的方法

    今天小編就為大家分享一篇vue 2.1.3 實(shí)時顯示當(dāng)前時間,每秒更新的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • element-ui中el-cascader動態(tài)加載和默認(rèn)值詳解

    element-ui中el-cascader動態(tài)加載和默認(rèn)值詳解

    vue+elementUI項(xiàng)目中el-cascader級聯(lián)選擇器使用頻率非常高,下面這篇文章主要給大家介紹了關(guān)于element-ui中el-cascader動態(tài)加載和默認(rèn)值的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05

最新評論

治县。| 米林县| 正阳县| 桃园县| 张家口市| 绍兴市| 乌兰浩特市| 梅州市| 福泉市| 乳山市| 孟州市| 安远县| 颍上县| 阜南县| 甘孜县| 杭锦旗| 宜昌市| 东丰县| 潍坊市| 台中市| 明水县| 德安县| 筠连县| 天峻县| 华安县| 自治县| 龙游县| 威海市| 惠州市| 黑水县| 靖远县| 枣庄市| 无棣县| 武陟县| 当涂县| 简阳市| 炉霍县| 兴安县| 青河县| 赤峰市| 岫岩|