Vue组件v-for带工厂功能

问题描述 投票:2回答:1

我正在创建一个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>

我想发生的是,当我在表中悬停一个单元格时(将单元格的活动状态设置为true),类也会切换。

:class="{active: cell.isActive()"

该类道具并不监视单元格工厂的变化。我明白这一点,但我不知道如何让它变成反应式的。我试过了,找了好久才找到解决办法,但没有成功。

希望有人能进一步帮助我,先谢谢了!

javascript vue.js factory v-for
1个回答
1
投票

在我看来,问题就出在这里=&gt。cell.isActive()

因为你返回的是一个函数,而不是一个反应式变量,所以没有任何东西来指示那里的变化。现在你可以用 forceUpdate()但这样一来,你会重新绘制所有的单元格,效率非常低。如果可能的话,你应该尽量不使用函数作为渲染的一部分,尤其是在循环中,因为它们在每次绘制时都会被触发。

我喜欢的方式是不要让单个组件管理自己的状态,而是使用一个嵌套的objectarray状态来处理列、行和单元格的数据。但我假设这不是你要找的。

如果你能使用一个computed,那么你可以在不调用函数的情况下实现反应性。如果你使用的是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组成,它借组件组成。

© www.soinside.com 2019 - 2024. All rights reserved.