Subscribe on changes!

render函数和mount() 函数,在挂载的元素在文档流中移除后,没有正确释放。

avatar
Dec 8th 2023

Vue version

3.4.0-alpha.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9UsFq3DAQ/ZWJDrEXXC8ht8W70JaFpDRNSQOloIuxx2ul8shIsrvF+N87krebBEIOtjVv3ozfvNEkPvZ9Pg4oNqJwlVW9B4d+6HeSVNcb62ECi03GL6rRZtBmhu7MQB7rGRprOki4PJGk0QNqkFQZch46d4BtKE2TG9TawE9jdX2RrCRJagaqvDIElcXSP8TW6WqSBKHFxRYGRhpFWMPlJUO5xc6MmHJxZGyhNtXQIfk8dsC9xhClUtRqlOLEy1XNVCm6v3stRcCWKdJwBGjThNlJxiOqegNJY0ySKSK0N493Xxlog/AE5lW2FKAOX24+Szq7kKar7S5KZ+NuGbFjqZ9BeD1jgObsKvTgp1gvnrPbHHjses3DcARQtFe7aYo2znOx5iiiLBgqXTq3lYJ9v29/oZNiV6w5sTAU9YOH8UNnatTM4g5SwJqTxfrFH0QmvONVNeqQPzlDfAGiXikq0/VKo73vw4q4+wZOk0hRsiF/vkTM2wFPvnBNi9XvN/AndwyYFN8tOnYGpTjnfGkP6Jf0/sc3PPL5nGT1g2b2O8kHdEYPQeNC+8SXhmW/4EW1t/EaKzo8uv3RI7n/QwWhyzqWudnOz++M/iz3Or+OdbxDMf8D2Y0Ruw==

Steps to reproduce

  1. 创建一个元素
  2. 在此元素上 使用 render&h 或 defineComponent&mount 挂载一些元素
  3. 移除这个元素
  4. 重复1-3
  5. 打开内存快照,查找 Detached HTMLDivElement 。发现此项只增不减。

What is expected?

在被挂载的元素移除后,释放dom的引用和内存。

What is actually happening?

在被挂载的元素移除后,无法释放dom的引用和内存。

System Info

No response

Any additional comments?

No response

avatar
Dec 11th 2023

没复现出来啊。Collect Garbage 后,DOM 节点会被回收。

avatar
Dec 11th 2023

His meaning is that I used a certain component in the template. Afterward, I manually obtained this element, removed the element, and the instance of the corresponding component will not be destroyed. This is as expected because Vue does not monitor the removal of DOM. Therefore, the component instance will not be destroyed.

avatar
Dec 11th 2023

@edison1105 我这能复现的 image 我在mapbox的popup的setHTML方法中append一个元素,然后用render再挂载一个到popup的元素上,popup remove时,被挂载的元素没有释放,我在mapbox也提了issue了,人家让我找vue😂https://github.com/mapbox/mapbox-gl-js/issues/12954

avatar
Dec 11th 2023

image

你提供的 reproduction 是不能复现的。 能提供一个不带 mapbox 的复现吗?

avatar
Dec 11th 2023

你是否期望得到一下效果?在dom移除后卸载dom所渲染的组件实例,但是你只执行了 dom.remove() ,这不会使组件卸载,您应该在移除dom的同时,卸载组件实例,你可以尝试一下方式:

Palyground

let unmount
let count = 0
function renderApp() {
  unmount?.()
  const el = document.createElement("div")
  document.body.appendChild(el)
  const app = createApp(TestComponentsBox, { id: 'foo', innerHTML: 'hello' + ++count })
  app.mount(el)

  unmount = () => {
    // 卸载app
    app.unmount()
    // 移除dom
    el.remove()
  }
}
avatar
Dec 11th 2023

如 @Alfred-Skyblue 所说,你需要先卸载 Vue app 再移除 DOM 元素,这并非 Vue 的问题。