一、需求:当body的有了zoom值之后,element ui相关的popper弹框(下拉框、日期选择框、分页组件)位置都会出现偏移问题
二、问题来源
popper弹框都会需要根据屏幕x,y的坐标来设置位置,但是有了zoom值之后,x,y坐标就会获取错误,这是element ui官方的一个bug,当前element ui已经停止维护了,所以我们就得更改源码。
三、如何解决
1.使用饿了么官方解决方式(不推荐,因为只能解决这两个组件偏移问题,而且当在弹框打开下拉框又会重新这个问题)
select组件添加:popper-append-to-body="false"
<el-select :popper-append-to-body="false" v-model="value" placeholder="请选择"><el-optionv-for="item in options":key="item.value":label="item.label":value="item.value"></el-option></el-select>
date-picker组件添加:append-to-body="false"
<el-date-picker:append-to-body="false"v-model="value1"type="date"placeholder="选择日期"></el-date-picker>
2.通过修改源码的方式(推荐,一劳永逸)
在'element-ui/lib/utils/popper.js文件中
的617行634行和635行中进行修改
var styles = {position: data.offsets.popper.position,direction: data.placement}
else {//获取当前zoomvar zoom = window.getComputedStyle(document.body).zoomstyles.left = leftstyles.top = top//当有zoom值时,重新修改样式if (zoom !== '1') {//其中top-start和top是popper打开的方向,可以通过打印styles.direction来判断这个组件的打开方向if (styles.direction === 'top-start') {styles.left = left / zoom//40或者30是我自己定的,这个方法不能100%还原之前的效果,可以自定义值styles.top = top / zoom + 40} else if (styles.direction === 'top') {styles.left = left / zoomstyles.top = top / zoom + 30} else {styles.left = left / zoomstyles.top = top / zoom}}}
修改源码的方式虽好,但是重新下依赖就会丢失修改的代码(如果你想防御性编程的话,就不用看后面的了)
将我们修改后的源码抽离出来为一个js文件,再全局使用,即使重新下载依赖也生效
1.创建element-ui-bug-fixed.js
文件
import Popper from 'element-ui/lib/utils/popper'
Popper.prototype.modifiers.applyStyle = function (data) {// console.log(data.placement);// apply the final offsets to the popper// NOTE: 1 DOM access herevar styles = {position: data.offsets.popper.position,direction: data.placement}// round top and left to avoid blurry textvar left = Math.round(data.offsets.popper.left)var top = Math.round(data.offsets.popper.top)// if gpuAcceleration is set to true and transform is supported, we use `translate3d` to apply the position to the popper// we automatically use the supported prefixed version if neededvar prefixedPropertyif (this._options.gpuAcceleration &&(prefixedProperty = getSupportedPropertyName('transform'))) {styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)'styles.top = 0styles.left = 0}// othwerise, we use the standard `left` and `top` propertieselse {//获取当前zoomvar zoom = window.getComputedStyle(document.body).zoomstyles.left = leftstyles.top = top//当有zoom值时,重新修改样式if (zoom !== '1') {//其中top-start和top是popper打开的方向,可以通过打印styles.direction来判断这个组件的打开方向if (styles.direction === 'top-start') {styles.left = left / zoom//40或者30是我自己定的,这个方法不能100%还原之前的效果,可以自定义值styles.top = top / zoom + 40} else if (styles.direction === 'top') {styles.left = left / zoomstyles.top = top / zoom + 30} else {styles.left = left / zoomstyles.top = top / zoom}}}// any property present in `data.styles` will be applied to the popper,// in this way we can make the 3rd party modifiers add custom styles to it// Be aware, modifiers could override the properties defined in the previous// lines of this modifier!Object.assign(styles, data.styles)setStyle(this._popper, styles)// set an attribute which will be useful to style the tooltip (use it to properly position its arrow)// NOTE: 1 DOM access herethis._popper.setAttribute('x-placement', data.placement)// if the arrow modifier is required and the arrow style has been computed, apply the arrow styleif (this.isModifierRequired(this.modifiers.applyStyle, this.modifiers.arrow) &&data.offsets.arrow) {setStyle(data.arrowElement, data.offsets.arrow)}return data
}
function setStyle (element, styles) {function is_numeric (n) {return n !== '' && !isNaN(parseFloat(n)) && isFinite(n)}Object.keys(styles).forEach(function (prop) {var unit = ''// add unit if the value is numeric and is one of the followingif (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !==-1 &&is_numeric(styles[prop])) {unit = 'px'}element.style[prop] = styles[prop] + unit})
}
2.在main.js
文件中添加这个文件(注意路径)
//解决饿了么缩放bug
import '@/utils/element-ui-bug-fixed' // 引入自定义的 Popper 修改脚本
上才艺!!!