Hey , you !


  • Home

  • Archives

使用 qrcodejs 生成二维码的几个问题

Posted on 2018-10-03 | In js

Preface

产品希望我这边下载页面加个二维码,可以扫描下载 APP,并且希望二维码中有公司的 logo,很合理的需求,不过实现的时候依旧遇到了几个问题,在此记录下。

Main

二维码的实现逻辑我当然没有这个时间去研究,直接用的 qrcodejs。官方给的 demo 是最简单的版本,各种各样的需求都是在 issues 里找到的提示,似乎这个库已经很久没有人去维护了,虽然 star 是很多。

官网示例(改编)

<div id="qrcode" class="qrcode"></div>
.qrcode {
width: 150px;
height: 150px;
border: 2px solid green;
margin-top: 15px;
}
let qrcodeEl = document.getElementById('qrcode')
let qrcode = new QRCode(qrcodeEl, {
text: 'https://avatars1.githubusercontent.com/u/23273077',
width: 128,
height: 128,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
})

效果如图:

截图20181003145142.png

尺寸控制

我给官网的示例加上了边框,二维码的尺寸和 js 里的尺寸不一样,这个缺点立马就暴露出来了。

我很可能是想生成的二维码填满传入的 qrcode 元素的,但是这里的 width 不支持 100%,更不支持 vw 这种尺寸单位了。当然,我可以用 qrcode.offsetWidth 来解决这个问题,但是如果 qrcode 的尺寸后期会动态修改的话,那不还是会有问题么。

经 SO 的提示,发现了一个好方案,

.qrcode {
width: 150px;
height: 150px;
border: 2px solid green;
margin-top: 15px;
}
.qrcode canvas + img {
width: 100%;
height: 100%;
}

这样就可以了,不过仍然有个不足,就是二维码有失真。经测试,只有传入的尺寸和 qrcode 的尺寸一样时,才不会失真,所以传入的尺寸还是需要动态计算。不过,可以试试 svg 的 qrcode 库,svg 不会出现这个问题。

加 logo 的二维码

qrcodejs 并没有提供这个 API,issues 里有人给了 demo,其实就是在原有元素上覆盖一个 logo 就可以了,虽然遮盖了原有二维码的一部分,但是实测并不影响扫描。不过我没有进行大规模测试,可能会有一定的错误率。

<div id="qrcode" class="qrcode">
<img
src="https://avatars1.githubusercontent.com/u/23273077"
class="qrcode__logo"
/>
</div>
.qrcode {
width: 150px;
height: 150px;
border: 2px solid green;
margin-top: 15px;
position: relative;
}

.qrcode canvas + img {
width: 100%;
height: 100%;
}
.qrcode__logo {
width: 50px;
height: 50px;
border-radius: 10%;
border: 1px solid #fff;
position: absolute;
margin: auto;
left: 0;
top: 0;
right: 0;
bottom: 0;
}

效果如图:

截图20181003164515.png

检测二维码的生成

某些情况下,我需要重用二维码,在这种情况下,我发现,二维码的生成是异步的,譬如:

let qrcodeEl = document.getElementById('qrcode')
let qrcode = new QRCode(qrcodeEl, {
text: 'https://avatars1.githubusercontent.com/u/23273077',
width: 200,
height: 200,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
})
let qrcodeImg = document.querySelectorAll('.qrcode canvas+img')
console.log('qrcodeImg.src', qrcodeImg.src)
setTimeout(function() {
console.log('qrcodeImg.src', qrcodeImg.src)
}, 1000)

第一个日志就是空白的,第二个才有 base64。搞笑的是,qrcodejs 也没有给出回调或者通知告诉用户什么时候生成完毕。

这个问题也是在 issues 里找到的提示,关键点在于 MutationObserver。

这个 API 很少在项目中用,因为不兼容性 ie11-,但是有时在几千行代码里 debug 时会用,尤其是我怀疑中间有代码改了某个元素的属性,确又找不到证据或者找不到哪段代码时,会用这个来监测下。在这里的用法如下:

