【vue自定义组件】前端生成二维码

前言

佛祖保佑, 永无bug。Hello 大家好!我是海的对岸!

期望效果

背景

这次需求是要做一个二维码的需求,涉及到移动端操作,让移动端扫码,进行一系列的逻辑,最后移动端处理好了,电脑端点击确认,重新刷新数据,把移动端提交的数据获取到,并在电脑端显示出来

功能实现

首先,我先查询了一下,前端生成二维码的方法

可以看出,方法很多,有qrcode.js, jquery-qrcode, 等等,因为本次项目是vue2技术栈,所以,依旧使用 npm/yarn 的方式安装第三方包。

一番资料查询下来,发现qrcodejs2 使用的人蛮多的,基本可能存在的坑也踩的差不多了,因此,决定使用 qrcodejs2进行需求的实现。

实现步骤

插件安装

bash 复制代码
npm install qrcodejs2 -S
或
yarn add qrcodejs2

我安装之后的版本是 (防止出现可能隐藏的问题,存在第三方包版本后续升级,导致相同的代码,最后实现不了效果)

bash 复制代码
"qrcodejs2": "^0.0.2",

如果要安装指定版本

bash 复制代码
npm install qrcodejs2@0.0.2 -S
或
yarn add qrcodejs2@0.0.2

使用

前置剧情

因为我的二维码生成,是放在一个弹框里面,我这里图方便,就把二维码直接写在弹框里了,之所以这么干,主要还有另一个问题。

之前是用 element-uidialog组件,这是一个现成的弹框,直接把二维码的标签容器,放进去,结果,element-ui的dialog 没打开的时候,在dom树中是不存在的,你打开之后,才创建出来的,相当于是一个v-if的那种效果。

二维码的生成方法,是依赖那个dom树中存放二维码标签的容器的,所以在dialog组件没打开的时候,这个二维码容器的标签是不存在的,所以会出现一个报错。

比如我二维码存放的标签是这个:

csharp 复制代码
<div ref="qrcode" class="img"></div>

dialog还没有打开之前,这个标签是不存在的,那么,我需要使用this.nextTick(() => {...}),等弹框加载好了,之后才能去调用二维码的生成方法。

而我当下的场景,是弹框里面再套一个弹框,第一个弹框A展示内容,第二个弹框B显示二维码,而第一个弹框里面的内容较多,加载就要一会,而第二个弹框,里面就一个二维码,然后还有一个确认,取消按钮,其他就没了,与其再写一个this.nextTick,不如直接梭哈。

所以,我果断自己手搓一个简单的div,来充当弹框使用。

正式开干

大致需求如下:

  1. 点击一个生成二维码的按钮,打开一个弹框,里面有一个二维码,还有一个确定,取消按钮
  2. 确定按钮,是移动端扫码之后,在移动设备上,把逻辑操作完成之后,点击确定,从接口获取最新数据
  3. 取消按钮,关闭二维码弹框
  4. 鼠标悬停到二维码图像上,可以刷新二维码
  5. 确定按钮点击之后,页面上刷新,拿到最新数据,会把签名图片加载出来,悬停签名图片,可以删除签名

(二维码生成的)核心代码:

bash 复制代码
<template>
    ...
    <div ref="qrcode" class="img"></div>
    ...
</template>

<script>
export default {
    data() {
        return {
           showImg: false,         // 是否显示企业签名二维码的弹框,默认false
           qrcode: '',             // 二维码数据   
        };
    },
    methods: {
        // 生成企业签名二维码
        getQRInviteCode() {
          // 清除上一次的二维码
          if (this.$refs.qrcode) {
            this.$refs.qrcode.innerHTML = ''; // 清除二维码方法
          }

          // 生成二维码(这里有个坑,一定要在 new关键字前面用 等于号,赋给一个变量,否则vue运行会报错)
          this.qrcode = new QRCode(this.$refs.qrcode, {
            width: 70,  // 二维码宽度 (不支持100%)
            height: 70, // 二维码高度(不支持100%)
            text: 'www.baidu.com', // 后端返回的二维码地址,这里暂时写死
            render: 'canvas', // 设置渲染方式(有两种方式 table和canvas,默认是canvas)
          });
        },
    },
};
</script>

其他的效果基本就是和css相关,

  • 简易弹框

涉及到的知识点,就是一个遮罩,加一个内容框,因为我这里是在弹框A的里面,再做要给弹框的效果,要注意遮罩是封盖全屏的,一不小心,就会把设置弄成只覆盖到弹框A自身,弹框A外的区域就没覆盖掉

这个时候,把 position 设置成 fixed就满足条件了

  • 悬停刷新
  • 悬停删除

完整代码

