解决移动端一像素问题的Vue指令

27次阅读

共计 1366 个字符,预计需要花费 4 分钟才能阅读完成。

最近公司项目要解决一像素问题,自己琢磨了一阵子并且网上搜索了一堆博客,总结出最好的办法应该是通过 css 的 transform scale 缩放 1px 的内容来模拟设备上 1px 的效果了。但是这个方法有太多局限。然后秉着 css 解决不了的问题就用 js 来解决的原则,然后结合 vue 的自定义指令,手撸了一个一像素 vue 自定义指令。打算扔到 giuhub 留存。顺便总结一下遇到的问题。
项目地址:https://github.com/HelloWorld20/onepx
欢迎各位取用。如有错误的地方,也欢迎指正。
原因
众所周知,自从 iPhone 4 带来了 Retina display 后,移动端开始引入了一个叫设备像素比(devicePixelRatio)的东西。
另一方面,如果给一个 html 标签写一个小于 1px(H5)的 border;IOS 可以正常渲染,但是安卓设备不渲染。所以是不能用正常的方法来让安卓设备渲染一个 1 物理像素的线。
戳这里看 DEMO;
当然用移动端才能看到效果:

网上的解决方案
网上搜能搜出很多解决方案,这篇文章基本汇总了网上的所有方案。然后结论是:使用 css 的伪元素来渲染一个 1px(H5)的 div,并且使用 CSS3 的 scale 来缩放 dpr 倍,从而渲染一个 1px 物理像素的线。
然而理论毕竟理论,用到项目中的时候还是遇到了很多问题
1. 如果两个伪元素都被占用,则无法实现
网上的方案都是用 CSS 伪元素来实现的,而伪元素只有 before 和 after 两个,所以要是实际开发中中占用了 before、after,则无法用 CSS 来实现模拟一像素。
2. 必须手动设置圆角
圆角是最头疼的问题。用 CSS 伪元素虽然可以做到圆角,但是 CSS 伪元素只能通过 border-radius: inherit 得到和父元素一样值的圆角大小,缩放之后就不一样了,且 css 无法计算缩放后还和父元素一样的圆角。而且 js 也不能操作 CSS 伪元素,所以不得不手动计算 dpr,然后给 CSS 伪元素设置圆角。
3. -webkit-device-pixel-ratio 不是标准方法

CSS 中判断设备设备像素比的方法是 -webkit-device-pixel-ratio,不是标准的方法,所以用起来心慌慌。而 JS 的 window.devicePixelRatio 已经全面支持,顶多也就一个 undefined。完全不用担心兼容性问题。
4. 部分标签不能设置伪元素
type 为 text 的 input 标签就无法在标签内插入的 dom(虽然控制台里显示已经被插入,但是不会被渲染出来),所以伪元素也无法给其加上模拟的 1 像素。

更好的方案
本着 CSS 解决不了的问题就用 JS 来解决的思想。再结合 Vue 提供的自定义指令,可以在想要加 1 像素的 html 标签上加上一个指令,js 能通过 Vue 的自定义指令拿到对应的 DOM,那么就一切皆有可能。
最终实现了一个 Vue 指令,只需要给对应的 HTML 标签加上一条指令就行。其他的 Vue 指令自动处理。并且这个指令在我们项目中运行过一段时间,基本是可靠的。
要注意的地方

绑定的元素必须显示声明其 position 值为:relative、fixed、absolute 之一,不然模拟一像素的 div 无法定位到位置
务必给对应的 DOM 清除掉 border 样式
不能用于 <input type=”text” /> 标签等内部不能插入元素的标签

正文完
 0