zoom引发的tooltip错位
Demo预览:
https://sunzsh.github.io/vue-demos/#/tooltipzoom
代码:
https://github.com/sunzsh/vue-el-demo/blob/master/src/views/tooltipzoom.vue
这个bug的两个解决思路挺好玩哈
我们先来看问题
这个小伙伴说啊
他只要给body设置这个zoom属性(样式)
然后再拉动滚动条啊
这个tooltip就会错位
大家看滚动的越远
错位的也就越远
大家看下边这个就错到这来了
为了方便调试啊
我把这个代码放到了我本地的demo里了
就是这样看看他也是错位的
我们看下边错位的更多一样的
然后啊我们先去快速的定位一下问题
我们先点到tooltip里
然后点到这个main里
然后这里边我之前再给大家介绍过
这里边有个updatePopper方法
这updatePopper在哪呢
其实在
mixins就是这个proper里边
我们再点到这个proper
然后这里边呢
我们再搜一下updatePopper
在这里
然后这里边它又调了popperJS的update方法
popperJS在哪呢
我们再来搜一下
它在这new了一个popperJS
这个popperJS呢就在上面声明的在这里
require popper然后我们再去看这个popper文件
popper文件里边我们再来搜
update方法
然后这个update的方法里边
关于位置的就是这个offset
我们再看这个offset方法
大家看这里边
他最终会把这个变量的left呀
top呀都赋值给这个结果然后返回
那我们来看这个变量哪来的
在这里他调了这个方法得到这个变量
我们再来点进去
好,这个方法就很重要了
因为这个bug的
根本原因出在了这个方法上
为什么呢
因为这个方法会拿到
我们这个button
元素在整个屏幕的一个位置
然后呢他再去定位这个popper
应该放在什么位置
但是呢如果我们设置了zoom
他这个方法拿到的数据就不准了
我们可以来验证一下,怎么验证呢?
首先啊我们先选中上面这个
拿上面这个button来举例子
选中他以后呢
document.documentElement.scrollTop
大家看 现在是
然后呢我把它设置成1,让它滚动一点
(1个像素)
之后呢我们再来看button的位置
点getBondingClientRect
然后呢.top(我们就看TOP值)
大看现在是这个数
然后我们再把滚动条滚动到头(0的位置)
回到0的位置我们再来看一下.top
我们来看一下相差了多少
用这个数减去这个数
那为什么不是1呢
其实这就跟我们设置的这个Zoom
等于1.2有关系
我们可以算一下
我们用1/1.2就是这个数0.83333几
我们可以再这样验证
我们把这个1.2改成1.
刷新一下
然后啊我们滚到顶先把这个button
打印出来
它的帮顶top值打印出来
这个大概是103点几
然后呢
我们再让滚动条往下滚一个像素
然后我们再打一下button的这个bounding值
大家看,是102点几
我们再来算一下他们差多少
减去
这个值
他看是0.
我们再用1除以1.
大家看看
就是0.
所以啊
出现这个错位的原因就是当我们
设置了zoom之后
再滚动的时候
再去获取这个绑定值
他就不准了
找到了原因
我们怎么去解决这个问题呢
我们再回头看一下这个方法
他刚才调的就是这个方法
然后他在这里调的我们刚才用的这个
HTMLElement的原生的这个方法
外边这个方法
我们肯定是没办法重写了
我们要重写的话呢
只能考虑重写里边的这个方法
这个方法就是HTML原生的了
我给大家分享两个方案
希望这两个方案能对大家以后解决
其他bug有所帮助哈
第一个方案呢
就是我们全局来改HTMLElement
里边的prototype的
这个BoundingClientRect方法
我们首先把HTML原声的这个boundingClientRect
的备份到一个bak方法备份起来
然后呢
我们来重新指定它的这个rect方法
在这里呢我们先去调用它原生的方法
(就是我们刚才备份那个去掉)
把这个this传进去拿到一个结果
这个时候注意我们要在这判断一下
因为
我们设置的zoom是针对body设置的
所以如果我们拿到是documentElement
其实这个时候
他拿到的这个位置是准确的
只有它里边的元素
在获取这个邦丁clientRect的时候
是不准的
所以我们
外边这个就不要再去用zoom去较准了
为什么呢
我们来看一下啊这个方法
他在调用的时候啊
他不止在调用当前这个元素
他还在调用这个parent
那这个parent是什么呢
我们再往上找
他在这调用呢
大家看这个就是那个button
这个popper是那个弹出的那个层(黑色的)
大家看这个方法里边
它是取这个offsetParent,同时取到的
offsetParent如果是body
它会返回(强制返回)一个documentElement
我们来试一下
我们先让它弹出
然后呢我们检查这个元素
为了不让它关闭
咱们先禁用一下Javascript
鼠标不要离开那里啊
直接输入disable Javascript
然后呢我们这时候移开就行了
这时候再选中它
注意选中这个tooltip了
然后我们 $0.offsetParent
大看是body
所以回到这
如果是body他强制返回了一个element
也就是说我们重写的这个方法呀
被用来计算这个button的位置
他可能也会用来计算document的位置
但document的位置呢
因为他没有外层没有缩放
所以这个位置是准的
我们就不用再做校准了啊
然后再往下我们拿到zoom
zoom就是我们设那个一点几:1.6、1.
然后呢
分别取到纵向和横向的滚动条的位置
然后根据这个zoom计算偏差
然后重新返回一个DOMRect
把这个偏差加上左右(都去解决一下)
我们再来试一下啊
刷新一下
好大家看!这个时候滚动就准确了
我们再看下边
大家看都没有问题了
那第二个方法是什么呢
我们先把它禁用掉
第二个方法我们就不改prototype的这个
rect方法了
我们呀写一个vue的指令
然后在指令里拿到这个element的
之后啊
我们单独针对这个对象去改他的
这个rect的方法
先去把原来的备份一下
然后思路跟刚才是一样的
然后最终用的时候呢我们在页面上
找到这个button
这个button现在位置是不准确的
我先保存试一下
刷新大家看是有偏差的
然后给这个button加上v
然后这个指令
刷新
大看这样就准了
下边的还不准
我们再来看一下
下边的就不知道偏哪去了
这个关掉
好,在下边…
然后呢我们把下边这个按钮也加一个
好刷新
大家看,下边的也准了
最后更新于
这有帮助吗?