浅谈Vue中的this.$nextTick()方法(利用QRCode.js在dialog弹窗中生成二维码)

简介: 浅谈Vue中的this.$nextTick()方法(利用QRCode.js在dialog弹窗中生成二维码)

一:前言

最近在做项目时候需要实现微信扫码支付功能,已经在后端获取到了微信服务器返回的Code_url,但是却难倒在了前端如何将Code_url转换成二维码的问题上(还怎么做全干工程师!),具体问题为获取不到用来装载二维码的div元素对象,从早上弄到下午,无果,晚上经大佬指点了一下豁然开朗,现将此问题记录下来希望有遇到同样问题的人看到我这篇文章后能少走弯路。

二:问题引入

在项目中我用到的生成二维码工具是QRCode.js,其帮助文档可以查看这里,要在静态页面中实现并不难,只需要将其相关函数直接拷贝下来即可运行,但是在我的项目中我的需求是当用户点击“支付”按钮时候就会弹出dialog弹窗,弹窗里面会展现支付二维码供用户扫码支付。要成功生成二维码,就需要通过new QRCode(element, option)函数生成一个可执行对象,其中element表示显示二维码的元素或该元素的 ID,option表示参数配置,我的简化代码如下:

<div id="add_order" class="app">
    <button type="button" @click="ORCode">支付</button>
    <!-- 微信支付二维码 -->
    <el-dialog :visible.sync="codeDialogVisible" :show-close="false" @close="closeDialog" width="300px" center>
        <div ref="qrcode" style="width:100px; height:100px; margin-top:100px; margin-left:40%;"></div>
        使用微信扫码支付
    </el-dialog>
    <!-- <div ref="qrcode"  style="width:100px; height:100px; margin-top:100px; margin-left:40%;"></div> -->
</div>
<!--ORCode-->
<script type="text/javascript" src="http://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="http://static.runoob.com/assets/qrcode/qrcode.min.js"></script>
<script>
    new Vue({
        el: "#add_order",
        data() {
            return {
                codeDialogVisible: false, //微信支付二维码弹窗
                Code_url: 'https://www.baidu.com/'
            }
        },
        methods: {
            //展示支付二维码
            ORCode() {
                console.log(this.$refs.qrcode);
                let qrcode = new QRCode(this.$refs.qrcode, {
                    width: 100,
                    height: 100,
                    correctLevel: QRCode.CorrectLevel.L
                });
                // console.log(qrcode);
                qrcode.makeCode(this.Code_url);
                //打开二维码弹窗
                this.codeDialogVisible = true
            },
            //关闭微信支付二维码对话框
            closeDialog() {
                this.payBtnDisabled = false
            },
        }
    })
</script>

理想情况下当用户点击支付按钮时候就会调用ORCode函数,函数先生成qrcode对象,然后再调用qrcode.makeCode()方法生成二维码,最后设置弹窗属性为可见将二维码展示出来,运行结果如下:

可以看到元素对象为undefined,这也就直接导致后面程序报错,修改程序,将div单独提取出来:

<div id="add_order" class="app">
    <button type="button" @click="ORCode">支付</button>
    <!-- 微信支付二维码 -->
    <el-dialog :visible.sync="codeDialogVisible" :show-close="false" @close="closeDialog" width="300px" center>
        <!-- <div ref="qrcode"  style="width:100px; height:100px; margin-top:100px; margin-left:40%;"></div> -->
        使用微信扫码支付
    </el-dialog>
    <div ref="qrcode" style="width:100px; height:100px; margin-top:100px; margin-left:40%;"></div>
</div>

运行结果如下:

可以看到成功获取到DOM并生成二维码,这时候问题来了,为什么将这个DOM放进dialog弹窗时候就获取不到呢?原因很简单,因为dialog的visiable属性初始设置为fase,这也就直接导致获取不到里面的DOM元素。接下来尝试在执行new QRCode(element, option)函数之前将visiable属性设置为true使得可以获取到其里面的DOM元素:

//展示支付二维码
ORCode() {
    //打开二维码弹窗(设置visible属性)
    this.codeDialogVisible = true
    console.log("显示二维码的元素(div)="+this.$refs.qrcode);
    let qrcode = new QRCode(this.$refs.qrcode, {
        width : 100,
        height : 100,
        correctLevel:QRCode.CorrectLevel.L
    });
    // console.log(qrcode);
    qrcode.makeCode(this.Code_url);
},

可以看到还是获取不到DOM元素,我就是在这里被卡住了,后来经过大佬提示尝试用this.$nextTick()方法,程序修改如下:

