具有工厂功能的 Vue 组件 v-for
Vue component v-for with factory function
我正在创建一个 Table 组件并为所有逻辑使用工厂函数。在 v-for
中,我为每行的每个项目创建一个单元格。
工厂
这是我在需要的vue页面导入的实际工厂。我这里只添加了相关代码。
const TableData = (data) => {
const methods = {
'getRows': () => {
const result = []
for(let i = 0, end = data.length; i < end; i++) {
result.push(TableRow(methods, i))
}
return result
}
}
return methods
}
const TableRow = (parent, rowIndex) => {
const methods = {
'getCells': () => {
const result = []
for(let colIndex = 0, end = parent.getColumnCount(); colIndex < end; colIndex++) {
result.push(TableCell(parent, rowIndex, colIndex))
}
return result
}
}
return methods
}
const TableCell = (parent, rowIndex, columnIndex) => {
let active = false
const methods = {
'hover': () => {
active = !active
},
'isActive': () => {
return active
}
}
return methods
}
组件
所以在组件下面
<template>
<div class="table-container">
<table class="table" v-if="table">
<thead>
<tr>
<th class="index-col"></ths>
<th v-for="(col, index) in columns">{{col}}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows">
<td class="cell" v-for="cell in row.getCells()" @mouseenter="cell.hover" @mouseleave="cell.hover" :class="{active: cell.isActive()}">{{cell.getValue()}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
/* Table Data Factory */
import TableData from "~/plugins/library/table/data_new.js";
export default {
data() {
return {
table: null
};
},
methods: {
async fetch() {
/* Here I fetch data from API (fetchedData is an array) */
this.data = fetchedData
if(this.data) {
this.table = TableData(this.data)
} else {
console.error('Got no data')
}
}
},
computed: {
columns() {
return this.table.getColumns()
},
rows() {
return this.table.getRows()
}
},
mounted() {
this.fetch()
}
};
</script>
我想要发生的是,当我将一个单元格悬停在 table 中(将单元格活动状态设置为 true)时,class 也会切换。
:class="{active: cell.isActive()"
class 属性不会监视细胞工厂的变化。我明白了,但我不知道如何让它具有反应性。我已经尝试并搜索了一段时间以找到解决方案,但没有成功。
希望有人能进一步帮助我,在此先感谢!
在我看来问题出在这里=> cell.isActive()
因为您返回的是函数而不是反应变量,所以没有任何迹象表明那里发生了变化。现在您可以使用 forceUpdate()
强制更新,但是您将重新绘制所有单元格,这是非常低效的。如果可能,您应该尽量不要将函数用作渲染的一部分,尤其是在循环中,因为它们会在每次绘制时触发。
我的首选方法是不让单独的组件管理它们自己的状态,而是使用可以处理列、行、and/or 单元格数据的嵌套 object/array 状态。但我假设这不是您要找的。
如果您可以使用计算,那么您可以在不调用函数的情况下实现反应性。如果您使用的是 vue 2.6+,则可以通过 DIY 的方式添加它。从 Vue 2.6 开始,可以定义独立的可观察对象,您可以使用它来存储和改变状态,并生成计算字段。
您还应该将此应用于其他工厂,例如 row.getCells()
将重新生成所有数据,因为它没有状态。
未测试代码:
const TableCell = (parent, rowIndex, columnIndex) => {
const state = Vue.Observable({
active: false
});
const computed= {
isActive: () => state.active,
}
const methods = {
hover: () => {
active = !active;
},
};
// return all merged (need to watch for overlapping names)
return {...state, ...computed, ...methods};
};
有了这个,您应该能够使用 cell.isActive
并让它对变化做出反应。
附带说明一下,如果您希望以这种方式使用 Vue,您可能会受益于 Vue 3(最近发布的测试版)中的变化,即 API 组合,它借出组成成分。
我正在创建一个 Table 组件并为所有逻辑使用工厂函数。在 v-for
中,我为每行的每个项目创建一个单元格。
工厂
这是我在需要的vue页面导入的实际工厂。我这里只添加了相关代码。
const TableData = (data) => {
const methods = {
'getRows': () => {
const result = []
for(let i = 0, end = data.length; i < end; i++) {
result.push(TableRow(methods, i))
}
return result
}
}
return methods
}
const TableRow = (parent, rowIndex) => {
const methods = {
'getCells': () => {
const result = []
for(let colIndex = 0, end = parent.getColumnCount(); colIndex < end; colIndex++) {
result.push(TableCell(parent, rowIndex, colIndex))
}
return result
}
}
return methods
}
const TableCell = (parent, rowIndex, columnIndex) => {
let active = false
const methods = {
'hover': () => {
active = !active
},
'isActive': () => {
return active
}
}
return methods
}
组件
所以在组件下面
<template>
<div class="table-container">
<table class="table" v-if="table">
<thead>
<tr>
<th class="index-col"></ths>
<th v-for="(col, index) in columns">{{col}}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows">
<td class="cell" v-for="cell in row.getCells()" @mouseenter="cell.hover" @mouseleave="cell.hover" :class="{active: cell.isActive()}">{{cell.getValue()}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
/* Table Data Factory */
import TableData from "~/plugins/library/table/data_new.js";
export default {
data() {
return {
table: null
};
},
methods: {
async fetch() {
/* Here I fetch data from API (fetchedData is an array) */
this.data = fetchedData
if(this.data) {
this.table = TableData(this.data)
} else {
console.error('Got no data')
}
}
},
computed: {
columns() {
return this.table.getColumns()
},
rows() {
return this.table.getRows()
}
},
mounted() {
this.fetch()
}
};
</script>
我想要发生的是,当我将一个单元格悬停在 table 中(将单元格活动状态设置为 true)时,class 也会切换。
:class="{active: cell.isActive()"
class 属性不会监视细胞工厂的变化。我明白了,但我不知道如何让它具有反应性。我已经尝试并搜索了一段时间以找到解决方案,但没有成功。
希望有人能进一步帮助我,在此先感谢!
在我看来问题出在这里=> cell.isActive()
因为您返回的是函数而不是反应变量,所以没有任何迹象表明那里发生了变化。现在您可以使用 forceUpdate()
强制更新,但是您将重新绘制所有单元格,这是非常低效的。如果可能,您应该尽量不要将函数用作渲染的一部分,尤其是在循环中,因为它们会在每次绘制时触发。
我的首选方法是不让单独的组件管理它们自己的状态,而是使用可以处理列、行、and/or 单元格数据的嵌套 object/array 状态。但我假设这不是您要找的。
如果您可以使用计算,那么您可以在不调用函数的情况下实现反应性。如果您使用的是 vue 2.6+,则可以通过 DIY 的方式添加它。从 Vue 2.6 开始,可以定义独立的可观察对象,您可以使用它来存储和改变状态,并生成计算字段。
您还应该将此应用于其他工厂,例如 row.getCells()
将重新生成所有数据,因为它没有状态。
未测试代码:
const TableCell = (parent, rowIndex, columnIndex) => {
const state = Vue.Observable({
active: false
});
const computed= {
isActive: () => state.active,
}
const methods = {
hover: () => {
active = !active;
},
};
// return all merged (need to watch for overlapping names)
return {...state, ...computed, ...methods};
};
有了这个,您应该能够使用 cell.isActive
并让它对变化做出反应。
附带说明一下,如果您希望以这种方式使用 Vue,您可能会受益于 Vue 3(最近发布的测试版)中的变化,即 API 组合,它借出组成成分。