带有vue.js和" v-for"的手风琴表在根元素中

时间:2018-03-23 23:03:03

标签: javascript vue.js

我试图用VUE实现这个目标: https://jsfiddle.net/jacekpr/roschwvL/5/

目前,我有这个: https://jsfiddle.net/jacekpr/8bhpqc5s/13/

但是当我想在risk-Component中渲染control-Component时,我仍然遇到组件中多个根元素的问题。

理想情况下,我会在风险成分的最后得到以下内容:

<control-Component v-for="control in risk.controls" :control="control" :key="risk.title + control.title" />

但是我收到了这个错误:

  

组件模板应该只包含一个根元素。如果您在多个元素上使用v-if,请使用v-else-if来链接它们。

知道如何解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

您可以在表格中添加多个tbody代码。在risk-component中换行tbody,您可以在其中包含多个tr。您需要进行一些重组,以便tbody不要嵌套。

&#13;
&#13;
var risks = '[{"title":"Risk1", "controls":[{"title":"Control1"}, {"title":"Control2"}, {"title":"Control3"}]},' +
  '{"title":"Risk2", "controls":[{"title":"Control1"}, {"title":"Control2"}, {"title":"Control3"}]},' +
  '{"title":"Risk3", "controls":[{"title":"Control1"}, {"title":"Control2"}, {"title":"Control3"}]}]';

var programs = '[{"title":"Program1", "practice":"IT", "auditType":"GAT", "version":"0.01", "programId":"2017.1", "status":"draft", "risks":' + risks + '},' +
  '{"title":"Program2", "practice":"IT", "auditType":"On-request", "version":"0.01", "programId":"2017.2", "status":"draft", "risks":""},' +
  '{"title":"Program3", "practice":"CA", "auditType":"GAT", "version":"0.01", "programId":"2017.3", "status":"approved", "risks":' + risks + '},' +
  '{"title":"Program4", "practice":"CA", "auditType":"On-request", "version":"0.01", "programId":"2018.1", "status":"draft", "risks":' + risks + '},' +
  '{"title":"Program5", "practice":"OA\FA", "auditType":"GAT", "version":"0.01", "programId":"2019.1", "status":"draft", "risks":' + risks + '},' +
  '{"title":"Program6", "practice":"OA\FA", "auditType":"On-request", "version":"0.01", "programId":"2020.1", "status":"approved", "risks":' + risks + '}]';


var dataO = JSON.parse(programs);

Vue.component('control-component', {
  props: ['control'],
  template: '<tr class="control" >' +
    '<td></td>' +
    '<td colspan="6"><a href="#">{{ control.title }}</a></td>' +
    '</tr>'
})

Vue.component('risk-component', {
  props: ['risk'],
  template: '<tbody><tr class="risk" >' +
    '<td></td>' +
    '<td colspan="5"><a href="#">{{risk.title}}</a></td>' +
    '<td><span class="signrisk"></span></td>' +
    '</tr>' +
    '<control-component v-for="control in risk.controls" :control="control" :key="control.title"></control-component>' +
    '</tbody>'
});


var programTable = new Vue({
  el: '#programTable',
  data: {
    programs: ''
  }
})
programTable.programs = dataO;
&#13;
.signprogram:after {
  content: "+";
  display: inline-block;
  cursor: pointer;
}

.expandprogram:after {
  content: "-";
  cursor: pointer;
}

.signrisk:after {
  content: "+";
  display: inline-block;
  cursor: pointer;
}

.expandrisk:after {
  content: "-";
  cursor: pointer;
}

th {
  background-color: #e0e0e0;
}

.program {
  background-color: #e9e9e9;
}

.risk {
  background-color: #eeeeee;
}

.control {
  background-color: #f2f2f2;
}

.spacing {
  background-color: white;
}
&#13;
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<table class="table" width="300px" id="programTable">
  <thead>
    <tr>
      <th>Status</th>
      <th>Title</th>
      <th>Practice</th>
      <th>Audit Type</th>
      <th>Version</th>
      <th>Program</th>
      <th>&nbsp;</th>
    </tr>
  </thead>
  <template v-for="program in programs">
    <tbody>
      <tr class="program" >
        <td v-if="program.status == 'draft'" style="width: 20px; background-color: lightblue;">&nbsp;&nbsp;&nbsp;</td>
        <td v-if="program.status == 'approved'" style="width: 20px; background-color: lightgreen;">&nbsp;&nbsp;&nbsp;</td>
        <td><a href="/auditprograms/1">{{program.title}}</a></td>
        <td>{{program.practice}}</td>
        <td>{{program.auditType}}</td>
        <td>{{program.version}}</td>
        <td>{{program.programId}}</td>		
        <td><span class="signprogram"></span></td>
      </tr>
    </tbody>
    <risk-component v-for="risk in program.risks" :risk="risk" :key="program.title + risk.title"></risk-component>
  </template>
</table>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

对于类似的问题,我打算给出另一个答案:Vue js error: Component template should contain exactly one root element

在您的情况下,您必须将<tbody/>委派给功能组件,这样才能构造<tr/>组件的列表。 或者将<table/>委托给功能组件tha将构造<tbody/>组件的列表。 或两者兼有。

在此处复制/粘贴:

如果出于任何原因,您不想添加包装器(在我的第一种情况下,该包装器用于<tr/>组件),则可以使用功能组件。

components/MyCompo.vue文件夹中只有几个文件,而不是一个components/MyCompo

  • components/MyCompo/index.js
  • components/MyCompo/File.vue
  • components/MyCompo/Avatar.vue

采用这种结构,您调用组件的方式不会改变。

components/MyCompo/index.js文件内容:

import File from './File';
import Avatar from './Avatar';   

const commonSort=(a,b)=>b-a;

export default {
  functional: true,
  name: 'MyCompo',
  props: [ 'someProp', 'plopProp' ],
  render(createElement, context) {
    return [
        createElement( File, { props: Object.assign({light: true, sort: commonSort},context.props) } ),
        createElement( Avatar, { props: Object.assign({light: false, sort: commonSort},context.props) } )
    ]; 
  }
};

如果两个模板中都使用了某些功能或数据,则将它们作为属性传递就可以了!

我让您想象使用此模式构建组件列表以及如此多的功能。