当前位置: 首页 > Web前端 > vue.js

更改ElementUI具体组件弹出浮层中的默认父节点

时间:2023-03-31 15:48:55 vue.js

Cascader级联选择器或TimePicker,点击DatePicker选择器后的浮层直接插入到body标签下,elementUI会自动计算出一个合适的Dots位置浮层绝对。但是最近在公司使用ElementUI框架的项目中,因为有特殊需求,这类组件的浮层不能脱离.vue的功能组件,所以默认在body下插入浮层的方法一定不能满足要求。ELementUI中的Select选择器组件提供了一个属性来控制下拉菜单是否插入到body中:所以对于select,只需要将这个属性设置为false即可,但是对于Cascader,TimePicker,DatePicker这些组件是没有这个的财产。这个问题我想了很久,花了90%的心血,想出了下面的方法来模拟实现。将Cascader组件的浮层父节点设置为id为wrap的节点,并使用popper-class属性为浮层定义一个类名,后面需要获取。为Cascader组件定义一个id,后面会用到;监听Cascader组件自带的visible-change事件,在浮层弹出时启动一个timer定时器,寻找浮层dom节点;找到浮层节点后,将浮层插入指定节点,这样body下的浮层节点就相当于被裁剪到指定节点;此时Cascader组件还处于弹出状态,但是原来检测到的浮层被裁掉了,裁掉的新地址还没有检测到,所以关闭再打开就相当于重新启动了。因为这里需要手动触发点击事件,而Cascader组件的点击事件定义在elementUI内部,用native不容易触发,所以这里引入jquery,在其实例上使用trigger方法触发点击事件;在这个过程中需要加一个锁标志,防止手动触发浮层时进入定时器。示例:设置Cascader组件浮层的父节点为id为wrap的节点(为了强调,示例中省略了一些不相关的代码)

import$from'jquery'exportdefault{data(){return{timer:null,flag:true,//锁定,手动触发浮层时控制不进入计时器...//省略}},方法:{visibleChange(e){if(e&&this.flag){this.flag=falsethis.timer=setInterval(()=>{letfloatingLayer=document.getElementsByClassName('floating-layer')[0];if(floatingLayer&&floatingLayer.style.display==""){//获取浮层的dom节点,但不能为隐藏状态document.getElementById('wrap').appendChild(floatingLayer)//在wrap节点下插入浮层$(document.getElementById('el_cascader')).trigger('click')//第一次关闭浮层$(document.getElementById('el_cascader')).trigger('click')//第二次time打开浮层clearInterval(this.timer)this.timer=null}},300)}else{this.flag=trueclearInterval(this.timer)this.timer=null}},}}willTimePicker,DatePicker选择器components如果浮层的父节点设置id为wrap,如果是TimePicker或者DatePicker选择器,因为没有类似Cascader组件的visible-change事件,但是可以用focus和blur事件代替,但是思路同TimePicker和DatePicker浮层父节点变化后选择器的位置值好像是基于HTML的,所以underwrap自然会有偏差,所以需要加个修正号,或者位置应该直接设置为固定位置。Cascader组件好像没有这个问题,我也没有深究。下面是一个简化的代码。我在当前项目中只使用了这些组件,其他组件不需要这样特殊处理,但是我觉得这个思路是可行的,有需要的朋友可以自己琢磨。上面提到的一些内部原理都是我的猜测。具体演示我没有看源码。反正这个方法解决了我的问题,不知道还有什么好办法吗?欢迎有想法的同学给我留言讨论。