二维码项目中踩坑总结

2020-02-20  本文已影响0人  vonson

\color{red}{处理数据的基本思路是:数据单向流动 如果有多个来源的数据,在不能保证顺序的时候,需要合并成一个数据去处理}

1.组件先于接收的请求参数;
解决方案:
①子组件watch监听后进行数据相关操作;

watch: {
        qrcodeList: {
            deep: true,
            handler(val) {
                this.getLogos(val)
            }
        }
    },

②父组件引用的时候使用v-if懒加载方式;

2.对数组中的item做数据转化(增加字段)
解决方案:在计算属性computed遍历做转化;
注意:computed是优于methods和watch执行的,如若使用到watch中的数据源,watch之后computed会再次执行,computed自由缓存机制;

 renderList() {
            return this.qrcodeList.map((item, index) => {
                item.qrImg = this.logoImages[item.logoFileId] ?       
                this.logoImages[item.logoFileId] : '';
                return item;
            })
        }

3.场景问题:根据数组中的某id通过接口去异步获取id对应的某个值,
每个item是否有值是不确定的,最后需要将id和值一一对应;

getLogos(list) {
            let ids = []
            list.map((item, index) => {
                if (item.logoFileId) {
                    ids.push(item.logoFileId)
                }
            })
            qrcodeService.getFiles(ids).then((res) => {
                let [err, images] = res;
                // this.logoImages = images
                var imgObj = {};
                var arr = images;
                arr.map(item => {
                    imgObj[item.name] = item.src
                })
                this.logoImages = imgObj
            })
        },

4.场景问题:引用二维码渲染插件,参数为一个对象,对象中的数据需要做特殊处理,对象最后还需要处理的情况,插件还在数组中需要遍历;
<div class="code-item" v-for="(qrItem,index) in qrcodeList" :key="index">
<QRCode :options="options" />
</div>
实现思路:
① <QRCode :options="{
size: item.size,
data: item.url,
logo: item.logo
}" />
存在问题:
a.此处无直接的中间的logo url,需要做数据处理;
方案:对qrcodeList做处理,首先watch qrcodeList数据源,进行异步接口处理,得到相应的logo url,放入一个对象数组;再根据qrcodeList生成一个新的list包含一一对应的含log url的新字段;

①
watch: {
        qrcodeList: {
            deep: true,
            handler(val) {
                this.getLogos(val)
            }
        }
    },
②
getLogos(list) {
            let ids = []
            list.map((item, index) => {
                if (item.logoFileId) {
                    ids.push(item.logoFileId)
                }
            })
            qrcodeService.getFiles(ids).then((res) => {
                let [err, images] = res;
                // this.logoImages = images
                var imgObj = {};
                var arr = images;
                arr.map(item => {
                    imgObj[item.name] = item.src
                })
                this.logoImages = imgObj
            })
        },
③
computed: {
        renderList() {
            return this.qrcodeList.map((item, index) => {
                item.qrImg = this.logoImages[item.logoFileId] ?     
                this.logoImages[item.logoFileId] : '';
                return item;
            })
        }
    },

b. 此处的options直接通过item相关的键值渲染,无法实现处理数据this.options的相关操作;
解决方案:
新增一个中间子组件qrcode,将处理好的item相关的数据传入到子组件,在子组件中拼装options;
父组件:

import qrcode from './qrcode';
<qrcode class="qrImg"
                        :logo="item.logourl"
                        :size="defaultSize"
                        :data="item.qrUrl" />

子组件:

<QRCode :options="options" />
 data() {
    return {
      options: {
        size: this.size,
        data: this.data,
        logo: this.logo
      }
    };
  },
watch得到logo的url时对options进项后续操作;
watch: {
    logo(src) {
      const image = new Image();
      image.src = src;
      image.onload = () => {
        this.options = Object.assign({}, this.options, {
          logo: {
            image
          }
        });
      };
    }
  },

5.下载相关问题;
①vue-qr插件,生成二维码是通过将二维码图片和logo图片转化成blob的方式,如若logo的url地址不是同域,而是阿里云之类的,会出现logo跨域问题,暂未发现解决方式;(无法生成带logo二维码)
②qrcanvas-vue插件,生成二维码方式是通过canvas方式,跨域logo可直接生成,但是生成canvas图片本质上也有跨域下载问题,是否可转化为url或文件流等下载?待尝试(可生成带logo二维码,无法下载?)
③通过后端返回文件流形式的二维码图片;
存在问题:
a.接口返回的response非普通接口含有相应的errcode等字段,无法使用项目中统一封装的axios,需要重新实例化一个全新的axios;
b.请求传参问题;
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/responseType
解决方案:传参时和header同级的地方添加responseType: 'blob',
return axios.post(${baseUrl}/download/qrCode, pars, {
responseType: 'blob',
headers: byHeaders()
})
如若是文档等,需要responseType: 'arraybuffer',
文件流下载的两种方式:

let blob = new Blob([res.data], { type: 'image/jpeg' });
                // const blob = res.data;
                const reader = new FileReader();
                reader.onload = (e) => {
                    const a = document.createElement('a');
                    a.download = item.qrName;
                    // 后端设置的文件名称在res.headers的 "content-disposition": "form-data; name=\"attachment\"; filename=\"20181211191944.zip\"",
                    a.href = e.target.result;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);


let a = document.createElement('a');
                let blob = new Blob([res.data], { type: 'image/jpeg' });
                let objectUrl = URL.createObjectURL(blob);
                a.setAttribute('href', objectUrl);
                let downName = item.qrName
                a.setAttribute('download', `${downName}(${size}x${size})`);
                a.click();

下载中如果下载的文件名包含各种特殊字符,下载的文件会出现无后缀名,无法显示的问题;
// 处理特殊字符

                const pattern = /[`~!@#$^&*()=|{}':;',\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;
                downName = downName.replace(pattern, '');

待强化问题:
1.深刻理解computed,watch,filter等不同使用场景及区别;
2.深刻理解canvas,blob,base64,url和文件流等相关区别;

上一篇下一篇

猜你喜欢

热点阅读