Vue компонент v-for с заводской функцией - PullRequest
3 голосов
/ 23 апреля 2020

Я создаю компонент 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()"

Класс проп не наблюдает за изменениями в фабрике ячеек. Что я понимаю, но я понятия не имею, как сделать это реактивным. Я пытался и искал некоторое время, чтобы найти решение, но безуспешно.

Надеюсь, кто-нибудь может мне помочь, заранее спасибо!

1 Ответ

1 голос
/ 24 апреля 2020

мне кажется, что проблема здесь в этом => cell.isActive()

Поскольку вы возвращаете функцию вместо реактивной переменной, там нет ничего, что указывало бы на изменение. Теперь вы можете принудительно обновить forceUpdate(), но тогда вы будете перерисовывать все ячейки, что ужасно неэффективно. Вы должны стараться не использовать функции как часть рендеринга, если это возможно, особенно внутри циклов, так как они запускаются при каждом отрисовке.

Мой предпочтительный способ состоял бы в том, чтобы отдельные компоненты не управляли своим собственным состоянием, а использовали вложенные состояние объекта / массива, которое может обрабатывать данные столбцов, строк и / или ячеек. Но я предполагаю, что это не то, что вы ищете.

Если бы вы могли использовать вычисленные значения, то вы можете реализовать реактивность без вызова функции. Вы можете добавить это с помощью DIY, если вы используете vue 2.6+. Начиная с 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, который предоставляет компонентный состав.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...