我在Vuex和同级组件状态更新方面遇到问题。我知道有必要使用:key
绑定。
我的状态是:
filters: {
clientId: 0,
projectId: 0,
projectRoleId: 0,
subProjectId: 0,
},
我有4个组成该页面的组件:
月:此组件具有子组件,但具有过滤器的v-处于此级别
DailyDetail (每日详细信息):该组件显示了一天的时间条目,其中包含更多详细信息
议程:这是日历中显示的同一天的垂直视图(月控制)
过滤器:在这里我们可以过滤4个字段(客户,项目,子项目或项目角色)中的1个
当我单击并添加过滤器时,所有3个组件(“月”,“每日详细信息”和“议程”)都仅显示过滤的结果。这就是我要的。
但是,当我单击“过滤器”控件上的“清除过滤器” 按钮时,似乎只有“月份”组件会注意到它。其他只是保持不变。从filtered
getter更改时正确应用和删除hasFilters
类的事实出发。
如果有帮助,请参见以下动作/突变和获取器:
过滤器的设置直接从计算的设置器中获取突变:
// Computed properties on the Filter component:
filteredClientId: {
get() { return this.$store.state.time.filters.clientId; },
set(value) { this.$store.commit('time/SET_FILTERED_CLIENT', value); },
},
filteredProjectId: {
get() { return this.$store.state.time.filters.projectId; },
set(value) { this.$store.commit('time/SET_FILTERED_PROJECT', value); },
},
filteredProjectRoleId: {
get() { return this.$store.state.time.filters.projectRoleId; },
set(value) { this.$store.commit('time/SET_FILTERED_PROJECT_ROLE', value); },
},
filteredSubProjectId: {
get() { return this.$store.state.time.filters.subProjectId; },
set(value) { this.$store.commit('time/SET_FILTERED_SUB_PROJECT', value); },
},
// Here are the corresponding mutations
SET_FILTERED_CLIENT(state, value) {
state.filters.clientId = value;
},
SET_FILTERED_PROJECT(state, value) {
state.filters.projectId = value;
},
SET_FILTERED_PROJECT_ROLE(state, value) {
state.filters.projectRoleId = value;
},
SET_FILTERED_SUB_PROJECT(state, value) {
state.filters.subProjectId = value;
},
这里是“月份”组件(该组件始终可以设置和清除过滤器):
<template>
<div class="month"
:class="{ 'filtered': hasFilters }"
>
<weekDays />
<week v-for="(week, index) in weeks"
:key="index"
:week="week"
/>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import week from './week.vue';
import weekDays from './weekDays.vue';
export default {
components: {
week,
weekDays,
},
computed: {
...mapGetters('time', ['hasFilters', 'weeks']),
},
};
</script>
以下是这些组件的吸气剂:
daysWithinPayPeriod: (state, getters) => {
if (!state.currentDay) // This is simply to gracefully exit when no data is loaded yet
return [];
let payPeriodSerial = state.currentDay.PayPeriodSerial;
// Find all of the entries within the pay period
let validDays = state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial);
if (getters.hasFilters) {
for (let day of validDays) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return validDays;
},
hasFilters: state => {
return state.filters.clientId !== 0 ||
state.filters.projectId !== 0 ||
state.filters.projectRoleId !== 0 ||
state.filters.subProjectId !== 0;
},
weeks: (state, getters) => {
if (getters.hasFilters) {
let result = JSON.parse(JSON.stringify(state.monthlyData.Weeks));
for (let week of result) {
for (let day of week.Days) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return result;
} else {
return state.monthlyData.Weeks
? state.monthlyData.Weeks
: [];
}
},
这里是将议程组件进行了一些微调,以仅显示有用的信息:
<template>
<div class="agenda">
<table class="table table-hover mb-0 table-bordered"
:class="{ 'filtered': hasFilters }"
>
...
<tbody>
<tr v-for="day in daysWithinPayPeriod"
:key="day.DayOfYear"
:class="{ 'is-today': day.IsToday, 'weekend': day.IsWeekend, 'focused': isDaySelected(day) }"
class="day-row"
@click="selectDay(day)"
>
...
<td colspan="4"
class="breakout"
>
<table v-if="day.ProjectTimes.length > 0"
class="table table-sm table-striped table-hover table-borderless mb-0"
>
<tbody>
<tr v-for="entry in day.ProjectTimes"
:key="entry.ID"
>
...
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
import store from '../../store';
export default {
store: store,
mixins: [ formattingFilters ],
computed: {
...mapGetters('time', ['daysWithinPayPeriod', 'hasFilters']),
...mapState('time', {
}),
},
methods: {
selectDay(day) {
this.$store.dispatch('time/dateSelected', day);
},
},
};
</script>
使用“议程”组件,我会假设它是嵌套的v-for
,但是DailyDetail组件(后面)没有嵌套的v-for
并且不会“清除”过滤器。
这是DailyDetail组件:
<template>
<div class="daily-detail">
<table class="table table-sm table-striped table-hover mb-0"
:class="{ 'filtered': hasFilters }"
>
...
<tbody>
<tr v-for="entry of currentDaysTimeEntries"
:key="entry.ID"
:class="{ 'italic': entry.Project.IsUniversal }"
>
<td class="text-center"><i class="far fa-pencil" /></td>
<td><div class="text-right">{{ entry.Time | formatNumber }}</div></td>
<td>
<div class="truncate">{{ entry.Project.Name }}</div>
<div v-if="entry.SubProject.ID > 0"
class="subproject"
>
{{ entry.SubProject.Name}}
</div>
<small>{{ entry.Project.Client.Name }}</small>
</td>
...
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import store from '../store';
import formattingFilters from '../mixins/formatting';
export default {
store: store,
computed: {
...mapGetters('time', ['currentDaysTotalTime', 'currentDaysTimeEntries', 'hasFilters', 'selectedDate']),
},
};
</script>
清除过滤器需要执行以下操作:
// Action
clearFilters(context) {
context.commit('CLEAR_FILTERS');
},
// Mutation
CLEAR_FILTERS(state) {
state.filters.clientId = 0;
state.filters.projectId = 0;
state.filters.projectRoleId = 0;
state.filters.subProjectId = 0;
},
重申一下,问题在于所有3个组件都使用hasFilters
吸气剂在其组件上应用名为filtered
的类,以表示存在过滤器。此部分适用于设置和清除过滤器。问题在于,清除过滤器后,进入过滤器(该部分有效)时过滤掉的值不会被清除。 Month组件运行良好,但是Agenda和DailyDetails只是保持过滤状态。
答案 0 :(得分:0)
好吧,经过一夜的睡眠,我想我会再戳一遍。这是我的错(正如预期的那样)。我注意到两件事,一是DailyDetail
组件正确显示了filtered
类(如上所述),但是 not 过滤数据。这样的解决方法就在这里:
未过滤的DailyDetail
的原始吸气剂
currentDaysTimeEntries: state => {
return state.currentDay
? state.currentDay.ProjectTimes
: [];
},
修复了DailyDetail
会过滤的吸气剂
currentDaysTimeEntries: (state, getters) => {
if (state.currentDay) {
if (getters.hasFilters) {
return state.currentDay.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
} else {
return state.currentDay.ProjectTimes;
}
} else {
return [];
}
},
然后,一旦修复该问题并且3个组件中的2个都运行良好,我就意识到Agenda
组件(一个不起作用的组件)并不是使用JavaScript {{1 }}方法,它还需要做更多的工作并提取出不需要的内容。
答案这是filter
将不需要的内容从数组中覆盖,从而覆盖了原始数组,因此,当关闭过滤功能时,没有任何内容可返回。因此,我制作了阵列的副本,现在所有3个组件都可以工作!
用于议程的原始获取程序,它已进行过滤并完全删除
filter
更新的议程吸气剂(只是更改),可以在过滤器之前复制数组
daysWithinPayPeriod: (state, getters) => {
if (!state.currentDay)
return [];
let payPeriodSerial = state.currentDay.PayPeriodSerial;
// Find all of the entries within the pay period
let validDays = state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial);
if (getters.hasFilters) {
for (let day of validDays) {
day.ProjectTimes = day.ProjectTimes.filter(x => {
return (
x.Project.Client.ID === (state.filters.clientId === 0 ? x.Project.Client.ID : state.filters.clientId) &&
x.Project.ID === (state.filters.projectId === 0 ? x.Project.ID : state.filters.projectId) &&
x.ProjectRole.ID === (state.filters.projectRoleId === 0 ? x.ProjectRole.ID : state.filters.projectRoleId) &&
x.SubProject.ID === (state.filters.subProjectId === 0 ? x.SubProject.ID : state.filters.subProjectId)
);
});
}
}
return validDays;
},
这是问题所在的特定行,需要该数组的副本:
// Find all of the entries within the pay period and make a copy
let validDays = JSON.parse(JSON.stringify(
state.monthlyData.AllDays
.filter(x => x.PayPeriodSerial === payPeriodSerial)
));