let qrcodeEl = document.getElementById('qrcode')
let qrcode = new QRCode(qrcodeEl, {
text: 'https://avatars1.githubusercontent.com/u/23273077',
width: 200,
height: 200,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
})
let qrcodeImg = document.querySelector('.qrcode canvas+img')
listenQrcodeSrc()
function listenQrcodeSrc() {
var observeConfig = { attributes: true }
var observeCb = function(mutationsList, observer) {
mutationsList.forEach(function(mutation) {
if (
mutation.type.toLowerCase() === 'attributes' &&
mutation.attributeName.toLowerCase() === 'src'
) {
console.log('qrcodeImg src done!', mutation.target.src)
observer.disconnect()
}
})
}
if (typeof MutationObserver !== 'undefined') {
var observer = new MutationObserver(observeCb)
observer.observe(qrcodeImg, observeConfig)
}
}

微信中二维码要放在 img 中,不能放在 background-image

2019.1.31 ,微信 7.0.0 亲测

微信中多个二维码在一起识别错误

这个问题,我也遇到了,根据网友的提示,微信是截屏识别的,所以会出现这种问题。我测试的结果是,左右两个,永远识别的右边的那个。网上有好几种方案:

  • 调透明度和层级

最初尝试过,结果发现失败,等到成功的时候,透明度已经小于 0.5 了,视觉差异太明显,所以放弃了这个方案。

  • 替换二维码

最终采取的是这个,这个也有问题,就是用户会看到二维码变化的过程,除非你把多个二维码做得很像。

假设,我们要显示两个二维码,所谓替换二维码,其实也就是在多个 img.src 属性里切换,可以把实际的二维码保存在 data-real-src 属性里,然后在用户 touchstart 事件中,替换另一个 img 的 src 为当前按下的这个,然后在 touchend 事件中再改回来,因为原来的地址都保存在 data-real-src 属性里。

这里就用到了前面提到的检测 src 属性来判断 qrcode 生成完毕,否则一开始直接把 src 属性赋给 data-real-src 属性,就是空白。

示例代码(这里代码跟前面脱节了,dom 是另外的结构,仅作为示例代码):

//* pubMethods 是类似 jq 的一些 API 的汇总对象
var qrcodeImgs = pubMethods.$('.download__qrcode-box canvas+img')
listenQrcodeSrc()
var downloadBox = pubMethods.$('.download')[0]
downloadBox.addEventListener('touchstart', changeQrcodeSrcToOne)
downloadBox.addEventListener('touchend', changeQrcodeSrcBack)
downloadBox.addEventListener('touchcancel', changeQrcodeSrcBack)

function listenQrcodeSrc() {
var observeConfig = { attributes: true }
var observeCb = function(mutationsList, observer) {
mutationsList.forEach(function(mutation) {
if (
mutation.type.toLowerCase() === 'attributes' &&
mutation.attributeName.toLowerCase() === 'src'
) {
mutation.target.setAttribute('data-real-src', mutation.target.src)
observer.disconnect()
}
})
}
qrcodeImgs.forEach(function(ele) {
if (typeof MutationObserver !== 'undefined') {
var observer = new MutationObserver(observeCb)
observer.observe(ele, observeConfig)
}
})
}
function changeQrcodeSrcToOne(event) {
var target = event.target
var getQrcodeBox = pubMethods.closest(
target,
'.download__qrcode-box',
downloadBox
)
if (getQrcodeBox) {
var targetImg = qrcodeImgs.filter(function(ele) {
return getQrcodeBox.contains(ele)
})[0]
qrcodeImgs.forEach(function(ele) {
ele.src = targetImg.getAttribute('data-real-src')
})
}
}
function changeQrcodeSrcBack(event) {
qrcodeImgs.forEach(function(ele) {
ele.src = ele.getAttribute('data-real-src')
})
}

Ending

Reference

  • Make qr code full width

  • 微信中有两个挨着二维码长按识别的问题?

自定义微信分享样式

Posted on 2018-10-02 | In js

Preface

产品希望我们在微信分享出去的链接,有自己的样式,而不是仅仅一个链接。用产品的话来说,你发给客户一个链接,客户敢点么???

听着比较有意思,不过也不能说完全没有道理,毕竟各种各样的诈骗大家也是有所耳闻,经确认,产品想要:

截图20181002175453.png