bash 复制代码
<template>
<div>
...
  <div class="enterprise-signature">
    <div class="btn">
      <el-button type="primary" @click="openImg">企业二维码</el-button>
    </div>
    <!-- 这里到时候要从接口获取签名数据,这里先写假数据,写个2条,意思一下 -->
    <div class="signature">
      <div class="img-item">
        <img class="img" src="https://copyright.bdstatic.com/vcg/creative/cc9c744cf9f7c864889c563cbdeddce6.jpg@h_1280"/>
        <span class="option">
          <i class="el-icon-delete" @click="delImg('id001')"></i>
        </span>
      </div>
    </div>
    <div class="signature">
      <div class="img-item">
        <img class="img" src="https://copyright.bdstatic.com/vcg/creative/cc9c744cf9f7c864889c563cbdeddce6.jpg@h_1280"/>
        <span class="option">
          <i class="el-icon-delete" @click="delImg('id002')"></i>
        </span>
      </div>
    </div>
  </div>
  ...
    <!-- 手戳弹框的问题,主要在于样式,html部分其实不复杂 -->
    <div class="enterprise-dialog" v-show="showImg">
      <div class="content">
        <div class="title">企业签名</div>
        <div class="item-pic" >
          <div class="qrcode-item">
            <div ref="qrcode" class="img"></div>
            <!-- 悬停刷新二维码 -->
            <span class="option">
              <i class="el-icon-refresh" @click="getQRInviteCode()"></i>
            </span>
          </div>
        </div>
        <div class="tip">请扫码签名,完成后点击确认</div>

        <div class="foot">
          <el-button type="primary" @click="closeImg(true)">确 定</el-button>
          <el-button @click="closeImg(false)">取 消</el-button>
        </div>
      </div>
    </div>
</div>  
<template>

<script>
...
import QRCode from 'qrcodejs2';
...

export default {
    ...
    data() {
        return {
            ...
           showImg: false,         // 是否显示企业签名二维码的弹框,默认false
           qrcode: '',             // 二维码数据            
        };
    },
    methods: {
        ...
        // 删除企业签名
       delImg(id) {
        console.log('id', id);
       },
       // 关闭企业弹框
       async closeImg(isSure) {
          // 确认 并重新加载
          if (isSure) {
            // 重新加载最新数据
            ...
          }
          // 取消
          this.showImg = false;
        },
        // 打开企业弹框
        openImg() {
          this.showImg = true;
          this.getQRInviteCode(); // 调用二维码的方法
        },
        // 生成企业签名二维码
        getQRInviteCode() {
          // 清除上一次的二维码
          if (this.$refs.qrcode) {
            this.$refs.qrcode.innerHTML = ''; // 清除二维码方法
          }

          // 生成二维码
          this.qrcode = new QRCode(this.$refs.qrcode, {
            width: 70,  // 二维码宽度 (不支持100%)
            height: 70, // 二维码高度(不支持100%)
            text: 'www.baidu.com', // 后端返回的二维码地址
            render: 'canvas', // 设置渲染方式(有两种方式 table和canvas,默认是canvas)
          });
        },
    },
};
<script>

<style lang="scss" scoped>
...
.enterprise-signature {
  height: 100px;
  display: flex;
  .btn {
    width: 100px;
    display: flex;
    align-items: center;
  }
  .signature {
    width: 100px;
    display: flex;
    align-items: center;
    margin-right: 5px;
    .img-item {
      width: 100px;
      height: 50px;
      position: relative;
      .img {
        width: 100%;
        height: 100%;
      }
      .option {
        opacity: 0;
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        text-align: center;
        line-height: 50px;
        cursor: pointer;
        color: #fff;
        background-color: rgba(0,0,0,.5);
        transition: opacity .3s;
      }
      &:hover {
        .option {
          opacity: 1;
        }
      }
    }
  }
}
.enterprise-dialog {
  position: fixed;
  z-index: 999;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0,0,0,.5);
  .content {
    position: absolute;
    top: 33%;
    left: 42%;
    width: 300px;
    height: 250px;
    background-color: white;
    .title {
      height: 40px;
      line-height: 40px;
      padding-left: 20px;
      font-size: 16px;
      font-weight: bold;
    }
    .item-pic {
      height: 114px;
      display: flex;
      justify-content: center;
      align-items: center;
      .qrcode-item {
        position: relative;
        .img {
          width: 70px;
          height: 70px;
        }
        .option {
          opacity: 0;
          position: absolute;
          left: 0;
          top: 0;
          width: 100%;
          height: 100%;
          text-align: center;
          line-height: 75px;
          font-size: 32px;
          cursor: pointer;
          color: #fff;
          background-color: rgba(0,0,0,.5);
          transition: opacity .3s;
        }
        &:hover {
          .option {
            opacity: 1;
          }
        }
      }
    }
    .tip {
      text-align: center;
      height: 40px;
      line-height: 20px;
    }
    .foot {
      text-align: center;
    }
  }
}
</style>

参考文章

1.【前端】前端页面直接根据URL链接生成二维码【亲测可用】

2.Vue使用qrcodejs2实现二维码生成

相关推荐
还是大剑师兰特30 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解31 分钟前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~37 分钟前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding42 分钟前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
man201744 分钟前
【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
vue.js·spring boot·后端
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django