You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue2程序化创建组件时,如何获取DOM节点的插槽内容?

Vue 2.7.14:程序化实例化组件时读取DOM props与插槽的方法

在Vue 2.7.14中,直接通过new VueComponentConstructor({el: ...})实例化组件时,Vue不会自动解析目标DOM节点上的props属性和插槽内容——这是因为手动实例化的流程跳过了根Vue实例编译模板时自动处理组件props、插槽的环节。以下是具体解决方案:

1. 读取DOM上的Props属性

除了手动传入propsData,还可以从目标DOM元素自动提取并转换props:

  • 获取目标DOM元素,提取所有属性
  • 过滤出组件声明的props,同时将kebab-case格式的属性名转为camelCase(比如prop-name转propName)
  • 将处理后的props传入实例化选项的propsData中

2. 复用DOM中的插槽内容

手动实例化时需要手动收集DOM中的插槽内容,传入组件实例的slots选项(Vue 2.7支持该选项):

  • 对于具名插槽,找到DOM中对应v-slot:name(或slot="name")的模板元素
  • 将插槽内容转为Vue可识别的VNode,或者封装为函数式插槽
  • 在实例化时通过slots选项传入对应名称的插槽内容

修改后的示例代码

JavaScript代码

const Test = Vue.component('Test',{
  name: 'Test',
  props: ['prop'],
  template: `<div class="hello">
                SLOTCONTENT: <slot name="name">default from template</slot><br>
                PROPS: {{$props}}
             </div>`
});

// 根实例挂载(正常工作)
new Vue({el:'#el1'})

// 工具函数:从DOM提取props
function extractProps(el, componentProps) {
  const props = {};
  const attributes = el.attributes;
  for (let i = 0; i < attributes.length; i++) {
    const attr = attributes[i];
    const propName = attr.name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
    if (componentProps.includes(propName)) {
      props[propName] = attr.value;
    }
  }
  return props;
}

// 工具函数:从DOM提取具名插槽
function extractSlots(el) {
  const slots = {};
  // 查找所有具名template插槽
  const templateSlots = el.querySelectorAll('template[v-slot\\:name], template[slot="name"]');
  if (templateSlots.length) {
    // 将插槽内容转为VNode,借助Vue的createElement
    slots.name = function(createElement) {
      return Array.from(templateSlots[0].childNodes).map(node => {
        if (node.nodeType === Node.TEXT_NODE) {
          return node.textContent.trim() ? createElement('span', node.textContent.trim()) : null;
        } else if (node.nodeType === Node.ELEMENT_NODE) {
          return createElement(node.tagName.toLowerCase(), {}, Array.from(node.childNodes).map(child => {
            return child.nodeType === Node.TEXT_NODE ? child.textContent.trim() : createElement(child.tagName.toLowerCase());
          }));
        }
      }).filter(Boolean);
    };
  }
  return slots;
}

// 实例化Test组件并处理props和插槽
const el2 = document.getElementById('el2');
new Test({
  el: el2,
  propsData: extractProps(el2, Test.options.props),
  slots: extractSlots(el2)
});

const el3 = document.getElementById('el3');
new Test({
  el: el3,
  propsData: {...extractProps(el3, Test.options.props), prop: 'el3prop from propsdata'},
  slots: extractSlots(el3)
});

HTML代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.14/vue.min.js"></script>

Component created with new Vue()
<Test id="el1" prop="el1prop">
  <template #name>el1 (from markup)</template>
</Test>
<br><br> Component created with new Test()
<Test id="el2" prop="el2prop">
  <template #name>el2 (from markup)</template>
</Test>
<br><br> Component created with new Test() propsData supplied
<Test id="el3" prop="el3prop">
  <template #name>el3 (from markup)</template>
</Test>

内容的提问来源于stack exchange,提问作者Joschi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:37:03