如何正确传递参数给vuex mapActions
How to correctly pass paramters to vuex mapActions
我有一个 ProjectPage.vue 页面显示 v-data-table 中的问题。项目从侧边栏中的服务器 api 调用中检索并显示在那里。选择一个项目后,我想使用该项目的 id 从服务器获取它的问题。是否可以使用 Vuex 来实现。
是否可以使用 Vuex,每个项目都可以使用相同的 .js 文件来检索其问题,因为可能有任意数量的项目。
我想做的是从 VerticalNavMenu.vue 开始,将 id 和项目作为道具传递给 ProjectPage,这样我就可以将 id 作为参数传递给 ProjectPage 中的 mapAction 以检索其问题。
我现在的方法不起作用。当我打开项目的 table
时 table 没有可用数据
我希望 Peoject_Pages.js 帮助理解我的问题。
VerticalNavMenu.vue(相关模板行为 38 -> 48)
<template>
<v-navigation-drawer
:value="isDrawerOpen"
app
expand-on-hover
mini-variant-width="60px"
floating
width="260"
class="app-navigation-menu"
:right="$vuetify.rtl"
@input="val => $emit('update:is-drawer-open', val)"
>
<!-- Navigation Header -->
<div class="vertical-nav-header d-flex items-center ps-6 pe-5 pt-5 pb-2">
<router-link to="/" class="d-flex align-center text-decoration-none">
<v-slide-x-transition>
<h2 class="app-title text--primary">ITrackerHub</h2>
</v-slide-x-transition>
</router-link>
</div>
<!-- Navigation Items -->
<v-list expand shaped class="vertical-nav-menu-items pr-5">
<nav-menu-link
title="Dashboard"
:to="{ name: 'dashboard' }"
:icon="icons.mdiHomeOutline"
></nav-menu-link>
<v-list>
<v-list-group :prepend-icon="icons.mdiTelevisionGuide">
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="'My Projects'"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item v-for="(project, index) in ProjectList" :key="index">
<v-icon class="mx-2">{{ icons.mdiAccountGroup }}</v-icon>
<v-list-item-content>
<router-link
class="d-flex align-center text-decoration-none black--text"
:to="{ name: 'ProjectPage', params: { id: project.id, project} }"
>
{{ project.title }}
</router-link>
</v-list-item-content>
</v-list-item>
</v-list-group>
</v-list>
<nav-menu-link title="My Issues" :to="{ name: 'MyIssues' }" :icon="icons.mdiBookEditOutline"></nav-menu-link>
<nav-menu-link
style="position:relative; top:70px;"
title="Account Settings"
:to="{ name: 'pages-account-settings' }"
:icon="icons.mdiAccountCogOutline"
></nav-menu-link>
<nav-menu-link
style="position: relative; top: 200px"
title="Create Project"
:to="{ name: 'CreateProject' }"
:icon="icons.mdiPlusMinus"
></nav-menu-link>
</v-list>
</v-navigation-drawer>
</template>
<script>
// eslint-disable-next-line object-curly-newline
import {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
} from '@mdi/js'
// import NavMenuSectionTitle from './components/NavMenuSectionTitle.vue'
import NavMenuGroup from './components/NavMenuGroup.vue'
import NavMenuLink from './components/NavMenuLink.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
// NavMenuSectionTitle,
NavMenuGroup,
NavMenuLink,
},
computed: {
...mapGetters(['ProjectList'])
},
methods: {
...mapActions(['fetchProjects'])
},
created() {
// this.getProjectList()
this.fetchProjects()
},
props: {
isDrawerOpen: {
type: Boolean,
default: null,
},
},
setup() {
return {
icons: {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
},
}
},
}
</script>
<style lang="scss" scoped>
.app-title {
font-size: 1.25rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: 0.3px;
}
// ? Adjust this `translateX` value to keep logo in center when vertical nav menu is collapsed (Value depends on your logo)
.app-logo {
transition: all 0.18s ease-in-out;
.v-navigation-drawer--mini-variant & {
transform: translateX(-10px);
}
}
@include theme(app-navigation-menu) using ($material) {
background-color: map-deep-get($material, 'background');
}
.app-navigation-menu {
.v-list-item {
&.vertical-nav-menu-link {
::v-deep .v-list-item__icon {
.v-icon {
transition: none !important;
}
}
}
}
}
</style>
NavBar.js
import axios from 'axios'
const state = {
Projects: [],
}
const getters = {
ProjectList: (state) => state.Projects
}
const actions = {
async fetchProjects({ commit }) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-projects/')
commit('setProjects', response.data)
}
}
const mutations = {
setProjects: (state, Projects) => (state.Projects = Projects)
}
export default {
state,
getters,
actions,
mutations
}
ProjectPage.vue
<template>
<v-card>
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
{{ project.title }}
</h1>
</v-card-title>
<v-tabs v-model="tab" background-color="primary" dark centered>
<v-tab v-for="item in items" :key="item.tab">{{ item.tab }}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in items" :key="item.tab">
<v-card flat>
<v-card v-if="item.tab == 'Issues'">
<template>
<div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on }">
<v-btn class="success" dark v-on="on">
<v-icon align-self: left>
mdi-plus-thick
</v-icon>
Add Issue
</v-btn>
</template>
<v-card>
<v-card-title>
<h2>Add Issue</h2>
</v-card-title>
<v-card-text>
<v-form class="px-3">
<v-text-field v-model="title" label="Title"></v-text-field>
<v-textarea v-model="description" label="Description"></v-textarea>
<v-select
item-text="text"
item-value="value"
:items="time_est"
v-model="time_estimate"
label="Time Estimate"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueType"
v-model="issue_type"
label="Issue Type"
></v-select>
<v-select
item-text="title"
item-value="id"
v-model="issue_status"
label="Issue Status"
:items="issueStatus"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueSeverity"
v-model="issue_severity"
label="Issue Severity"
></v-select>
<v-spacer></v-spacer>
<v-btn
flat
@click="
postIssue()
reloadPage()
"
class="success mx-0 mt-3"
>
<v-icon align-self:left>mdi-content-save-check-outline</v-icon> Save</v-btn
>
</v-form>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<v-card>
<v-data-table
:headers="headers"
:items="Project_Issues"
item-key="full_name"
class="table-rounded"
hide-default-footer
enable-sort
@click:row="handleClick"
>
</v-data-table>
</v-card>
</v-card>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card>
</template>
<script>
import axios from 'axios'
import { mapGetters, mapActions } from 'vuex'
export default {
props: ['id', 'project'],
computed: {
...mapGetters(['Project_Issues']),
},
data() {
return {
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
title: '',
description: '',
time_estimate: '',
issue_type: '',
issue_status: '',
issue_severity: '',
time_est: [
{ value: '1', text: '1' },
{ value: '2', text: '2' },
{ value: '3', text: '3' },
{ value: '4', text: '4' },
{ value: '5', text: '5' },
{ value: '6', text: '6' },
{ value: '7', text: '7' },
{ value: '8', text: '8' },
],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'user' },
{ text: 'Type', value: 'issueType' },
{ text: 'Status', value: 'issueStatus' },
{ text: 'Severity', value: 'issueSeverity' },
],
}
},
methods: {
...mapActions(['fetchProjectIssueList']),
handleClick(issue) {
this.$router.push({
name: 'IssuePage',
params: { id: issue.id, issue },
})
},
postIssue() {
axios
.post('https://fadiserver.herokuapp.com/api/v1/my-issues/', {
title: this.title,
description: this.description,
time_estimate: this.time_estimate,
userid: 'f3260d22-8b5b-4c40-be1e-d93ba732c576',
projectid: this.id,
issueTypeId: this.issue_type,
issueStatusId: this.issue_status,
issueSeverityId: this.issue_severity,
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
},
reloadPage() {
window.location.reload()
},
},
mounted() {
this.fetchProjectIssueList(this.id)
},
}
</script>
<style scoped>
.v-btn {
left: 43%;
}
</style>
Project_Page.js
import axios from 'axios'
const state = {
issuesList: [],
}
const getters = {
Project_Issues: (state) => state.issuesList
}
const actions = {
async fetchProjectIssueList({ commit }, {projectid}) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid)
commit('setProjectIssues', response.data)
},
}
const mutations = {
setProjectIssues: (state, issuesList) => (state.issuesList = issuesList)
}
export default {
state,
getters,
actions,
mutations
}
有两种方法可以解决您的问题。
- 或者您在
fetchProjectIssueList
方法中传递一个带有键 projectid
的对象
- 或者你不需要在
fetchProjectIssueList
方法中解构对象
this.fetchProjectIssueList({ projectid: this.id })
...
async fetchProjectIssueList({ commit }, {projectid}) { ... }
或
this.fetchProjectIssueList(this.id)
...
async fetchProjectIssueList({ commit }, projectid) { ... }
我有一个 ProjectPage.vue 页面显示 v-data-table 中的问题。项目从侧边栏中的服务器 api 调用中检索并显示在那里。选择一个项目后,我想使用该项目的 id 从服务器获取它的问题。是否可以使用 Vuex 来实现。
是否可以使用 Vuex,每个项目都可以使用相同的 .js 文件来检索其问题,因为可能有任意数量的项目。
我想做的是从 VerticalNavMenu.vue 开始,将 id 和项目作为道具传递给 ProjectPage,这样我就可以将 id 作为参数传递给 ProjectPage 中的 mapAction 以检索其问题。
我现在的方法不起作用。当我打开项目的 table
时 table 没有可用数据我希望 Peoject_Pages.js 帮助理解我的问题。
VerticalNavMenu.vue(相关模板行为 38 -> 48)
<template>
<v-navigation-drawer
:value="isDrawerOpen"
app
expand-on-hover
mini-variant-width="60px"
floating
width="260"
class="app-navigation-menu"
:right="$vuetify.rtl"
@input="val => $emit('update:is-drawer-open', val)"
>
<!-- Navigation Header -->
<div class="vertical-nav-header d-flex items-center ps-6 pe-5 pt-5 pb-2">
<router-link to="/" class="d-flex align-center text-decoration-none">
<v-slide-x-transition>
<h2 class="app-title text--primary">ITrackerHub</h2>
</v-slide-x-transition>
</router-link>
</div>
<!-- Navigation Items -->
<v-list expand shaped class="vertical-nav-menu-items pr-5">
<nav-menu-link
title="Dashboard"
:to="{ name: 'dashboard' }"
:icon="icons.mdiHomeOutline"
></nav-menu-link>
<v-list>
<v-list-group :prepend-icon="icons.mdiTelevisionGuide">
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="'My Projects'"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item v-for="(project, index) in ProjectList" :key="index">
<v-icon class="mx-2">{{ icons.mdiAccountGroup }}</v-icon>
<v-list-item-content>
<router-link
class="d-flex align-center text-decoration-none black--text"
:to="{ name: 'ProjectPage', params: { id: project.id, project} }"
>
{{ project.title }}
</router-link>
</v-list-item-content>
</v-list-item>
</v-list-group>
</v-list>
<nav-menu-link title="My Issues" :to="{ name: 'MyIssues' }" :icon="icons.mdiBookEditOutline"></nav-menu-link>
<nav-menu-link
style="position:relative; top:70px;"
title="Account Settings"
:to="{ name: 'pages-account-settings' }"
:icon="icons.mdiAccountCogOutline"
></nav-menu-link>
<nav-menu-link
style="position: relative; top: 200px"
title="Create Project"
:to="{ name: 'CreateProject' }"
:icon="icons.mdiPlusMinus"
></nav-menu-link>
</v-list>
</v-navigation-drawer>
</template>
<script>
// eslint-disable-next-line object-curly-newline
import {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
} from '@mdi/js'
// import NavMenuSectionTitle from './components/NavMenuSectionTitle.vue'
import NavMenuGroup from './components/NavMenuGroup.vue'
import NavMenuLink from './components/NavMenuLink.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
// NavMenuSectionTitle,
NavMenuGroup,
NavMenuLink,
},
computed: {
...mapGetters(['ProjectList'])
},
methods: {
...mapActions(['fetchProjects'])
},
created() {
// this.getProjectList()
this.fetchProjects()
},
props: {
isDrawerOpen: {
type: Boolean,
default: null,
},
},
setup() {
return {
icons: {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
},
}
},
}
</script>
<style lang="scss" scoped>
.app-title {
font-size: 1.25rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: 0.3px;
}
// ? Adjust this `translateX` value to keep logo in center when vertical nav menu is collapsed (Value depends on your logo)
.app-logo {
transition: all 0.18s ease-in-out;
.v-navigation-drawer--mini-variant & {
transform: translateX(-10px);
}
}
@include theme(app-navigation-menu) using ($material) {
background-color: map-deep-get($material, 'background');
}
.app-navigation-menu {
.v-list-item {
&.vertical-nav-menu-link {
::v-deep .v-list-item__icon {
.v-icon {
transition: none !important;
}
}
}
}
}
</style>
NavBar.js
import axios from 'axios'
const state = {
Projects: [],
}
const getters = {
ProjectList: (state) => state.Projects
}
const actions = {
async fetchProjects({ commit }) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-projects/')
commit('setProjects', response.data)
}
}
const mutations = {
setProjects: (state, Projects) => (state.Projects = Projects)
}
export default {
state,
getters,
actions,
mutations
}
ProjectPage.vue
<template>
<v-card>
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
{{ project.title }}
</h1>
</v-card-title>
<v-tabs v-model="tab" background-color="primary" dark centered>
<v-tab v-for="item in items" :key="item.tab">{{ item.tab }}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in items" :key="item.tab">
<v-card flat>
<v-card v-if="item.tab == 'Issues'">
<template>
<div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on }">
<v-btn class="success" dark v-on="on">
<v-icon align-self: left>
mdi-plus-thick
</v-icon>
Add Issue
</v-btn>
</template>
<v-card>
<v-card-title>
<h2>Add Issue</h2>
</v-card-title>
<v-card-text>
<v-form class="px-3">
<v-text-field v-model="title" label="Title"></v-text-field>
<v-textarea v-model="description" label="Description"></v-textarea>
<v-select
item-text="text"
item-value="value"
:items="time_est"
v-model="time_estimate"
label="Time Estimate"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueType"
v-model="issue_type"
label="Issue Type"
></v-select>
<v-select
item-text="title"
item-value="id"
v-model="issue_status"
label="Issue Status"
:items="issueStatus"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueSeverity"
v-model="issue_severity"
label="Issue Severity"
></v-select>
<v-spacer></v-spacer>
<v-btn
flat
@click="
postIssue()
reloadPage()
"
class="success mx-0 mt-3"
>
<v-icon align-self:left>mdi-content-save-check-outline</v-icon> Save</v-btn
>
</v-form>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<v-card>
<v-data-table
:headers="headers"
:items="Project_Issues"
item-key="full_name"
class="table-rounded"
hide-default-footer
enable-sort
@click:row="handleClick"
>
</v-data-table>
</v-card>
</v-card>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card>
</template>
<script>
import axios from 'axios'
import { mapGetters, mapActions } from 'vuex'
export default {
props: ['id', 'project'],
computed: {
...mapGetters(['Project_Issues']),
},
data() {
return {
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
title: '',
description: '',
time_estimate: '',
issue_type: '',
issue_status: '',
issue_severity: '',
time_est: [
{ value: '1', text: '1' },
{ value: '2', text: '2' },
{ value: '3', text: '3' },
{ value: '4', text: '4' },
{ value: '5', text: '5' },
{ value: '6', text: '6' },
{ value: '7', text: '7' },
{ value: '8', text: '8' },
],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'user' },
{ text: 'Type', value: 'issueType' },
{ text: 'Status', value: 'issueStatus' },
{ text: 'Severity', value: 'issueSeverity' },
],
}
},
methods: {
...mapActions(['fetchProjectIssueList']),
handleClick(issue) {
this.$router.push({
name: 'IssuePage',
params: { id: issue.id, issue },
})
},
postIssue() {
axios
.post('https://fadiserver.herokuapp.com/api/v1/my-issues/', {
title: this.title,
description: this.description,
time_estimate: this.time_estimate,
userid: 'f3260d22-8b5b-4c40-be1e-d93ba732c576',
projectid: this.id,
issueTypeId: this.issue_type,
issueStatusId: this.issue_status,
issueSeverityId: this.issue_severity,
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
},
reloadPage() {
window.location.reload()
},
},
mounted() {
this.fetchProjectIssueList(this.id)
},
}
</script>
<style scoped>
.v-btn {
left: 43%;
}
</style>
Project_Page.js
import axios from 'axios'
const state = {
issuesList: [],
}
const getters = {
Project_Issues: (state) => state.issuesList
}
const actions = {
async fetchProjectIssueList({ commit }, {projectid}) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid)
commit('setProjectIssues', response.data)
},
}
const mutations = {
setProjectIssues: (state, issuesList) => (state.issuesList = issuesList)
}
export default {
state,
getters,
actions,
mutations
}
有两种方法可以解决您的问题。
- 或者您在
fetchProjectIssueList
方法中传递一个带有键projectid
的对象 - 或者你不需要在
fetchProjectIssueList
方法中解构对象
this.fetchProjectIssueList({ projectid: this.id })
...
async fetchProjectIssueList({ commit }, {projectid}) { ... }
或
this.fetchProjectIssueList(this.id)
...
async fetchProjectIssueList({ commit }, projectid) { ... }