前言:
最近运营反馈了一个问题:谷歌浏览器打开第三方储值平台,使用谷歌浏览器自带的翻译功能后,选择商品没有计算总额。
首先可以肯定的是这不是bug,这个平台已经兼容了13种语言,只是运营没有通过语言栏切换语言,而是通过谷歌翻译。
当初想到的方法禁止谷歌浏览器翻译当前页面,如下:(已采用)
但站在技术的角度来说,看看为什么还是有必要的,储值平台基于Vue,计算总额应用了双向数据绑定;为什么谷歌翻译后,Vue双向数据绑定失效?真的是失效了吗?接下来我们以最简单的例子还原案发现场,顺便解读一下这部分相关Vue源码。
问题重现
如下图,实现简单的双向数据绑定,name初始化为test:
刷新浏览器,将当前页面翻译成中文,如下图:
翻译后再次输入,下边没有更新输入的内容。
源码分析
首先自信地排除这是业务代码的bug,然后我们自信地看看框架相关部分的源码。
浏览器翻译前
可以看到,浏览器翻译前,当输入新的数据,这个文本节点的新旧虚拟DOM会进行对比;text不一样时会执行setTextContent方法,如下如所示。
setTextContent负责在值有变化时,把对应的值赋值给对应dom节点的textContent
执行完这步后,此时节点的textContent就变成了Your name is test1
浏览器翻译后
刷新浏览器恢复初始化数据,右击翻译后开始调试。
1)翻译后,DOM结构有什么变化?
可以看到谷歌翻译后,dom节点自动添加了标签,如图:
2)setTextContent是否还有执行?
经调试发现此方法仍有执行,并且text是正常的。
结论:问题出在传进来的node,node是旧虚拟DOM对应的真实DOM,由于翻译导致DOM结构发生了变化,在执行node.textContent = text前,这个node已经不存在了。
验证
如果结论正确,那么到node.textContent = text前,结果都还是符合预期的,我们给vue源码增加一句代码,把这个找不到了的DOM节点重新挂载到文档中,如下箭头所示:
运行结果:
输入test1,虽然谷歌翻译的那段没变化,但document.body.appendChild(node)得到了想要的结果,控制台访问一下data中的name,也是有更新的。
再试试数据驱动,也还可行:
快速地敲一敲,也行得通:
从这个角度来说,谷歌浏览器翻译后,Vue双向数据绑定其实并没有失效,只是翻译导致DOM结构发生了变更,Vue找不到原来的节点去更新数据了。