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

实现网页版的屏幕截图添加备注等功能,效果如下:
在这里插入图片描述
需要安装插件:tui-image-editor
这个弹出框具体代码:

<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/tui-image-editor.css'
import 'tui-color-picker/dist/tui-color-picker.css'

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 坐上角度图片
        'common.bi.image': '', // 在这里换上你喜欢的logo图片
        'common.bisize.width': '0px',
        'common.bisize.height': '0px',
        'common.backgroundImage': 'none',
        'common.backgroundColor': '#f3f4f6',
        'common.border': 'none',

        // header
        'header.backgroundImage': 'none',
        'header.backgroundColor': 'transparent',
        'header.border': '0px',

        // load button
        'loadButton.backgroundColor': '#fff',
        'loadButton.border': '1px solid #ddd',
        'loadButton.color': '#222',
        'loadButton.fontFamily': 'NotoSans, sans-serif',
        'loadButton.fontSize': '12px',
        'loadButton.display': 'none', // 可以直接隐藏掉

        // download button
        'downloadButton.backgroundColor': '#fdba3b',
        'downloadButton.border': '1px solid #fdba3b',
        'downloadButton.color': '#fff',
        'downloadButton.fontFamily': 'NotoSans, sans-serif',
        'downloadButton.fontSize': '12px',
        'downloadButton.display': 'none', // 可以直接隐藏掉

        // icons default
        'menu.normalIcon.color': '#8a8a8a',
        'menu.activeIcon.color': '#555555',
        'menu.disabledIcon.color': '#434343',
        'menu.hoverIcon.color': '#e9e9e9',
        'submenu.normalIcon.color': '#8a8a8a',
        'submenu.activeIcon.color': '#e9e9e9',

        'menu.iconSize.width': '18px',
        'menu.iconSize.height': '18px',
        'submenu.iconSize.width': '20px',
        'submenu.iconSize.height': '20px',
        // 'submenu.backgroundColor': '#ddd',

        // submenu primary color
        // 'submenu.backgroundColor': 'currentcolor',
        'submenu.partition.color': '#858585',

        // submenu labels
        'submenu.normalLabel.color': '#858585',
        'submenu.normalLabel.fontWeight': 'lighter',
        'submenu.activeLabel.color': '#fff',
        'submenu.activeLabel.fontWeight': 'lighter',

        // checkbox style
        'checkbox.border': '1px solid #ccc',
        'checkbox.backgroundColor': '#fff',

        // rango style
        'range.pointer.color': '#fff',
        'range.bar.color': '#666',
        'range.subbar.color': '#d1d1d1',

        'range.disabledPointer.color': '#414141',
        'range.disabledBar.color': '#282828',
        'range.disabledSubbar.color': '#414141',

        'range.value.color': '#fff',
        'range.value.fontWeight': 'lighter',
        'range.value.fontSize': '11px',
        'range.value.border': '1px solid #353535',
        'range.value.backgroundColor': '#151515',
        'range.title.color': '#fff',
        'range.title.fontWeight': 'lighter',

        // colorpicker style
        // 'colorpicker.button.border': '1px solid #1e1e1e',
        'colorpicker.title.color': '#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组件实例,后续操作需要用到this.instance这个对象
      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
      // 你也可以指定那个菜单隐藏,留几个有用的菜单
      // document.querySelector('[tooltip-content="Undo"]').style.display = 'none'// 上一步
      // document.querySelector('[tooltip-content="Redo"]').style.display = 'none' // 下一步
      // document.querySelector('[tooltip-content="Reset"]').style.display = 'none' // 完全重新编辑
      // document.querySelector('[tooltip-content="ZoomIn"]').style.display = 'none' // 放大
      // document.querySelector('[tooltip-content="ZoomOut"]').style.display = 'none' // 缩小
      // document.querySelector('[tooltip-content="Hand"]').style.display = '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组件实例,后续操作需要用到this.instance这个对象
      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(就不会被底部展开的工具栏遮挡住了)===>无效
      // document.getElementsByClassName('tui-image-editor-wrap')[0].style.bottom = 90

      //! 修改图片编辑器的顶部导航栏
      // document.querySelector('[tooltip-content="Undo"]').style.display = '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(() => {
        // state.instance.toDataURL() 编辑后的base64图片码
        // 传给上传组件(父组件)
        context.emit('closeDialog', state.instance.toDataURL())
      }, 700)
    }
    // 将base64转换成file类型,用于给tui-image-editor组件的官方方法调用,计算获得当前图片的宽高
    // ? this.instance.loadImageFromFile这个官方的方法会返回图片的宽高,但是传入的必须时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>

父组件

<!-- 调整截图弹出框 -->
<DialogPageSnapshot :dialog-visiable="dialogSnapshot" :img-url="imgBaseUrl" @closeDialog="handleCloseSnapshot" />
import html2canvas from 'html2canvas'

// 屏幕快照
async function PageSnapshot(ele) {
  let url = ''
  await html2canvas(ele, {
    dpi: 300,
    scale: 2, // 处理图片模糊
    background: '#fff',
    useCORS: true // 允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
  }).then((canvas) => {
    url = canvas.toDataURL('image/jpg')
  })
  return url
}
// 点击弹出框显示的事件内容
const handleDialogClick = () => {
	// 需要打印的模块
	const elementHtml = document.getElementsByClassName('box-excel')[0]
	state.imgBaseUrl = await PageSnapshot(elementHtml)
	nextTick(() => {
	   state.dialogSnapshot = true
	})	
}
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值