Vue 中的渲染函数和递归组件
Posted
技术标签:
【中文标题】Vue 中的渲染函数和递归组件【英文标题】:Render Functions and Recursive Components in Vue 【发布时间】:2020-09-11 11:22:28 【问题描述】:我在理解递归组件时遇到了一些麻烦,我相信对于我想要完成的事情,这可能是最好的方法。这是我目前所处的位置的小提琴,将在下面解释。
https://jsfiddle.net/wp0hon7z/2/
我正在尝试遍历嵌套的 JSON,它本质上是在模仿 DOM。每个“节点”看起来像这样。您可以打开 fiddle 以查看更多嵌套的 JSON 和
"tagName": "section",
"classes": ["container", "mx-auto"],
"attrs": "id":"main",
"textNode": "",
"children": []
目前我能够递归地遍历并将每个节点创建到一个组件中,并将它们放入一个组件数组中,我在 Vue 实例中填充该数组。
问题是,子组件需要显示在父组件内。我在想也许用组件对象创建一个对象,然后使用递归组件来解析这些,但我不知道该怎么做。
另一个想法可能是创建一个带有父 ID 的平面组件数组?然后可能以某种方式使用它?
有关如何进行此操作的一些指导会很棒,我认为递归组件会有所帮助,但不确定除了创建元素/渲染函数之外我还能如何使用它。每个节点都需要与类列表、属性列表、on 等进行 2 路绑定。我计划跟踪这些并使用状态/存储进行编辑,可能是 vuex。
目前在 Fiddle 中看到的代码会显示 JSON 中的所有组件,但没有嵌套,所以只是一个接一个。
const jsonData = [
"tagName": "section",
"classes": ["container","mx-auto"],
"attrs": ,
"textNode": "",
"children": [
"tagName": "div",
"classes": ["flex","flex-wrap"],
"attrs": ,
"textNode": "",
"children": [
"tagName": "div",
"classes": ["w-1/2"],
"attrs": ,
"textNode": "Hello"
,
"tagName": "div",
"classes": ["w-1/2"],
"attrs": ,
"textNode": "Goodbye"
]
]
];
let Components = [];
let uuid = 0;
function recurse()
recursiveInitialize(jsonData)
function recursiveInitialize(j)
if (Array.isArray(j))
return j.map((child) => recursiveInitialize(child))
if (j.children && j.children.length > 0)
initializeComponent(j)
console.log("Hi I am " + j["tagName"] + " and a parent")
j.children.forEach((c) =>
console.log("Hi I am " + c["tagName"] + " and my parent is " + j["tagName"])
recursiveInitialize(c)
);
else
console.log("Hi, I dont have any kids, I am " + j["tagName"])
initializeComponent(j)
function initializeComponent(jsonBlock)
let tempComponent =
name: jsonBlock["tagName"]+ uuid.toString(),
methods:
greet()
store.setMessageAction(this)
,
data: function()
return
tagName: jsonBlock["tagName"],
classes: jsonBlock["classes"],
attrs: jsonBlock["attrs"],
children: jsonBlock["children"],
textNode: jsonBlock["textNode"],
on: click: this.greet,
ref: uuid,
,
beforeCreate()
this.uuid = uuid.toString();
uuid += 1;
,
render: function(createElement)
return createElement(this.tagName,
class: this.classes,
on:
click: this.greet
,
attrs: this.attrs,
, this.textNode);
,
mounted()
// example usage
console.log('This ID:', this.uuid);
,
Components.push(tempComponent);
return tempComponent
const App = new Vue(
el: '#app',
data:
children: [
Components
],
,
beforeCreate()
recurse();
console.log("recurseRan")
,
mounted()
this.populate()
,
methods:
populate()
let i = 0;
let numberOfItems = Components.length;
for (i = 0; i < numberOfItems; i++)
console.log("populate: " + Components[i])
this.children.push(Components[i]);
,
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="(child, index) in children">
<component :is="child" :key="child.name"></component>
</template>
</div>
【问题讨论】:
【参考方案1】:你有没有尝试过类似的事情
// MyRecursiveComponent.vue
<template>
<div>
<!-- node content -->
<div v-for="childNode" in jsonData.children">
<MyRecursiveComponent :jsonData="childNode" />
</div>
</div>
<template
【讨论】:
那么我应该在哪里调用渲染函数来实际编译将替换它的 html?【参考方案2】: const jsonData = [
"tagName": "section",
"classes": ["container","mx-auto"],
"attrs": ,
"textNode": "",
"children": [
"tagName": "div",
"classes": ["flex","flex-wrap"],
"attrs": ,
"textNode": "",
"children": [
"tagName": "div",
"classes": ["w-1/2"],
"attrs": ,
"textNode": "Hello"
,
"tagName": "div",
"classes": ["w-1/2"],
"attrs": ,
"textNode": "Goodbye"
]
]
];
let Components = [];
let uuid = 0;
function recurse()
recursiveInitialize(jsonData)
function recursiveInitialize(j)
if (Array.isArray(j))
return j.map((child) => recursiveInitialize(child))
if (j.children && j.children.length > 0)
initializeComponent(j)
console.log("Hi I am " + j["tagName"] + " and a parent")
j.children.forEach((c) =>
console.log("Hi I am " + c["tagName"] + " and my parent is " + j["tagName"])
recursiveInitialize(c)
);
else
console.log("Hi, I dont have any kids, I am " + j["tagName"])
initializeComponent(j)
function initializeComponent(jsonBlock)
let tempComponent =
name: jsonBlock["tagName"]+ uuid.toString(),
methods:
greet()
store.setMessageAction(this)
,
data: function()
return
tagName: jsonBlock["tagName"],
classes: jsonBlock["classes"],
attrs: jsonBlock["attrs"],
children: jsonBlock["children"],
textNode: jsonBlock["textNode"],
on: click: this.greet,
ref: uuid,
,
beforeCreate()
this.uuid = uuid.toString();
uuid += 1;
,
render: function(createElement)
return createElement(this.tagName,
class: this.classes,
on:
click: this.greet
,
attrs: this.attrs,
, this.textNode);
,
mounted()
// example usage
console.log('This ID:', this.uuid);
,
Components.push(tempComponent);
return tempComponent
const App = new Vue(
el: '#app',
data:
children: [
Components
],
,
beforeCreate()
recurse();
console.log("recurseRan")
,
mounted()
this.populate()
,
methods:
populate()
let i = 0;
let numberOfItems = Components.length;
for (i = 0; i < numberOfItems; i++)
console.log("populate: " + Components[i])
this.children.push(Components[i]);
,
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="(child, index) in children">
<component :is="child" :key="child.name"></component>
</template>
</div>
【讨论】:
嗨,Maks,我认为您发布的代码与我的相同。以上是关于Vue 中的渲染函数和递归组件的主要内容,如果未能解决你的问题,请参考以下文章