最近在使用qiankun框架对vue子应用进行拆分时,出现了此问题:在子应用使用element中的下拉框,会被定位到父应用的顶部,同时控制台报错如下:
报错原因
element中的下拉框是通过appendChild的方式添加到对应的位置,而在使用的时候可能主应用和子应用都使用了element,子应用内下拉框无法准确识别,因此appendChild到了父应用上。
解决方法一
首先在【父应用】内若开启了沙箱的strictStyleIsolation,需要关闭,没有就不管
既然是appendChild方法无法识别子应用内,那么就在【子应用内】重写appendChild方法;在项目根文件内(main.js),生成实例render方法中改变append到子应用中。
// 顶部定义一个全局的originFn,最后卸载时需要还原给父应用
let originFn = document.body.appendChild.bind(document.body)
// 实例生成
function render(props = {}) {
console.log('routes ', routes);
const { container } = props;
redirectPopup(container)
const router = initRouter()
// 为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围
instance = new Vue({
router,
store,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
// 重写子应用的element的appendChild方法 element组件弹出框挂在到子应用内
function redirectPopup(container) {
// 子应用中需要挂载到子应用的弹窗的className,用作标记
const addPopup = 'el-select-dropdown el-popper el-zoom-in-top-leave el-zoom-in-top-leave-active'
const editPopup = 'el-select-dropdown el-popper'
const whiteList = [addPopup, editPopup]
// 保存原有document.body.appendChild方法
let originFn = document.body.appendChild.bind(document.body)
// 重写appendChild方法
document.body.appendChild = (dom) => {
// 根据标记,来区分是否用新的挂载方式
if (whiteList.includes(dom.className)) {
container.querySelector('#app').appendChild(dom)
} else {
originFn(dom)
}
}
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
document.body.appendChild = originFn; // 卸载时还原append方法
removeRouter()
}
如果设置之后定位到了子应用内,但是还是没能定位到准确位置(测试的时候,全部定位到了子应用内,但是都是在子应用的顶部)
不妨尝试重新启动项目,或者重新拉去一个新的项目下来试试(自己电脑上死活都是定位到子应用顶部,别人都正常,重新拉去项目后正常)
解决方法二
如果第一种方法没能解决弹出框的定位问题,element中也给出了一个定位解决方案
即对每一个下拉框中添加这个属性popper-append-to-body: false; 只是通常我们项目中的下拉框数量比较多,若是一个一个添加就较为麻烦
如果各位大佬还有其他更好的解决方法,还请告知🙏🙏🙏