Tengo una página de componentes Vue.js que obtiene algunos datos de mi backend:
<script setup> const props = defineProps({ records: { type: Object, }, }); </script>Tengo tres filtros/estados diferentes que quiero que mis usuarios puedan seleccionar:
A continuación se muestra cómo obtengo los registros para los diferentes filtros. Estoy usando collect.js para facilitar el trabajo con el objeto:
let getRecords = () => { return collect(props.records) } const getUnlabeledRecords = () => { return getRecords() .where('skipped', false) .where('processed', false); } const getCompletedRecords = () => { return getRecords() .where('processed', true); } const getSkippedRecords = () => { return getRecords() .where('processed', false) .where('skipped', true); } //Load all records on page load. const allRecords = ref(getUnlabeledRecords()); //Show current record to the user. const current = ref(allRecords.value.first());Mis usuarios pueden hacer clic en el filtro que deseen:
<a :class="{'bg-gray-100' : currentFilter === 'Unlabeled' }" @click="allRecords = getUnlabeledRecords(), currentFilter = 'Unlabeled'"> Unlabeled ({{ getUnlabeledRecords().count() }}) </a> <a :class="{'bg-gray-100' : currentFilter === 'Skipped' }" @click="allRecords = getSkippedRecords(), currentFilter = 'Skipped'"> Skipped ({{ getSkippedRecords().count() }}) </a> <a :class="{'bg-gray-100' : currentFilter === 'Completed' }" @click="allRecords = getCompletedRecords(), currentFilter = 'Completed'"> Completed ({{ getCompletedRecords().count() }}) </a>El código anterior funciona, pero se siente muy "torpe" y no muy escalable. Digamos, quiero introducir un filtrado más avanzado, o simplemente otras "opciones de filtro", tengo que duplicar una gran cantidad de código.
¿Alguien tiene sugerencias sobre cómo puedo hacer esto de una mejor manera?
Es una pregunta un poco amplia porque no sabemos el formato de sus datos o qué posibles filtros futuros puede desear. Esto hace que sea difícil darle una buena respuesta real. Sin embargo, una victoria fácil parecería ser introducir una clase/objeto de filtro que contenga los detalles de lo que desea filtrar, como por ejemplo:
const filters = [ { text: 'Unlabeled', statesToFilterOn: [ { key: 'skipped', value: false }, { key: 'processed', value: false }, ] }, { text: 'Skipped', statesToFilterOn: [ { key: 'skipped', value: true }, { key: 'processed', value: false }, ] } ]Ahora puede obtener datos filtrados con un método getFilteredData:
const currentFilteredData = ref(getRecords()); const currentFilter = ref(); function applyFilter(filter) { currentFilter.value = filter; currentFilteredData.value = getFilteredData(filter); } function getFilteredData(filter) { let filtered = getRecords(); filter.statesToFilterOn.forEach(state => { filtered = filtered.where(state.key, state.value); }); return filtered; }Y su interfaz de usuario puede verse así:
<a v-for="filter in filters" :key="filter.text" @click="applyFilter(filter)" > {{ filter.text }} ({{ getFilteredData(filter).count }}) </a> Y ahora, si desea agregar más filtros, simplemente agregue uno a la matriz de filters . Puede hacer esto tantas veces como quiera y no tiene que cambiar nada más que la matriz de filtros. Creo que esta es una respuesta tan buena como puedo dar con la información proporcionada.