最近项目遇到的要求是弹出框上传文件,需要用到页面截图,由于使用的是Vue3的框架于是选择用vue-web-screen-shot组件进行操作。(由于插件是Vue3编写的,所以只适用于Vue3的项目,如果是Vue2的项目,截图组件可以使用js-web-screen-shot)

需要实现的效果如下:

 点击截图后弹窗消失,用户可随意在页面中截图等操作

 确认后在弹窗中显示截图列表,上传表格

整个操作步骤实现如下:

  • 在项目中添加vue-web-screen-shot组件
  • 在项目入口文件中导入组件
  • 在需要使用的页面使用组件
  • 在页面截图后使用获得的64编码转为图片文件形式进行上传

1.在项目中添加vue-web-screen-shot组件

//使用以下代码添加插件

yarn add vue-web-screen-shot

# or

npm install vue-web-screen-shot --save

2.在main.js中导入组件

// 导入截屏插件
import screenShort from "vue-web-screen-shot";
const app = createApp(App);
// 使用截屏插件
app.use(screenShort, { enableWebRtc: false })

3.在需要的页面导入截图组件

<template>
    
    <div v-show="showScreenShort">
        
        <el-dialog>

           //省略弹框其他部分
           ...
             <el-button @click="jietu">快捷截图</el-button>
        </el-dialog>
    </div>

    //直接使用组件即可,不用在该页面继续添加
    <screen-short
    v-if="screenshotStatus"
    @get-image-data="getImg"
    @destroy-component="destroyComponent"
      >
    </screen-short>
</template>

如果将screen-short组件放在弹出框内部,则隐藏弹出框时会连同截屏组件一起隐藏,所以建议放在外部,并给dialog弹出框单独加一个div,用showScreenShort控制弹出框显示和隐藏

参数说明

如示例代码所示,在template中直接使用screen-short插件,绑定组件需要的事件处理函数即可。

接下来就跟大家讲下组件中每个属性的意义:

  • screenshotStatus 用于控制组件是否出现在dom中
  • @destroy-component 用于接收截图组件传递的销毁消息,我们需要在对应的函数中销毁截图组件
  • @get-image-data 用于接收截图组件传递的框选区域的base64图片信息,我们需要为他提供一个函数来接收截图组件传递的消息

可选参数

截图插件有一个可选参数,它接受一个对象,对象每个key的作用如下:

  • enableWebRtc 是否启用webrtc,值为boolean类型,值为false则使用html2canvas来截图
  • level 截图容器层级,值为number类型。
  • clickCutFullScreen 单击截全屏启用状态,值为boolean类型, 默认为false
  • hiddenToolIco 需要隐藏的截图工具栏图标,值为{ save?: boolean; undo?: boolean; confirm?: boolean }类型,默认为{}。传你需要隐藏的图标名称,将值设为true即可。
  • enableCORS html2canvas截图模式下跨域的启用状态,值为boolean类型,默认为false
  • proxyAddress html2canvas截图模式下的图片服务器代理地址,值为string类型,默认为undefined

 截图功能实现代码如下:

<script>

function jietu() {
  showScreenShort.value = false;//隐藏弹框
  screenshotStatus.value = true;//显示截图插件
}

//截图按了√以后生成64编码
async function getImg(base64) {
  var image = new Image();
  image.src = base64;
  image.onload = () => {
    var canvas = convertImageToCanvas(image);
    var url = canvas.toDataURL('image/jpeg');
    var name = guid();
    uploadlist.value.push({ image: url, name: name });
  };
//截图完成后显示弹框
  showScreenShort.value = true;
}

//生成文件唯一编码作为name 方便后续删除图片时查找对象
function guid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = (Math.random() * 16) | 0,
      v = c == 'x' ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
}

//取消截图 显示弹窗 隐藏截图插件
function destroyComponent() {
  screenshotStatus.value = false;
  showScreenShort.value = true;
}
</script>

接下来制作截图的列表框,循环的是js代码中64编码uploadlist表,由于用户可能需要对图片进行查看、删除等操作,加入点击事件

//在之前的弹窗快捷截图后边
 <div v-if="uploadlist.length > 0" class="imglist">
    <div v-for="(item, index) in uploadlist" class="picBox">
                    <img
                      :src="item.image"
                      title="点击查看大图"
                      alt="item.name"
                      @click="handlePictureCardPreview(item.image)"/>
        <span style="float: right">
        <i class="iconfont icon-guanbi" @click="deleteImg(item.name)"></i>
        </span>
    </div>
</div>
//查看大图也是一个弹出框的形式

 <el-dialog v-model="dialogVisible" class="dialogSmall">
        <template #header>
          <div class="dialogHeader">
            <div>查看大图</div>
          </div>
        </template>
        <img w-full :src="dialogImageUrl" alt="Preview Image" style="width: 100%" />
      </el-dialog>
//涉及语法
// 查看图片大图
<script>
function handlePictureCardPreview(url) {
  dialogImageUrl.value = url;
  dialogVisible.value = true;
}
</script>

删除截图代码: 

function deleteImg(name) {
  console.log(name);
  uploadlist.value.forEach((value, index, array) => {
    if (name == value.name) {
      array.splice(index, 1);
    }
  });
}

4.确定上传时将64编码转成文件形式上传

因为之前可能会涉及到文件的删除,所以考虑在最后上传的时候再将所有的截图64编码进行数据转换。

async function submitForm(formEl) {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
//上述是绑定了表格验证

//下面开始上传文件
      let formData = new FormData();
      formData.append('description', servicesForm.value['description']);

//这里是关于截图部分的64base转码
      if (uploadlist.value.length > 0) {
        uploadlist.value.forEach((e) => {
          //通过atob将base64进行编码
          var bytes = window.atob(e.image.split(',')[1]); 
          //处理异常,将ASCII码小于0的转换为大于0,进行二进制转换
          var buffer = new ArrayBuffer(bytes.length);
          //生成一个8位数的数组
          var uint = new Uint8Array(buffer); 
           //根据长度返回相对应的Unicode 编码
          for (var i = 0; i < bytes.length; i++) {
            uint[i] = bytes.charCodeAt(i); 
          }
          //Blob对象,type为图片的格式
          var imageFile = new Blob([buffer], { type: 'image/jpeg' }); 

           //最后将转换的文件放入要上传的数组中
          imageFilelist.push(imageFile);
        });
        
        //将已转换好的文件进行上传
        for (var i = 0; i < imageFilelist.length; i++) {
          formData.append('picFiles', imageFilelist[i], guid() + '.jpg');
        }
      }
     //上传接口,上传formData数据,关闭弹出框
      addFeedback(formData).then((data) => {
        closeDialog();
        emit('updateData', '');
      });
    }
  });
}

以上。

Logo

前往低代码交流专区

更多推荐