Vue中render函数挂载el-dialog到body但标签未解析问题?

参考element-plus的notification函数式调用实现
准备自己搞个el-dialog函数式调用,但是使用vue里面导出的render后,可以成功挂载到body上,但是标签还是el-dialog,没有解析成div

image.png

// Index.vue
<template>
  <el-dialog
    append-to-body
    destroy-on-close
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :width="dialogWidth"
    style="--el-dialog-border-radius: 8px"
    class="common-dialog"
  >
    <slot />
  </el-dialog>
</template>
import { VNode, createVNode, ref, render } from 'vue'
import DialogConstructor from './Index.vue'

export const createDialog = (
  content: VNode,
  options: { show?: boolean } = {}
) => {
  const show = ref(options.show ?? true)

  const vm = createVNode(
    DialogConstructor,
    { modelValue: show.value },
    () => content
  )
  render(vm, document.body)

  return {
    open: () => (show.value = true),
    close: () => (show.value = false)
  }
}
// 用法
  const dialog = createDialog(
    h(Form, {
      loading: loading.value,
      modelValue: model.value,
      onSubmit: () =>
        execute(model.value).then(() => {
          dialog.close()
          emits('refresh')
        })
    })
  )

试过用tsx,也不行

阅读 2.8k
avatarAI BotBETA
在 Vue 中使用 `render` 函数将组件挂载到 `body` 上时,确保组件被正确解析和渲染的关键在于确保组件的全局注册以及正确传递 `props` 和 `slots`。在你的案例中,`el-dialog` 组件没有解析成 `div`,可能是因为 `DialogConstructor` 组件(即 `Index.vue`)没有正确接收到或处理 `props` 和 `slots`。

首先,确保 `el-dialog` 组件在你的项目中已经正确安装并全局注册(如果你使用的是 Element Plus)。然后,检查以下几点:

1. **确保 `DialogConstructor` 正确处理 `v-model`**: 在 Vue 3 中,`v-model` 默认绑定到 `modelValue` prop 和一个名为 `update:modelValue` 的事件。你需要确保 `DialogConstructor` 组件内部正确处理了这个绑定。例如,你可能需要在 `Index.vue` 中添加一个监听器来响应 `modelValue` 的变化。

2. **正确传递 `slots`**: 在你的 `createDialog` 函数中,你尝试通过传递一个函数给 `createVNode` 来设置 `slots`。这种方式在某些情况下可能不工作,尤其是当组件内部对 `slots` 的处理有特定要求时。尝试改用对象语法来明确指定 `slots`。

3. **使用 `app.mount` 替代 `render`**: 如果你是在 Vue 3 环境中,并且已经创建了一个 Vue 应用实例(`app`),使用 `app.mount` 可能是一个更好的选择来挂载组件,因为它会自动处理组件的解析和渲染。然而,由于你想将组件挂载到 `body` 而不是应用的根元素,你可能需要调整你的应用结构或使用其他方法来确保组件的样式和作用域隔离。

4. **检查样式和作用域**: 当组件被挂载到 `body` 时,它可能脱离了原本的 Vue 应用的作用域,这可能导致样式或作用域问题。确保你的组件样式被正确地应用到挂载的组件上。

5. **使用 `h` 函数创建 VNode**: 在你的用法示例中,你使用了 `h` 函数来创建 `Form` 组件的 VNode。确保 `h` 函数是从 Vue 导入的,并且 `Form` 组件已经正确注册。

修正后的 `createDialog` 函数可能看起来像这样:

import { VNode, createVNode, ref, h, render } from 'vue'
import DialogConstructor from './Index.vue'

export const createDialog = (
content: VNode | (() => VNode),
options: { show?: boolean } = {}
) => {
const show = ref(options.show ?? true);

// 使用对象语法明确指定默认插槽内容
const vnode = createVNode(

DialogConstructor,
{ modelValue: show.value, 'update:modelValue': (value) => show.value = value },
{ default: () => typeof content === 'function' ? content() : content }

);

render(vnode, document.body);

return {

open: () => show.value = true,
close: () => show.value = false

};
}


注意,这里我假设 `DialogConstructor` 组件内部能够正确处理 `modelValue` 和 `update:modelValue`。此外,我添加了类型检查来确保 `content` 可以是一个 VNode 或一个返回 VNode 的函数。
1 个回答
vm.appContext = createDialog._context

然后在main.js
createDialog._context = app._context
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