//展示支付二维码
ORCode() {
    //打开二维码弹窗(设置visible属性)
    this.codeDialogVisible = true
    this.$nextTick(()=>{
        console.log("显示二维码的元素(div)="+this.$refs.qrcode);
        let qrcode = new QRCode(this.$refs.qrcode, {
            width : 100,
            height : 100,
            correctLevel:QRCode.CorrectLevel.L
        });
        // console.log(qrcode);
        qrcode.makeCode(this.Code_url);
    })
},

可以看到成功运行,这里要注意的是必须将this.codeDialogVisible = true放在nextTick()函数外面,具体原因等你看完下面对nextTick函数的介绍就懂了。

三:this.$nextTick()函数介绍

**this.nextTick()**方法主要是用在随数据改变而改变的dom应用场景中,vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.nextTick()方法主要是用在随数据改变而改变的dom应用场景中,vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.nextTick()的回调函数中。

程序调用created()时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,所以,created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,所以在mounted()中操作dom基本不会存在渲染问题。

简单的理解,vue.js中this.$nextTick()就是起到了一个等待数据的作用,也就是说,将一些回调延迟,等到DOM更新之后再开始执行。再简单点说,相当于setTimeout()的作用。

例如:

1.你改变了dom元素数据,然后你又想输出dom,那你只能等到dom更新完成之后才会实现,在程序中我要修改的是visible属性,因此要获取里面的dom(即div),就必须等待其修改完成后才能获取,这也就能理解为什么我说必须将this.codeDialogVisible = true放在nextTick()函数外面。

2.通过事件改变data数据,然后输出dom,在方法里直接打印的话, 由于dom元素还没有更新, 因此打印出来的还是未改变之前的值,(体现为虽然我在第二次报错中虽然将visible属性设置成了true,但是这时候dom元素实质上还没更新完成就通过this.refs.qrcode获取DOM显然是获取不到的,这时候的visible属性还是为false),而通过this.refs.qrcode获取DOM显然是获取不到的,这时候的visible属性还是为false),而通过this.nextTick()获取到的值为dom更新之后的值,这时候就可以成功获取DOM了。

四:优化

当我将弹窗关闭再次点击支付时候,二维码会多次生成造成盒子叠加的情况,具体现象见下图:

显然这是很不友好的,改进代码如下:

new Vue({
    el: "#add_order",
    data() {
        return {
            codeDialogVisible: false, //微信支付二维码弹窗
            Code_url: 'https://www.baidu.com/',
            qrcode: null,
        }
    },
    methods: {
        //展示支付二维码
        ORCode() {
            //打开二维码弹窗(设置visible属性)
            this.codeDialogVisible = true
            this.$nextTick(() => {
                console.log("显示二维码的元素(div)=" + this.$refs.qrcode);
                if (this.qrcode != null) {
                    this.qrcode.clear(); // 清除代码
                }
                else {
                    this.qrcode = new QRCode(this.$refs.qrcode, {
                        width: 100,
                        height: 100,
                        correctLevel: QRCode.CorrectLevel.L
                    });
                    // console.log(qrcode);
                    //生成二维码
                    this.qrcode.makeCode(this.Code_url);
                }
            })
        },
        //关闭微信支付二维码对话框
        closeDialog() {
            this.payBtnDisabled = false
        },
    }
})

改进措施为将qrcode放到data里面,然后在调用QRCode方法时候先判断qrcode是否为空,为空的情况下再重新生成二维码,不为空的情况下直接展示上次生成的二维码。

五:总结

有问题在网上找不到解决方法及时找大佬!有问题在网上找不到解决方法及时找大佬!有问题在网上找不到解决方法及时找大佬!虽然自己搜索也能学到东西,但是别人给你指明方向你再有针对性地进行查找学到的东西会更好,印象也会更深刻,后续我开发完微信支付这个功能后会继续发布相关文章供大家参考,喜欢的可以点点关注。

相关文章
|
20天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
18天前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
114 52
|
1月前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
1月前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
19天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
28 5
|
20天前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
24 1
|
1月前
|
JavaScript 前端开发
.js方法参数argument
【10月更文挑战第26天】`arguments` 对象为JavaScript函数提供了一种灵活处理参数的方式,能够满足各种不同的参数传递和处理需求,在实际开发中具有广泛的应用价值。
38 7
|
1月前
|
JavaScript 前端开发 图形学
JavaScript 中 Math 对象常用方法
【10月更文挑战第29天】JavaScript中的Math对象提供了丰富多样的数学方法,涵盖了基本数学运算、幂运算、开方、随机数生成、极值获取以及三角函数等多个方面,为各种数学相关的计算和处理提供了强大的支持,是JavaScript编程中不可或缺的一部分。
|
1月前
|
JavaScript 前端开发 开发者