我最近才开始深入研究 Vue JS - 到目前为止很喜欢它。我现在面临一个问题,我正在尝试创建一个(非平凡的)表(使用 vue-good-table 插件),其中每个单元格都是它自己的组件。
阅读了插件的文档后,有人提到可以创建一个 HTML 列类型,您可以在其中使用原始 HTML(我猜): https ://xaksis.github.io/vue-good-表/指南/配置/column-options.html#html
为简化起见,这就是我所拥有的——一个 Vue 组件(称为 Dashboard2.vue),它包含表和名为 Test.vue 的子组件
我正在为每个相关单元格动态创建测试组件并将其分配给相关的行单元格。由于我已将列定义为 HTML 类型,因此我使用 innerHTML 属性从 Vue 组件中提取原始 HTML。(按照这篇文章https://css-tricks.com/creating-vue-js-component-instances-programmatically/)一切都进行得很好,仪表板看起来正是我想要的样子,但是当点击里面的按钮时每个测试组件,没有任何反应。
我怀疑由于我使用了 innerHTML 属性,它只是以某种方式跳过了 Vue 甚至处理程序机制,所以我有点卡住了。
以下是相关组件部分:
仪表板2.vue:
<template>
<div>
<vue-good-table
:columns="columns"
:rows="rows"
:search-options="{enabled: true}"
styleClass="vgt-table condensed bordered"
max-height="700px"
:fixed-header="true"
theme="black-rhino">
</vue-good-table>
</div>
</template>
<script>
import axios from 'axios';
import Vue from 'vue';
import { serverURL } from './Config.vue';
import Test from './Test.vue';
export default {
name: 'Dashboard2',
data() {
return {
jobName: 'team_regression_suite_for_mgmt',
lastXBuilds: 7,
builds: [],
columns: [
{
label: 'Test Name',
field: 'testName',
},
],
rows: [],
};
},
methods: {
fetchResults() {
const path = `${serverURL}/builds?name=${this.jobName}&last_x_builds=${this.lastXBuilds}`;
axios.get(path)
.then((res) => {
this.builds = res.data;
this.builds.forEach(this.createColumnByBuildName);
this.createTestsColumn();
this.fillTable();
})
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
},
createBaseRow(build) {
return {
id: build.id,
name: build.name,
cluster: build.resource_name,
startTime: build.timestamp,
runtime: build.duration_min,
estimatedRuntime: build.estimated_duration_min,
result: build.result,
};
},
addChildRows(build, children) {
const row = this.createBaseRow(build);
// eslint-disable-next-line no-plusplus
for (let i = 0; i < build.sub_builds.length; i++) {
const currentBuild = build.sub_builds[i];
if (currentBuild.name === '') {
this.addChildRows(currentBuild, children);
} else {
children.push(this.addChildRows(currentBuild, children));
}
}
return row;
},
createColumnByBuildName(build) {
this.columns.push({ label: build.name, field: build.id, html: true });
},
addRow(build) {
const row = this.createBaseRow(build);
row.children = [];
this.addChildRows(build, row.children);
this.rows.push(row);
},
createTestsColumn() {
const build = this.builds[0];
const row = this.createBaseRow(build);
row.children = [];
this.addChildRows(build, row.children);
// eslint-disable-next-line no-plusplus
for (let i = 0; i < row.children.length; i++) {
this.rows.push({ testName: row.children[i].name });
}
},
fillBuildColumn(build) {
const row = this.createBaseRow(build);
row.children = [];
this.addChildRows(build, row.children);
// eslint-disable-next-line no-plusplus
for (let i = 0; i < row.children.length; i++) {
const childBuild = row.children[i];
const TestSlot = Vue.extend(Test);
const instance = new TestSlot({
propsData: {
testName: childBuild.name,
result: childBuild.result,
runTime: childBuild.runtime.toString(),
startTime: childBuild.startTime,
estimatedRunTime: childBuild.estimatedRuntime.toString(),
},
});
instance.$mount();
this.rows[i] = Object.assign(this.rows[i], { [build.id]: instance.$el.innerHTML });
}
},
fillTable() {
this.builds.forEach(this.fillBuildColumn);
},
},
created() {
this.fetchResults();
},
};
</script>
<style scoped>
</style>
测试.vue
<template>
<div>
<b-card :header="result" class="mb-2" :bg-variant="variant"
text-variant="white">
<b-card-text>Started: {{ startTime }}<br>
Runtime: {{ runTime }} min<br>
Estimated: {{ estimatedRunTime }} min
</b-card-text>
<b-button @click="sayHi" variant="primary">Hi</b-button>
</b-card>
</div>
</template>
<script>
export default {
name: 'Test',
props: {
id: String,
testName: String,
build: String,
cluster: String,
startTime: String,
runTime: String,
estimatedRunTime: String,
result: String,
},
computed: {
variant() {
if (this.result === 'SUCCESS') { return 'success'; }
if (this.result === 'FAILURE') { return 'danger'; }
if (this.result === 'ABORTED') { return 'warning'; }
if (this.result === 'RUNNING') { return 'info'; }
return 'info';
},
},
methods: {
sayHi() {
alert('hi');
},
},
};
</script>
<style scoped>
</style>
我知道这是很多代码。具体的相关部分(在 Dashboard2.vue 中)是fillBuildColumn
再说一次 - 我是 Vue JS 的新手 - 据说我的直觉告诉我我在这里做错了很多事情。
任何帮助将不胜感激。
编辑:
通过丢失 innerHTML 属性和 html 类型,我最终得到:
浏览器抛出“RangeError:超出最大调用堆栈大小”。不知道是什么原因造成的