浅谈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是否为空,为空的情况下再重新生成二维码,不为空的情况下直接展示上次生成的二维码。

五:总结

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

相关文章
|
3天前
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
15天前
|
缓存 监控 前端开发
JavaScript 实现大文件上传的方法
【10月更文挑战第17天】通过以上步骤和方法,我们可以实现较为可靠和高效的大文件上传功能。当然,具体的实现方式还需要根据实际的应用场景和服务器要求进行调整和优化。
|
2天前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
2天前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
2天前
|
JavaScript 前端开发
.js方法参数argument
【10月更文挑战第26天】`arguments` 对象为JavaScript函数提供了一种灵活处理参数的方式,能够满足各种不同的参数传递和处理需求,在实际开发中具有广泛的应用价值。
14 7
|
3天前
|
JavaScript 前端开发 图形学
JavaScript 中 Math 对象常用方法
【10月更文挑战第29天】JavaScript中的Math对象提供了丰富多样的数学方法,涵盖了基本数学运算、幂运算、开方、随机数生成、极值获取以及三角函数等多个方面,为各种数学相关的计算和处理提供了强大的支持,是JavaScript编程中不可或缺的一部分。
|
8天前
|
JavaScript 前端开发 Go
异步加载 JS 的方法
【10月更文挑战第24天】异步加载 JavaScript 是提高网页性能和用户体验的重要手段。通过使用不同的方法和技术,可以实现灵活、高效的异步加载 JavaScript。在实际应用中,需要根据具体情况选择合适的方法,并注意处理可能出现的问题,以确保网页能够正常加载和执行。
|
12天前
|
JavaScript 前端开发 持续交付
构建现代Web应用:Vue.js与Node.js的完美结合
【10月更文挑战第22天】随着互联网技术的快速发展,Web应用已经成为了人们日常生活和工作的重要组成部分。前端技术和后端技术的不断创新,为Web应用的构建提供了更多可能。在本篇文章中,我们将探讨Vue.js和Node.js这两大热门技术如何完美结合,构建现代Web应用。
16 4
|
19天前
|
人工智能 JavaScript 网络安全
ToB项目身份认证AD集成(三完):利用ldap.js实现与windows AD对接实现用户搜索、认证、密码修改等功能 - 以及针对中文转义问题的补丁方法
本文详细介绍了如何使用 `ldapjs` 库在 Node.js 中实现与 Windows AD 的交互,包括用户搜索、身份验证、密码修改和重置等功能。通过创建 `LdapService` 类,提供了与 AD 服务器通信的完整解决方案,同时解决了中文字段在 LDAP 操作中被转义的问题。
|
3天前
|
JavaScript 前端开发 开发者