vue3网页端屏幕截图并可以裁剪,反转,添加批注等

时间:2025-02-16 19:08:10
<template> <!-- 屏幕截图弹出窗 --> <el-dialog v-model="dialogShow" custom-class="customSnapshotDialog" title="调整截图" width="1000px" top="49px" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose" > <div class="boardBox"> <div id="tui-image-editor" /> </div> <template #footer> <span class="dialog-footer"> <el-button @click="handleClose">取 消</el-button> <el-button type="primary" @click="handleCanvas2Img">确认上传</el-button> </span> </template> </el-dialog> </template> <script> import { reactive, toRefs, watch, nextTick } from 'vue' import 'tui-image-editor/dist/' import 'tui-color-picker/dist/' export default { name: 'DialogPageSnapshot', components: { }, props: { dialogVisiable: { type: Boolean, default: false }, imgUrl: { type: String, default: '' } }, emits: ['closeDialog'], setup(props, context) { // const { proxy } = getCurrentInstance() const state = reactive({ dialogShow: false, imgBaseUrl: '', // 创建的画布对象 instance: null, ImageEditor: require('tui-image-editor'), localeCN: { Crop: '裁剪', Draw: '涂鸦', Text: '添加文本', Undo: '上一步', Redo: '下一步', Reset: '重置', Apply: '确定', Cancel: '取消', Custom: '自定义', Square: '正方形', Free: '曲线', Straight: '直线', Color: '颜色', Range: '粗细/角度', Bold: '加粗', Italic: '斜体', Underline: '下划线', Left: '左对齐', Center: '居中', Right: '右对齐', 'Flip X': 'X 轴', 'Flip Y': 'Y 轴', Flip: '镜像', Rotate: '旋转', ZoomIn: '放大', ZoomOut: '缩小', Hand: '拖动', 'Text size': '字体大小' }, customTheme: { // image 坐上角度图片 '': '', // 在这里换上你喜欢的logo图片 '': '0px', '': '0px', '': 'none', '': '#f3f4f6', '': 'none', // header '': 'none', '': 'transparent', '': '0px', // load button '': '#fff', '': '1px solid #ddd', '': '#222', '': 'NotoSans, sans-serif', '': '12px', '': 'none', // 可以直接隐藏掉 // download button '': '#fdba3b', '': '1px solid #fdba3b', '': '#fff', '': 'NotoSans, sans-serif', '': '12px', '': 'none', // 可以直接隐藏掉 // icons default '': '#8a8a8a', '': '#555555', '': '#434343', '': '#e9e9e9', '': '#8a8a8a', '': '#e9e9e9', '': '18px', '': '18px', '': '20px', '': '20px', // '': '#ddd', // submenu primary color // '': 'currentcolor', '': '#858585', // submenu labels '': '#858585', '': 'lighter', '': '#fff', '': 'lighter', // checkbox style '': '1px solid #ccc', '': '#fff', // rango style '': '#fff', '': '#666', '': '#d1d1d1', '': '#414141', '': '#282828', '': '#414141', '': '#fff', '': 'lighter', '': '11px', '': '1px solid #353535', '': '#151515', '': '#fff', '': 'lighter', // colorpicker style // '': '1px solid #1e1e1e', '': '#fff' } }) watch(props, (newValue) => { state.dialogShow = newValue.dialogVisiable if (state.dialogShow) { state.refPage = newValue.refPage state.imgBaseUrl = newValue.imgUrl if (state.imgBaseUrl) { nextTick(() => { // 获取到当前屏幕的宽高,用于判断当前是大屏幕还是小屏幕==》进而确定的那个要渲染哪个init(画布大小不一样) // 如果不压缩图片大小,太大的图片出现拖动,手机端无法操作,所以要根据不同屏幕大小渲染不同大小的画布 if (document.documentElement.clientWidth <= 500) { initMini() } else { // 页面加载好,就调用这个方法来创建图片编辑器 init() } }) } } }) const init = () => { // 创建tui-image-editor组件实例,后续操作需要用到这个对象 state.instance = new state.ImageEditor(document.querySelector('#tui-image-editor'), { includeUI: { // 默认加载的图片 loadImage: { // 图片路径 path: state.imgBaseUrl, // 图片的名字,可以省略 name: 'image' }, // 默认开启绘图的功能,小屏幕情况下,直接打开菜单,会占用较大屏幕空间,不美观 initMenu: 'draw', // 支持的菜单 menu: [ 'crop', // 裁切 'draw', // 添加绘画 'text', // 添加文本 'rotate', // 旋转 'flip' // 翻转 // 'shape', // 添加形状 // 'icon', // 添加图标 // 'mask', // 添加覆盖 // 'filter' // 添加滤镜 ], // 菜单位置在下面 menuBarPosition: 'bottom', // 汉化 locale: state.localeCN, // 自定义样式(隐藏默认顶部栏目、按钮颜色。。。) theme: state.customTheme }, // 设置画布的最大宽高,能自动等比例缩放大图片到指定的宽高内 // TODO:可以监听当前页面的缩放,动态修改画布最大宽高以防止图片过大 cssMaxWidth: 850 // cssMaxHeight: 580 } ) // 清除自定义样式造成的一条边框线 document.getElementsByClassName('tui-image-editor-main')[0].style.top = 0 // 你也可以指定那个菜单隐藏,留几个有用的菜单 // ('[tooltip-content="Undo"]'). = 'none'// 上一步 // ('[tooltip-content="Redo"]'). = 'none' // 下一步 // ('[tooltip-content="Reset"]'). = 'none' // 完全重新编辑 // ('[tooltip-content="ZoomIn"]'). = 'none' // 放大 // ('[tooltip-content="ZoomOut"]'). = 'none' // 缩小 // ('[tooltip-content="Hand"]'). = 'none' // 拖动界面 document.querySelector('[tooltip-content="History"]').style.display = 'none' document.querySelector('[tooltip-content="Delete"]').style.display = 'none' // 删除选中编辑内容 document.querySelector('[tooltip-content="DeleteAll"]').style.display = 'none' // 清空 // 隐藏分割线 document.querySelectorAll('.tui-image-editor-icpartition').forEach(item => { item.style.display = 'none' }) } // 创建图片编辑器 ==>小屏幕 const initMini = () => { // 创建tui-image-editor组件实例,后续操作需要用到这个对象 state.instance = new state.ImageEditor( document.querySelector('#tui-image-editor'), { includeUI: { // 默认加载的图片 loadImage: { // 图片路径 path: state.imgBaseUrl, // 图片的名字,可以省略 name: 'image' }, // 默认开启绘图的功能,小屏幕情况下,直接打开菜单,会占用较大屏幕空间,不美观 initMenu: 'draw', // 支持的菜单 menu: [ 'crop', // 裁切 'draw', // 添加绘画 'text' // 添加文本 ], // 菜单位置在下面 menuBarPosition: 'bottom', // 汉化 locale: state.localeCN, // 自定义样式(隐藏默认顶部栏目、按钮颜色。。。) theme: state.customTheme }, // 设置画布的最大宽高,能自动等比例缩放大图片到指定的宽高内 // !设置小图宽高,自动压缩图片,防止过大出现滚动,导致无法操作 cssMaxWidth: 350, cssMaxHeight: 500 } ) // 清除自定义样式造成的一条边框线 document.getElementsByClassName('tui-image-editor-main')[0].style.top = 0 // 设置图片编辑其余距离底部90px(就不会被底部展开的工具栏遮挡住了)===>无效 // ('tui-image-editor-wrap')[0]. = 90 //! 修改图片编辑器的顶部导航栏 // ('[tooltip-content="Undo"]'). = 'none'// 上一步 document.querySelector('[tooltip-content="History"]').style.display = 'none' document.querySelector('[tooltip-content="Delete"]').style.display = 'none' // 删除选中编辑内容 document.querySelector('[tooltip-content="DeleteAll"]').style.display = 'none' // 清空 // 隐藏分割线 document.querySelectorAll('.tui-image-editor-icpartition').forEach(item => { item.style.display = 'none' }) } /** 保存编辑后图片 */ const handleCanvas2Img = () => { // 要延时调用,否则会被锁死,因为异步方法会在没有这个dom时触发它 setTimeout(() => { // () 编辑后的base64图片码 // 传给上传组件(父组件) context.emit('closeDialog', state.instance.toDataURL()) }, 700) } // 将base64转换成file类型,用于给tui-image-editor组件的官方方法调用,计算获得当前图片的宽高 // ? 这个官方的方法会返回图片的宽高,但是传入的必须时file类型的文件 const dataURLtoFile = (dataurl) => { var arr = dataurl.split(',') var mime = arr[0].match(/:(.*?);/)[1] var bstr = atob(arr[1]) var n = bstr.length var u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } return new File([u8arr], { type: mime }) } const handleClose = () => { state.dialogShow = false context.emit('closeDialog', false) } return { ...toRefs(state), handleClose, handleCanvas2Img, dataURLtoFile, initMini, init } } } </script> <style lang="scss" scoped> .boardBox { width: 100%; height: 79.5vh; background: #f9f9f9; } // 弹窗的关闭按钮 .closeBigBtn { position: absolute; left: 150px; top: 12px; } </style> <style lang="scss"> .tui-image-editor-container .tui-image-editor-controls { height: 40px; background-color: #ddd; } .tui-image-editor-container .tui-image-editor-wrap { padding: 6px 0; position: initial; flex: 1; } .tui-image-editor-container .tui-image-editor-main { display: flex; flex-direction: column-reverse; } .tui-image-editor-container .tui-image-editor-main-container { height: calc(100% - 40px); } .tui-image-editor-container .color-picker-value { width: 22px; height: 22px; } .tui-image-editor { top: 0 !important; } .tui-image-editor-submenu { border-radius: 10px 10px 0 0 !important; } .tui-image-editor-container .tui-image-editor-partition > div { height: 40px; } .tui-image-editor-submenu-item { padding: 8px 0 8px 0 !important; } .tui-image-editor-container { background-color: transparent; } .tui-image-editor-container li { line-height: initial; } .tui-image-editor-container .svg_ic-submenu { display: inline-block; } /* 强制压缩菜单的高度 ,减少占用屏幕的空间*/ .tui-image-editor-container .tui-image-editor-submenu { height: auto !important; position: sticky !important; } .tui-image-editor-container.bottom .tui-image-editor-submenu>div { padding: 0 !important; } /* 顶部工具栏定位 */ .tui-image-editor-container .tui-image-editor-header { top: -55px; } .tui-image-editor-container .tui-image-editor-help-menu { border-radius: 10px 10px 0 0; } .tui-image-editor-container .tui-image-editor-help-menu.top { top: -32px; background-color: #f0f2f5; height: auto; } /* 顶部工具栏定位 */ .tui-image-editor-container { overflow: visible; }</style>