好的,因此,我有三个列表需要共同做出反应:网站,个人资料和员工。基本上,如果我选择一个站点,则只需要显示该站点的个人资料和员工,然后,如果我选择一个概要文件,则只需要显示具有该概要文件的网站和员工……依此类推。
鉴于列表已经是Vue组件,所以我继续并实现了Vuex商店来管理各种列表的内容。这是我的商店的代码:
const manageSchedulesModale = {
state: {
sites:[{
id: -1,
text: app.utils.translate("No Site"),
icon: "site",
selected: false
}].concat(app.metadata.sites.map(a=>({id:a.id,text:a.name}))),
profiles: [{
id: -1,
text: app.utils.translate( "No Profile" ),
icon: "profile",
selected: false
}].concat (app.metadata.profiles.map(a=>(
{
id: a.id,
text: a.name,
//FIXME add color tags to k-icon
html: "<span class='color-tag-group'><span data-color="+a.color+" class='color-tag'></span></span> "+a.name,
site_id: a.site_id
}
)
)),
employees: [{
id: -1,
text: app.utils.translate( "No Employee" ),
icon: "user"
}].concat(
app.metadata.employees.map(a=>{
var colors = a.profiles.map(a=>"<span data-color="+a.color+" class='color-tag'></span>").join("")
return {
id: a.id,
text: a.firstname + " " + a.lastname,
html: "<span class='color-tag-group'>"+colors+"</span> "+a.firstname+" "+a.lastname
}
})),
currentSite: -1,
currentProfile: -1,
currentEmployee: -1
},
actions:{
fetchProfiles(context, newSite){
app.ajax.defaultRequest("post", "/api/profiles",{site_id: context.state.currentSite, employee_id: context.state.currentEmployee},
function(response){
let content =
[{
id: -1,
text: app.utils.translate( "No Profile" ),
icon: "profile",
selected: false
}].concat(
response.data.map(
a =>
(
{
id: a.id,
text: a.name,
//FIXME add color tags to k-icon
html: "<span class='color-tag-group'><span data-color="+a.color+" class='color-tag'></span></span> "+a.name,
site_id: a.site_id
}
)
)
);
context.commit("reloadProfiles", content);
});
},
fetchEmployees(context, newProfile)
{
}
},
mutations:{
setCurrentSite(state, newSite){
state.currentSite = newSite;
},
setCurrentProfile(state, newProfile){
state.currentProfile = newProfile;
},
setCurrentEmployee(state, newEmployee){
state.currentEmployee = newEmployee;
},
reloadProfiles(state, profiles){
state.profiles = profiles;
}
},
getters:{
filterProfiles(state){
return siteId => state.profiles.filter(profile => {
return profile.site_id === siteId;
});
}
}
};
export default new Vuex.Store({
modules: {
// manageSchedulesModale: manageSchedulesModale
},
mutations: {
setModule(state, name){
if(typeof state[name] === 'undefined')
{
this.registerModule(name, manageSchedulesModale);
}
}
}
})
现在,这是我的列表的代码:
<template lang="pug">
div
.btn.dropdown-toggle.text-left.btn-block.k-selectbox-toggle(tabindex="0", v-on:keydown.down.stop="selectDown", v-on:keydown.up.stop="selectUp", v-on:keydown.enter="updateClose")
k-icon(:icon="currentOption.icon||icon||placeholderIcon", v-if="currentOption.icon||icon||(!currentOption.text&&placeholderIcon)")
span(v-if="currentOption.icon||icon||(!currentOption.text&&placeholderIcon)")
span(v-html="currentOption.html||currentOption.text||placeholder")
.dropdown-menu.pre-scrollable(v-if="searchResults.length")
.search-indicator(hidden v-if="options.length>5")
.dropdown-header.pr-3.pl-3(v-show="options.length>5")
input.form-control(type="text", :placeholder='__("Search...")', style="width:100%", v-model="searchText", v-on:keydown.down.stop="selectDown", v-on:keydown.up.stop="selectUp", v-on:keydown.enter.stop="updateClose()")
//{{__("Search...")}} FIXME because poedit is retarded
a(v-for="(option,index) in searchResults", :class="'dropdown-item '+(option.id==value?'active':'')", href="#" , v-on:mousedown="update(option.id)")
k-icon(:icon="option.icon||icon", v-if="option.icon||icon")
span(v-if="option.icon||icon")
span(v-html="option.html||option.text")
.dropdown-menu.pre-scrollable(v-else)
.dropdown-item {{__("Empty List")}}
input(type="hidden", :name="name", :value="value")
</template>
<script>
import { mapGetters } from 'vuex';
var allowClose = true;
// autofocus search in selectbox dropdowns
$(document).on('shown.bs.dropdown', function(e){
var searchInput = $(e.target).find('.search-indicator')
if(searchInput.length){
allowClose = false;
$(e.target).find('.form-control').focus();
}
});
// close on blur
$(document).on('blur', '.k-selectbox-toggle', function(e){
var element = $(this);
if(allowClose){
setTimeout(a=>{
element.next().removeClass("show") // WHY DOES THIS WORK ?!?!?!?
}, 100)
}
allowClose = true;
});
$(document).on('blur', '.k-selectbox-toggle+.dropdown-menu input.form-control', function(e){
var element = $(this);
setTimeout(a=>{
element.parent().parent().removeClass("show") // WHY DOES THIS WORK ?!?!?!?
}, 100);
});
$(document).on('focus','.k-selectbox-toggle', e => {
$(e.target).dropdown('toggle');
})
// mod negative numbers
var mod = (x, n) => ((x%n)+n)%n;
export default {
methods:{
update(id){
if(id!==undefined){
this.$emit('update:value', id)
}
},
updateClose(e){
if(this.searchResults[0]&&_.findIndex(this.searchResults, {id:this.value})==-1) this.$emit('update:value', this.searchResults[0].id);
this.$emit('update:value', this.value);
$(this.$el).find("input.form-control").blur();
$(this.$el).find(".k-selectbox-toggle").blur();
},
selectDown(e){
var index = _.findIndex(this.searchResults, {id:this.value});
if(index==-1)index=-1;
var length = this.searchResults.length;
this.value = this.searchResults[(index+1)%length].id;
e.preventDefault();
},
selectUp(e){
var index = _.findIndex(this.searchResults, {id:this.value});
if(index==-1)index=1;
var length = this.searchResults.length;
this.value = this.searchResults[mod(index-1, length)].id;
e.preventDefault();
}
},
computed:{
searchResults(){
var exclude = this.exclude||[];
// console.log(this.filterProfiles(26));
if(exclude[0]&&exclude[0].id){
exclude = exclude.map(a=>a.id)
}
return this.options.filter(a=>{
return _.lowerCase(a.text)
.indexOf(
_.lowerCase(this.searchText)
) !== -1;
}).filter(a=>exclude.indexOf(a.id) == -1);
},
currentOption(){
var currentValue = _.find(this.options, {id:this.value}) || _.find(this.options, {id:-1}) || (this.placeholder?{}:this.options[0]) || {};
var mutation = null;
// console.log("Tobbi Filteau");
// console.log(this.$store.state.manageSchedules);
if(this.model == "sites")
{
console.log("111;");
// console.log("djkflkjldflkjdsfsdlk");
this.$store.commit("setCurrentSite", currentValue);
this.$store.dispatch("fetchProfiles", currentValue);
}
else if(this.model == "profiles")
{
console.log("222;");
this.$store.commit("setCurrentProfile", currentValue);
}
else
{
console.log("333;");
this.$store.commit("setCurrentEmployee", currentValue);
}
return currentValue;
},
...mapGetters(['filterProfiles'])
},
watch:{
options(){
$(this.$el).find(".dropdown-menu").removeClass("show")
}
}
};
</script>
问题是我遇到了意外的行为。您会看到,在currentOption()
计算属性中,我有一个“ if”,它可以帮助我确定实际触发了哪个列表。现在,如果更改员工列表的值,最终在控制台中将显示以下输出:
333
111
222
但是,如果我评论以下行:
this.$store.dispatch("fetchProfiles", currentValue);
我得到的输出实际上只有“ 333”(这是我实际上期望的)。我不明白为什么添加“调度”会触发所有三个列表中的更改,即使它甚至都不应该执行。谁能解释?