我正在使用 Pinia 来管理整个应用程序中不同数据表的状态。多个表可以在彼此“顶部”打开(即彼此重叠)。这就是为什么我正在重新设计我们当前的设置,其中只能打开一个表,另一个表将覆盖前一个表,到一个可以同时打开多个表的新系统。
我想到使用 Pinia 和 Map() 来保持所有数据表配置就位,并使用“activeDataTableName”字段来跟踪哪个表当前是“活动”表。
我的 Pinia 商店是这样的:
export const useDataTableStore = defineStore('data-table', {
state: () => ({
dataTables: new Map(), // use a Map to store all data table configurations
activeDataTableName: null, // Used to track which is the current active data table
}),
getters: {
getActiveDataTableConfig: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig || null
},
getDataTableName: (state) => state.activeDataTableName,
getLoading: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.loading : true
},
getDataTableColumns: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.dataTableColumns : []
},
getTotalRecords: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.totalRecords : 0
},
getFirst: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.first : 0
},
getAmountRowsToShow: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.amountRowsToShow : 15
},
getSelectedRows: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.selectedRows : []
},
getFocussedRow: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.focussedRow : null
},
getLazyParams: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.lazyParams: {}
}
getSelectAll: (state) => {
const dtConfig = state.dataTables.get(state.activeDataTableName)
return dtConfig ? dtConfig.selectAll : false
},
},
actions: {
async initialize (nuxtApp, dtName) {
// The initialize function sets the dataTableName and loads the columns
const newDataTableConfigObject = {
loading: true,
dataTableName: dtName,
dataTableColumns: [],
totalRecords: 0,
first: 0,
amountRowsToShow: 15,
selectedRows: [],
focussedRow: null,
lazyParams: {},
selectAll: false,
}
this.dataTables.set(dtName, newDataTableConfigObject)
this.activeDataTableName = dtName
},
setSelectedRows (rows) {
const dtConfig = this.dataTables.get(this.activeDataTableName)
if (dtConfig) {
dtConfig.selectedRows = rows
}
},
},
})
当我尝试使用 v-model 进行 2 路绑定时,出现了问题。 例如:我将有一个组件“DataTable”,它从 v 模型中的商店中获取值,如下所示:
<DataTable
ref="dataTableRef"
v-model:selection="store.selectedRows"
v-model:first="store.first"
v-model:rows="store.amountRowsToShow"
...
/>
当我的商店初始化时:
const store = useDataTableStore()
“selectedRows”、“first”等的值不会直接位于存储中,而是位于存储中数据表内的活动配置对象中。 当我尝试为商店的变量设置值时,我也遇到了困难:
store.amountRowsToShow = rows
store.lazyParams.first = store.getFirst
store.lazyParams.rows = store.getAmountRowsToShow
这可能可以通过每个特定的 setter 来解决,但是如果我必须为懒惰参数中的每个潜在对象创建一个 setter 方法,它就会变得非常乏味。难道没有更好的方法吗?
有
activeDataTableName
也没关系,尽管这个状态可能属于“活跃”的组件而不是store
像
getActiveDataTableConfig
这样的吸气剂存在一个根本问题。如果要同时呈现多个表,则无法使用 getter 来显示非活动表中的数据。如果存储中所有表都被平等对待,那么可能会导致更少的问题。参数化计算可用于此:
getters: {
getSelectedRows: (state) => {
return (name) => state.dataTables.get(name) || null;
},
...
参数化计算不会被缓存,这对于性能密集型使用(表可能是这样)至关重要。可以使用为特定表创建计算的助手来代替参数化计算,或者除了参数化计算之外:
function mapStoreTable(name) {
const store = useTableStore();
const tableData = store.dataTables.get(name);
const selectedRows = computed(() => store.getSelectedRows(name));
...
return { selectedRows, ... };
}
这将使
selectedRows
等不会对其他表中的更改做出反应。
更新操作可以接受表名来更新特定的表:
actions: {
setSelectedRows(name, rows) {
const dtConfig = this.dataTables.get(name);
if (dtConfig) {
dtConfig.selectedRows = rows
}
},
...
直接使用
v-model
改变商店通常是值得怀疑的做法。尽管 Pinia 中允许这样做,但之前在 Vuex 中不鼓励这样做,因为这会导致代码难以调试和维护。无论如何,使用建议的助手这是不可能的。 v-model
可以脱糖为道具和事件。或者可以创建一个可写的计算,它在集合上调度一个动作并可以用作 v-model:selection="selectedRowsModel"
:
const { selectedRows } = mapStoreTable(tableName);
const selectedRowsModel = computed({
get() {
return selectedRows.value;
},
set(rows) {
store.setSelectedRows(name, rows)
}
});