【问题标题】:Accordion table with vue.js and "v-for" in root element根元素中带有 vue.js 和“v-for”的手风琴表
【发布时间】:2018-09-02 16:55:43
【问题描述】:

我正在尝试通过 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 链接它们。

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

【问题讨论】:

  • 注意:您要关闭 .program 的标签不是结束标签。

标签: javascript vue.js


【解决方案1】:

一个表中可以有多个tbody 标签。将risk-component 包裹在tbody 中,您可以在其中包含多个trs。您需要进行一些重组,以便 tbodys 不会嵌套。

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;
.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;
}
<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>

【讨论】:

  • 不幸的是,这会改变表的结构。
  • 您需要对其进行返工,以免将风险置于tbody 内部您的程序tbodyjsfiddle.net/8bhpqc5s/55
【解决方案2】:

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

在您的情况下,您必须将&lt;tbody/&gt; 委托给一个功能组件,这将构造一个&lt;tr/&gt; 组件列表。 或者将&lt;table/&gt; 委托给一个功能组件,它将构造一个&lt;tbody/&gt; 组件的列表。 或两者兼而有之。

在此处复制/粘贴:

如果出于任何原因,您不想添加包装器(在我的第一种情况下,它是为&lt;tr/&gt; 组件),您可以使用功能组件。

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) } )
    ]; 
  }
};

如果您在两个模板中都使用了一些函数或数据,请将它们作为属性传递,就是这样!

我让您想象使用这种模式构建组件列表和许多功能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 2011-09-27
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多