一种使用 v-for 指令在 VueJS 上渲染多个根元素的方法

Hel*_*rld 5 components vuejs2

现在,我正在尝试创建一个网站,该网站显示由我的 NodeJS API 提供的最近的新闻帖子。

我尝试了以下方法:

HTML

<div id="news" class="media" v-for="item in posts">
    <div>
        <h4 class="media-heading">{{item.title}}</h4>
        <p>{{item.msg}}</p>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

Javascript

const news = new Vue({
    el: '#news',
    data:   {
        posts:  [
            {title: 'My First News post',   msg: 'This is your fist news!'},
            {title: 'Cakes are great food', msg: 'Yummy Yummy Yummy'},
            {title: 'How to learnVueJS',    msg: 'Start Learning!'},
        ]
    }
})
Run Code Online (Sandbox Code Playgroud)

显然,上面的方法不起作用,因为 Vue 无法渲染多个根元素。

我查了 VueJS 的官方手册,并没有想出一个解决方案。谷歌搜索一段时间后,我明白不可能渲染多个根元素,但是,我还没有想出一个解决方案。

Cos*_*che 16

我发现添加多个根元素的最简单方法是添加一个<div>包装元素,并使用一些 CSS 魔法使其消失以进行渲染。

为此,我们可以使用“display:contents”CSS 属性。效果是它使容器消失,使元素的子元素成为 DOM 中的下一级元素。

因此,在你的 Vue 组件模板中,你可以有这样的东西:

<template>
    <div style="display: contents"> <!-- my wrapper div is rendered invisible -->
        <tr>...</tr>
        <tr>...</tr>
        <tr>...</tr>
    </div>
</template>
Run Code Online (Sandbox Code Playgroud)

我现在可以使用我的组件,而浏览器不会弄乱格式,因为浏览器<div>将忽略包装根元素以进行显示:

<table>
   <my-component></my-component> <!-- the wrapping div will be ignored -->
</table>
Run Code Online (Sandbox Code Playgroud)

但是请注意,虽然这应该适用于大多数浏览器,但您可能需要在此处检查以确保它可以处理您的目标浏览器。


Alv*_*van 8

定义自定义指令

Vue.directive('fragments', {
  inserted: function(el) {
    const children = Array.from(el.children)
    const parent = el.parentElement
    children.forEach((item) => { parent.appendChild(item) })
    parent.removeChild(el)
  }
});
Run Code Online (Sandbox Code Playgroud)

然后你可以在组件的根元素中使用它

<div v-fragments>
  <tr v-for="post in posts">...</tr>
</div>
Run Code Online (Sandbox Code Playgroud)

DOM 中不会渲染根元素,这在渲染 table 时特别​​有效。


rol*_*oli 7

您可以使用渲染函数拥有多个根元素(或组件)

一个简单的例子是有一个渲染多个<li>元素的组件:

<template>
 <li>Item</li>
 <li>Item2</li>
 ... etc
</template>
Run Code Online (Sandbox Code Playgroud)

但是上面会抛出一个错误。要解决此错误,可以将上述模板转换为:

export default {
 functional: true,
 render(createElement) {
  return [
    createElement('li', 'Item'),
    createElement('li', 'Item2'),
  ]
 }
}
Run Code Online (Sandbox Code Playgroud)

但是,正如您可能已经注意到的那样,例如,如果您想显示 50 里的项目,这会变得非常乏味。因此,最终,要动态显示元素,您可以执行以下操作:

export default {
 functional: true,
 props: ['listItems'], //this is an array of `<li>` names (e.g. ['Item', 'Item2'])

 render(createElement, { props }) {
   return props.listItems.map(name => {
     return createElement('li', name)
   })
 }
}
Run Code Online (Sandbox Code Playgroud)

INFO在这些示例中,我使用了属性功能:true但当然不需要使用“渲染功能”。请考虑在此处了解有关功能组件的更多信息


Ron*_*n C 5

Vue 要求只有一个根节点。但是,尝试将您的 html 更改为:

<div id="news" >
    <div class="media" v-for="item in posts">
       <h4 class="media-heading">{{item.title}}</h4>
       <p>{{item.msg}}</p>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

此更改允许使用单个根节点 id="news",但仍允许呈现最近帖子的列表。