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
相关产品推荐
相关产品推荐