而我们当前分享是:

截图20181002175558.png

Main

总监给我提示说,微信有 js-sdk ,可以在 js 里设置这个样式。

于是,我找到了微信 JS-SDK 说明文档,基本上就是根据文档走些配置,这个要和产品那边要些账号密码,改些东西之类,根据文档来,没什么好说的。

大体流程如下:

  1. 步骤一:绑定域名
  2. 步骤二:引入 JS 文件
  3. 步骤三:通过 config 接口注入权限验证配置
wx.config({}) //传入一些初始化参数
  1. 步骤四:通过 ready 接口处理成功验证
wx.ready(function() {}) //传入成功回调
  1. 步骤五:通过 error 接口处理失败验证
wx.error(function() {}) //传入失败回调

实际操作的时候,遇到了几点麻烦,这里需要提一下:

测试的时候,注意开启 debug 模式,方便定位问题。

wx.config({ debug: true /*其他参数*/ })

出于安全考虑,开发者必须在服务器端实现签名的逻辑。

这个是文档说的,反正就是给后台处理了,最终前端初始化需要的几个字段,除了 debug 和 jsApiList ,都是从后台拿的。

wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});

后台在实现的时候,可能需要注意文档提示的两点:

  1. access_token(有效期 7200 秒,开发者必须在自己的服务全局缓存 access_token)

  2. jsapi_ticket(有效期 7200 秒,开发者必须在自己的服务全局缓存 jsapi_ticket)

因为这会导致一开始生成的签名没错,但是两个小时后就失效了。

代码逻辑

通常的逻辑都是前端从后台拿到上面的几个字段,在前端完成初始化,然后添加初始化成功和失败的回调。

示例:

var link = location.href
$.ajax({
url: 'your_url', //后台给你提供的接口
type: 'GET',
data: { url: link },
async: true,
dataType: 'json',
success: function(data) {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
appId: data.configMap.appId, // 必填,公众号的唯一标识
timestamp: data.configMap.timestamp, // 必填,生成签名的时间戳
nonceStr: data.configMap.nonceStr, // 必填,生成签名的随机串
signature: data.configMap.signature, // 必填,签名,见附录1
jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
})
wx.ready(function(res) {
wx.onMenuShareAppMessage({
title: document.title,
desc: document.title,
link: link,
imgUrl: Imgurl,
trigger: function(res) {},
success: function(res) {},
cancel: function(res) {},
fail: function(res) {}
})
wx.onMenuShareTimeline({
title: document.title,
link: link,
imgUrl: Imgurl,
trigger: function(res) {},
success: function(res) {},
cancel: function(res) {},
fail: function(res) {}
})
})
wx.error(function(res) {
alert(res)
})
},
error: function(error) {
alert(error)
}
})

我司稍微特殊些,直接把初始化的代码放在前面需要引入微信的 js 文件后面了,所以我直接引入这个文件就完成了初始化操作。不过,我还是需要在引入后监听初始化成功和失败的回调。

我司代码:

<script src="./js/shareInWeChat.js?debug=1"></script>
<!-- 里面包含了 wx.config({}) 的代码-->
<!-- 通过 debug 参数来切换调试模式 -->
setWeChatShareStyle(product, imgUrl)
function setWeChatShareStyle(product, imgUrl) {
var success = function(res) {}
var fail = function(res) {}
var desc =
product.description && product.description !== ''
? product.description
: '后备描述'
wx.ready(function() {
var eventConf = {
title: product.name,
desc: desc,
imgUrl: imgUrl,
link: window.location.href,
success: success
}
if (pubMethods.isAndroid()) {
// 安卓适用于老接口,新接口不行
wx.onMenuShareAppMessage(eventConf)
wx.onMenuShareTimeline(eventConf)
wx.onMenuShareQQ(eventConf)
wx.onMenuShareQZone(eventConf)
}
if (pubMethods.isIOS()) {
// iOS 适用于新接口,老接口不行
wx.updateAppMessageShareData(eventConf, success)
wx.updateTimelineShareData(eventConf, success)
}
})
wx.error(fail)
}

最初我担心,这样可能会监听不到 wx.config 初始化的结果,结果发现还是可以监听到的,说明 wx.config 里面的操作是个异步操作。

