带有工厂功能的Vue组件v-for

Posted

技术标签:

【中文标题】带有工厂功能的Vue组件v-for【英文标题】:Vue component v-for with factory function 【发布时间】:2020-08-07 00:08:00 【问题描述】:

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

类 prop 不会监视单元工厂中的更改。我明白,但我不知道如何让它反应。我已经尝试并搜索了一段时间以找到解决方案,但没有成功。

希望有人可以进一步帮助我,在此先感谢!

【问题讨论】:

【参考方案1】:

在我看来问题在于这里 => cell.isActive()

因为您返回的是函数而不是反应变量,所以没有任何迹象表明那里发生了变化。现在您可以使用forceUpdate() 强制更新,但是您将重新绘制所有单元格,这是非常低效的。如果可能,您应该尽量不要将函数用作渲染的一部分,尤其是在循环中,因为它们会在每次绘制时触发。

我的首选方法是不让单个组件管理它们自己的状态,而是使用可以处理列、行和/或单元格数据的嵌套对象/数组状态。但我假设这不是您想要的。

如果您可以使用计算,那么您可以在不调用函数的情况下实现反应性。如果您使用的是 vue 2.6+,您可以通过 DIY 的方式添加它。从 Vue 2.6 开始,可以定义独立的 observables,您可以使用它来存储和改变状态,并生成计算字段。

您还应该将此应用于其他工厂,例如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 组合,它提供了组件组合。

【讨论】:

以上是关于带有工厂功能的Vue组件v-for的主要内容,如果未能解决你的问题,请参考以下文章

vue 异步组件 (按需加载)

如何从 Vue 实例外部触发 Stencil 组件功能/方法

如何将类从父组件应用到 Vue.js 功能组件?

Vue异步组件Demo

vue+webpack2实现路由的懒加载

vue2.x 路由懒加载 优化打包体积