Vue应用重新初始化不生效、点击事件失效如何解决
Vue应用被第三方弹窗插件移除DOM再插回后,重新初始化实例事件失效问题解决
失效原因
你的写法不生效核心是两点:
- Vue的
$destroy()方法只会销毁实例本身,解绑实例持有的事件、响应式依赖,不会把DOM恢复到Vue编译前的初始状态,也不会自动清掉DOM上残留的Vue标记、已经失效的事件绑定。 - jQuery弹窗插件执行删节点→调位置→插回节点的流程时,旧Vue实例和页面上真实DOM的关联已经断了。等节点插回你再调用
app.$destroy(),销毁逻辑操作的是旧实例手里存的已经脱离文档的DOM引用,根本清不掉当前页面上#app节点的残留内容。新Vue实例挂到这个带旧标记、带失效绑定的DOM上时,不会完整走编译和事件绑定流程,自然所有点击事件都没反应。
解决方法
方案1(通用无坑,适配所有Vue2场景)
第一次初始化Vue之前,先存好#app节点的原始HTML,重新初始化的时候直接把残留的旧节点整个替换成干净的原始节点再挂载,彻底避免DOM残留问题:
// 注意:这行必须在第一次new Vue()之前跑,存下没被Vue编译过的原始DOM const originalAppNodeHtml = document.getElementById('app').outerHTML; let app = null; function initializeApp() { // 把当前有残留的#app替换成干净的原始节点 const currentAppEl = document.getElementById('app'); currentAppEl.outerHTML = originalAppNodeHtml; // 挂载新的Vue实例 app = new Vue({ el: '#app' // 其余配置和你之前的写法完全一致 }); } function afterPopupOpen() { // 先销毁旧实例避免内存泄漏 if (app) app.$destroy(); initializeApp(); }
方案2(适合模板不写在DOM里的场景)
如果你本来就把模板写在Vue配置的template字段或者用render函数,不需要依赖#app里的原始DOM内容,可以不用提前存模板,挂载前手动清掉DOM残留就行:
let app = null; function initializeApp() { const appEl = document.getElementById('app'); // 清空节点所有内容 appEl.innerHTML = ''; // 删掉DOM上挂的旧Vue实例标记 delete appEl.__vue__; // 手动挂载新实例 app = new Vue({ // 这里不要写el配置,把你的模板、业务逻辑都放这 }).$mount(appEl); } function afterPopupOpen() { if (app) app.$destroy(); initializeApp(); }
注意:用方案2的话,必须把原来写在#app标签里的DOM模板挪到Vue实例的
template配置里,不然清空innerHTML之后模板内容会直接丢失。
内容的提问来源于stack exchange,提问作者Pramod Jodhani
相关产品推荐
相关产品推荐