代码兼容性

  • 统一传参

如上面代码所示,虽然根据微信的文档,对于不同的接口,传的参数稍有区别,但是我为了方便,都放在 eventConf 里面了,事实证明也是可以的(不可以我就要吐槽了,毕竟传入的是对象)。

  • 接口更新的 bug

虽然微信文档上有接口更新的说明:

请注意,原有的 wx.onMenuShareTimeline、wx.onMenuShareAppMessage、wx.onMenuShareQQ、wx.onMenuShareQZone 接口,即将废弃。请尽快迁移使用客户端 6.7.2 及 JSSDK 1.4.0 以上版本支持的 wx.updateAppMessageShareData、updateTimelineShareData 接口。

但我实际上测试的结果是,安卓不支持新接口,iOS 支持,但是我如果把新老接口全用上,有一端会失败,所以最终才有上面那个机型判断的结果,对于不同的机型采用了不同的接口。

if (pubMethods.isAndroid()) {
// 安卓适用于老接口,新接口不行
wx.onMenuShareAppMessage(eventConf)
wx.onMenuShareTimeline(eventConf)
wx.onMenuShareQQ(eventConf)
wx.onMenuShareQZone(eventConf)
}
if (pubMethods.isIOS()) {
// iOS 适用于新接口,老接口不行
wx.updateAppMessageShareData(eventConf, success)
wx.updateTimelineShareData(eventConf, success)
}
  • 分享的图片不能是 base64

由于我司需要对图片进行处理再去分享,所以当我用 canvas 导出 base64 作为 imgUrl 的时候,我发现是没有效果的。

Ending

Reference

  • 微信分享自定义样式

  • 微信分享图标设置,以及 wx.config 配置

settings in vscode

Posted on 2018-09-23 | In software

配置

  1. vscode 支持特定语言的设置,比如,为不同的语言设置不同的配置:
{
"[html]": {
"editor.tabSize": 4
},
"[css]": {
"editor.tabSize": 4
},
"[javascript]": {
"editor.insertSpaces": true,
"editor.tabSize": 2
},
"[typescript]": {
"editor.tabSize": 2
}
}
  1. 个别插件的配置比较特殊,需要配置后才能正常使用,譬如 csscomb, eslint, Easy LESS 等,注意查看文档。

  2. 我的配置文件,借助 Settings Sync VSCode 插件,不定期修改会同步到 https://gist.github.com/xianshenglu

相关插件

HTML:

Auto Rename Tag 修改 HTML 标签时,自动修改匹配的标签

Open in Browser

HTML CSS Class Completion: CSS class 提示

HTMLHint: HTML 格式提示

CSS:

Can I Use: HTML5、CSS3、SVG 的浏览器兼容性检查

Color Highlight: 颜色值在代码中高亮显示

Color Picker: 拾色器

csscomb: css 排序,格式化,支持 .vue,但对于嵌入式样式缩进有问题

HTML CSS Support: css 提示,支持 .vue

JS

ESLint: ESLint 语法校验,自动格式化,修改等

Version Lens package.json: 文件显示模块当前版本和最新版本

View Node Package: 快速打开选中模块的主页和代码仓库

JavaScript (ES6) code snippets: ES6 语法代码段

Version Lens: 在 package.json 里显示包最新版本号

HTML/CSS/JS

Emmet: html,css,js 提示

框架

vetur: 目前比较好的 Vue 语法高亮

VueHelper: Vue2 代码段(包括 Vue2 api、vue-router2、vuex2)

vue-peek: vue 文件内查找速览声明

vue-format: vue 格式化插件

非语言类

Bracket Pair Colorizer: 不同层级括号上色

Code Spelling Checker: 单词拼写检查

Output Colorizer: 彩色输出信息

Partial Diff: 对比两段代码或文件

Path Autocomplete: 路径补全

Path Intellisense: 路径提示

Project Manager: 快速切换项目

Settings Sync VSCode: 设置同步到 Gist

1…111213…18

xianshenglu

54 posts
14 categories
142 tags
© 2023 xianshenglu
Powered by Hexo
|
Theme — NexT.Muse v5.1.4