问题场景:
代码如下图:
图1 html结构 图2 js代码为了排除其他影响因素,我将代码逻辑全部注释掉。只留下一句打印语句。执行结果如下图显示:
图3 打印结果由打印结果可以看出:addGoods这个函数被执行了两次。
问题猜想:1.首先我猜测是由于事件冒泡导致的,即点击事件是绑定在span上面的,span里面还有一个img标签。当点击到按钮时,系统判断同时点击了img和span标签。因此导致事件两次执行。 我将代码改成如下图所示,以阻止事件冒泡:
图4发现问题依然存在,同时回想到打印结果,如果是事件冒泡导致的,两次输出对象应该分别是span和img两个节点对象。但是实际上两次输出都是img节点对象。故排除事件冒泡的猜想。
2.排除事件冒泡后,我认为很可能是在事件绑定的时候造成的。记得vue的click事件有一个once属性。html代码上我将@click改成@click.once字面意思就是点击事件只执行一次。结果是点击虽然只执行了一次,但是后续点击都失效了,所以被once这个属性修饰过的时间,意思是从始至终只能被点击一次。而我们现在的场景是每点击一次都会触发时间,问题是每次点击函数都会执行两次。因为once的处理不符合预期。
3.在找问题的时候发现这个问题只出现在浏览器端,在真机上面测试不会有这个问题。网上有些人遇到类似问题是,不管浏览器,真机上没有问题就可以了。但是我们这个代码的使用场景是包括在浏览器上的。所以这个只在浏览器上出现的问题没办法视而不见。
4.再暂时发现不了问题产生原因的情况下,尝试解决这个问题。既然是连续点击两次,那么我在代码上面利用定时器使函数在短时间内不能连续执行不就可以了?测试代码修改如下:
图5代码逻辑线注释掉,测试主要是看两句打印输出,结果如下图:
图6由图六看出,现在码只会执行一次了,那么把输出替换成代码逻辑就可以了。这个原理是这样的:首先声明一个定时器timer,然后做一个判断,当定时器被赋值的时候先清除定时器,再执行代码逻辑。这就相当于事件依然执行两次,但是在第一次执行的时候,我们利用定时器让它延后300毫秒执行,第二次执行的时候还不到300毫秒,这时候清除定时器,那么第一次的代码就不会被执行,只会执行第二次的。这种处理可以用来防止代码多次不间断的执行。
这个样子问题虽然解决了,但是心里还是觉得不舒服。首先手机真机上面不会出现这个问题,那么我们处理的这段代码对于手机端来说是多余的代码,没有意义。如果再加上判断手机还是浏览器再分别执行,代码会变得臃肿,其次之前做vue项目的时候,从来没有遇到过这个问题。为此,我又新建了一个文件测试。在新文件里面click也是正常只会执行一次。由此断定,这种异常情况是在这个文件中被其他代码所影响的。
重新审视有问题的这个文件,发现了问题的所在了。在这个文件下,我有使用一个叫做better-scroll的插件,目的是为了在不出现滚动条的情况下,项目可以利用transform3d属性滚动。在初始化插件的时候有传入一个对象。
图7里面有一个click:true。将这个属性修改为false,问题彻底解决。
总结:回过头去看这个问题,解决办法非常简单,就只需要修改一句代码。但是解决问题的思路和过程对自己还是会有帮助的。有时候出现问题,我们可以利用各种奇技淫巧来hack。这样相当于是补问题,换句话说,问题依然存在,但是我们利用别的办法消除了这个问题的影响。这种处理有时候是可行的,但是永远不是解决问题的最好方式,最好的方式就是搞清楚问题产生的原因,理清楚问题的产生的逻辑,然后对症下药。共勉!
网友评论