传递给 Vuex 模块的函数后的 Vue TypeScript 未定义值
Vue TypeScript Undefined value after passing to function of Vuex module
我的组件中有一个名为 save 的异步函数
async save(): Promise<void> {
if (!this.ValidateForm()) {
notifyError("", "Please enter all fields correctly");
}
else {
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
notifySuccess("Your profile updated");
}
}
当这一行执行时:
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
第二个和第三个参数的值在 userModule.update 中未定义。
另外我不得不说我没有使用任何箭头函数
我试过 console.log(this.user, this.file) 一切正常。
这是我的代码:
AccountSetting.ts HTML
<template>
<div>
<div class="row justify-content-center">
<!-- left column -->
<div class="col-md-6">
<!-- general form elements -->
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Change your information</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form>
<div class="card-body">
<div class="form-row">
<div class="col form-group">
<label>Username </label>
<input
type="text"
v-model="user.username"
@change="checkUsername()"
class="form-control"
placeholder="Enter new Username"
/>
<small class="validation">{{ validations.username }}</small>
</div>
<div class="col form-group">
<label>Profile Pricture </label>
<div class="custom-file">
<input
id="customFile"
type="file"
class="custom-file-input"
v-on:change="handleFileUpload($event)"
accept="image/*"
/>
<label class="custom-file-label" for="customFile">{{
lblFilename
}}</label>
</div>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Firstname </label>
<input
type="text"
v-model="user.firstname"
@change="checkFirstname()"
class="form-control"
placeholder="Enter your Firstname"
/>
<small class="validation">{{ validations.firstname }}</small>
</div>
<div class="col form-group">
<label>Lastname</label>
<input
type="text"
v-model="user.lastname"
@change="checkLastname()"
class="form-control"
placeholder="Enter your Lastname"
/>
<small class="validation">{{ validations.lastname }}</small>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Email </label>
<input
type="text"
v-model="user.email"
@change="checkEmail()"
class="form-control"
placeholder="Enter your Email address"
/>
<small class="validation">{{ validations.email }}</small>
</div>
<div class="col form-group">
<label>Phone Number</label>
<input
type="text"
v-model="user.phoneNumber"
@change="checkPhonenumber()"
class="form-control"
placeholder="Enter your Phone number"
/>
<small class="validation">{{
validations.phoneNumber
}}</small>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Birthdate </label>
<input
type="date"
v-model="user.birthdate"
class="form-control"
placeholder=""
/>
</div>
<div class="col form-group">
<label>Gender</label>
<div class="form-control">
<div class="form-check form-check-inline">
<label class="form-check-label pr-2" for="inlineRadioMale"
>Male</label
>
<input
id="inlineRadioMale"
type="radio"
name="gender"
value="1"
v-model="user.gender"
class="form-check-input"
checked
/>
</div>
<div class="form-check form-check-inline">
<label
class="form-check-label pl-3 pr-2"
for="inlineRadioFemale"
>Female</label
>
<input
id="inlineRadioFemale"
type="radio"
name="gender"
value="2"
v-model="user.gender"
class="form-check-input"
/>
</div>
</div>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="button" class="btn btn-primary" @click="save()">
Save
</button>
</div>
</form>
</div>
<!-- /.card -->
</div>
</div>
</div>
</template>
AccountSetting.ts 脚本
import { Component, Vue } from "vue-property-decorator";
import { UserUpdate } from "@/models/user/user";
import userModule from "@/store/modules/user";
import validationUtils from "@/common/validationUtils";
import { notifySuccess, notifyError } from
"@/common/notificationUtils";
import GenderType from "@/common/Enums/genderType";
import { isNullOrEmpty } from "@/common/stringUtils";
@Component
export default class AccountSetting extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private file: any;
private lblFilename = "Choose file";
private user: UserUpdate = {
username: userModule.currentUser?.username as string,
firstname: userModule.currentUser?.firstname as string,
lastname: userModule.currentUser?.lastname as string,
email: userModule.currentUser?.email as string,
birthdate: userModule.currentUser?.birthdate as string,
phoneNumber: userModule.currentUser?.username as string,
gender: userModule.currentUser?.gender as GenderType,
teamId: userModule.currentUser?.teamId as number,
profilePictureId: userModule.currentUser?.profilePictureId as number,
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private validations: any = {
username: "",
password: "",
firstname: "",
lastname: "",
email: "",
phoneNumber: "",
};
checkUsername(): void {
if (!validationUtils.isValidUsername(this.user.username)) {
this.validations.username = "Username is invalid";
}
else if (this.user.username.length == 0) {
this.validations.username = "Username is invalid";
}
else if (this.user.username.length > 15) {
this.validations.username = "Username should be less than 15 characters";
}
else {
this.validations.username = "";
}
}
checkEmail(): void {
if (!validationUtils.isValidEmail(this.user.email)) {
this.validations.email = "Email is invalid";
} else {
this.validations.email = "";
}
}
checkFirstname(): void {
if (this.user.firstname.length == 0) {
this.validations.firstname = "Firstname is invalid";
}
else if (this.user.firstname.length > 35) {
this.validations.firstname = "Firstname should be less than 35 characters";
}
else {
this.validations.firstname = "";
}
}
checkLastname(): void {
if (this.user.lastname.length == 0) {
this.validations.lastname = "Lastname is invalid";
}
else if (this.user.firstname.length > 35) {
this.validations.lastname = "Lastname should be less than 35 characters";
}
else {
this.validations.lastname = "";
}
}
checkPhonenumber(): void {
if (this.user.phoneNumber.length == 0) {
this.validations.phoneNumber = "Phone Number is invalid";
}
else {
this.validations.phoneNumber = "";
}
}
ValidateForm(): boolean {
this.checkUsername();
this.checkFirstname();
this.checkLastname();
this.checkEmail();
this.checkPhonenumber();
if (this.user.username == "" || !isNullOrEmpty(this.validations.userUsername)) {
return false;
}
if (this.user.firstname == "" || !isNullOrEmpty(this.validations.firstname)) {
return false;
}
if (this.user.lastname == "" || !isNullOrEmpty(this.validations.lastname)) {
return false;
}
if (this.user.email == "" || !isNullOrEmpty(this.validations.email)) {
return false;
}
if (this.user.phoneNumber == "" || !isNullOrEmpty(this.validations.phoneNumber)) {
return false;
}
return true;
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
handleFileUpload(event: any): void {
this.file = event.target.files[0];
this.lblFilename = this.file.name;
}
async save(): Promise<void> {
if (!this.ValidateForm()) {
notifyError("", "Please enter all fields correctly");
}
else {
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
notifySuccess("Your profile updated");
}
}
}
Vuex 模块
user.ts :
import {
Action,
getModule,
Module,
Mutation,
VuexModule
} from "vuex-module-decorators";
import modulesNames from "@/store/moduleNames";
import store from "@/store/index";
import localStorageUtils from "@/common/localStorageUtils";
import { User, UserCreate, UserUpdate } from
"@/models/user/user";
import Token from "@/models/authentication/token";
import authenticationService from
"@/services/authentication/authenticationService";
import userService from "@/services/user/userService";
import Login from "@/models/user/login";
import { isEmptyObject } from "@/common/objectUtils";
@Module({ dynamic: true, namespaced: true, store, name: modulesNames.user })
class UserModule extends VuexModule {
private _currentUser?: User = localStorageUtils.getItem("User");
private _authToken?: Token = localStorageUtils.getItem("Token");
get currentUser(): User | undefined | null {
return this._currentUser;
}
get authToken(): Token | undefined | null {
return this._authToken;
}
get isLoggedIn(): boolean {
return !isEmptyObject(this.currentUser);
}
@Mutation
private SET_CURRENT_USER(currentUser?: User): void {
if (currentUser) {
this._currentUser = currentUser;
localStorageUtils.setItem("User", currentUser);
} else {
this._authToken = undefined;
localStorageUtils.removeItem("User");
}
}
@Mutation
private SET_AUTH_TOKEN(authToken?: Token): void {
if (authToken) {
this._authToken = authToken;
localStorageUtils.setItem("Token", authToken);
} else {
this._authToken = undefined;
localStorageUtils.removeItem("Token");
}
}
@Action({ rawError: true })
public async login(login: Login): Promise<void> {
const response = await authenticationService.login(login);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async register(userCreateOrUpdate: UserCreate): Promise<void> {
const response = await authenticationService.register(userCreateOrUpdate);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async update(id: number, userUpdate: UserUpdate, file: any): Promise<void> {
const response = await userService.updateUser(id, userUpdate, file);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async logout(): Promise<void> {
await authenticationService.logout();
this.SET_AUTH_TOKEN(undefined);
this.SET_CURRENT_USER(undefined);
}
}
export default getModule(UserModule);
index.ts
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {},
});
modulesNames.ts :
const modulesNames = {
user: "user",
};
export default modulesNames;
我是 javascript 以及打字稿和前端框架的新手。
在 Whosebug 中多次尝试解决此问题后,还阅读了文档
,我什么也没发现,所以我决定做更多的调试,我明白了
Vuex 操作仅接受一个参数,因此另一个参数值未定义
我的组件中有一个名为 save 的异步函数
async save(): Promise<void> {
if (!this.ValidateForm()) {
notifyError("", "Please enter all fields correctly");
}
else {
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
notifySuccess("Your profile updated");
}
}
当这一行执行时:
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
第二个和第三个参数的值在 userModule.update 中未定义。
另外我不得不说我没有使用任何箭头函数 我试过 console.log(this.user, this.file) 一切正常。
这是我的代码:
AccountSetting.ts HTML
<template>
<div>
<div class="row justify-content-center">
<!-- left column -->
<div class="col-md-6">
<!-- general form elements -->
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Change your information</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form>
<div class="card-body">
<div class="form-row">
<div class="col form-group">
<label>Username </label>
<input
type="text"
v-model="user.username"
@change="checkUsername()"
class="form-control"
placeholder="Enter new Username"
/>
<small class="validation">{{ validations.username }}</small>
</div>
<div class="col form-group">
<label>Profile Pricture </label>
<div class="custom-file">
<input
id="customFile"
type="file"
class="custom-file-input"
v-on:change="handleFileUpload($event)"
accept="image/*"
/>
<label class="custom-file-label" for="customFile">{{
lblFilename
}}</label>
</div>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Firstname </label>
<input
type="text"
v-model="user.firstname"
@change="checkFirstname()"
class="form-control"
placeholder="Enter your Firstname"
/>
<small class="validation">{{ validations.firstname }}</small>
</div>
<div class="col form-group">
<label>Lastname</label>
<input
type="text"
v-model="user.lastname"
@change="checkLastname()"
class="form-control"
placeholder="Enter your Lastname"
/>
<small class="validation">{{ validations.lastname }}</small>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Email </label>
<input
type="text"
v-model="user.email"
@change="checkEmail()"
class="form-control"
placeholder="Enter your Email address"
/>
<small class="validation">{{ validations.email }}</small>
</div>
<div class="col form-group">
<label>Phone Number</label>
<input
type="text"
v-model="user.phoneNumber"
@change="checkPhonenumber()"
class="form-control"
placeholder="Enter your Phone number"
/>
<small class="validation">{{
validations.phoneNumber
}}</small>
</div>
</div>
<div class="form-row">
<div class="col form-group">
<label>Birthdate </label>
<input
type="date"
v-model="user.birthdate"
class="form-control"
placeholder=""
/>
</div>
<div class="col form-group">
<label>Gender</label>
<div class="form-control">
<div class="form-check form-check-inline">
<label class="form-check-label pr-2" for="inlineRadioMale"
>Male</label
>
<input
id="inlineRadioMale"
type="radio"
name="gender"
value="1"
v-model="user.gender"
class="form-check-input"
checked
/>
</div>
<div class="form-check form-check-inline">
<label
class="form-check-label pl-3 pr-2"
for="inlineRadioFemale"
>Female</label
>
<input
id="inlineRadioFemale"
type="radio"
name="gender"
value="2"
v-model="user.gender"
class="form-check-input"
/>
</div>
</div>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="button" class="btn btn-primary" @click="save()">
Save
</button>
</div>
</form>
</div>
<!-- /.card -->
</div>
</div>
</div>
</template>
AccountSetting.ts 脚本
import { Component, Vue } from "vue-property-decorator";
import { UserUpdate } from "@/models/user/user";
import userModule from "@/store/modules/user";
import validationUtils from "@/common/validationUtils";
import { notifySuccess, notifyError } from
"@/common/notificationUtils";
import GenderType from "@/common/Enums/genderType";
import { isNullOrEmpty } from "@/common/stringUtils";
@Component
export default class AccountSetting extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private file: any;
private lblFilename = "Choose file";
private user: UserUpdate = {
username: userModule.currentUser?.username as string,
firstname: userModule.currentUser?.firstname as string,
lastname: userModule.currentUser?.lastname as string,
email: userModule.currentUser?.email as string,
birthdate: userModule.currentUser?.birthdate as string,
phoneNumber: userModule.currentUser?.username as string,
gender: userModule.currentUser?.gender as GenderType,
teamId: userModule.currentUser?.teamId as number,
profilePictureId: userModule.currentUser?.profilePictureId as number,
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private validations: any = {
username: "",
password: "",
firstname: "",
lastname: "",
email: "",
phoneNumber: "",
};
checkUsername(): void {
if (!validationUtils.isValidUsername(this.user.username)) {
this.validations.username = "Username is invalid";
}
else if (this.user.username.length == 0) {
this.validations.username = "Username is invalid";
}
else if (this.user.username.length > 15) {
this.validations.username = "Username should be less than 15 characters";
}
else {
this.validations.username = "";
}
}
checkEmail(): void {
if (!validationUtils.isValidEmail(this.user.email)) {
this.validations.email = "Email is invalid";
} else {
this.validations.email = "";
}
}
checkFirstname(): void {
if (this.user.firstname.length == 0) {
this.validations.firstname = "Firstname is invalid";
}
else if (this.user.firstname.length > 35) {
this.validations.firstname = "Firstname should be less than 35 characters";
}
else {
this.validations.firstname = "";
}
}
checkLastname(): void {
if (this.user.lastname.length == 0) {
this.validations.lastname = "Lastname is invalid";
}
else if (this.user.firstname.length > 35) {
this.validations.lastname = "Lastname should be less than 35 characters";
}
else {
this.validations.lastname = "";
}
}
checkPhonenumber(): void {
if (this.user.phoneNumber.length == 0) {
this.validations.phoneNumber = "Phone Number is invalid";
}
else {
this.validations.phoneNumber = "";
}
}
ValidateForm(): boolean {
this.checkUsername();
this.checkFirstname();
this.checkLastname();
this.checkEmail();
this.checkPhonenumber();
if (this.user.username == "" || !isNullOrEmpty(this.validations.userUsername)) {
return false;
}
if (this.user.firstname == "" || !isNullOrEmpty(this.validations.firstname)) {
return false;
}
if (this.user.lastname == "" || !isNullOrEmpty(this.validations.lastname)) {
return false;
}
if (this.user.email == "" || !isNullOrEmpty(this.validations.email)) {
return false;
}
if (this.user.phoneNumber == "" || !isNullOrEmpty(this.validations.phoneNumber)) {
return false;
}
return true;
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
handleFileUpload(event: any): void {
this.file = event.target.files[0];
this.lblFilename = this.file.name;
}
async save(): Promise<void> {
if (!this.ValidateForm()) {
notifyError("", "Please enter all fields correctly");
}
else {
await userModule.update(userModule.currentUser?.id as number, this.user, this.file);
notifySuccess("Your profile updated");
}
}
}
Vuex 模块 user.ts :
import {
Action,
getModule,
Module,
Mutation,
VuexModule
} from "vuex-module-decorators";
import modulesNames from "@/store/moduleNames";
import store from "@/store/index";
import localStorageUtils from "@/common/localStorageUtils";
import { User, UserCreate, UserUpdate } from
"@/models/user/user";
import Token from "@/models/authentication/token";
import authenticationService from
"@/services/authentication/authenticationService";
import userService from "@/services/user/userService";
import Login from "@/models/user/login";
import { isEmptyObject } from "@/common/objectUtils";
@Module({ dynamic: true, namespaced: true, store, name: modulesNames.user })
class UserModule extends VuexModule {
private _currentUser?: User = localStorageUtils.getItem("User");
private _authToken?: Token = localStorageUtils.getItem("Token");
get currentUser(): User | undefined | null {
return this._currentUser;
}
get authToken(): Token | undefined | null {
return this._authToken;
}
get isLoggedIn(): boolean {
return !isEmptyObject(this.currentUser);
}
@Mutation
private SET_CURRENT_USER(currentUser?: User): void {
if (currentUser) {
this._currentUser = currentUser;
localStorageUtils.setItem("User", currentUser);
} else {
this._authToken = undefined;
localStorageUtils.removeItem("User");
}
}
@Mutation
private SET_AUTH_TOKEN(authToken?: Token): void {
if (authToken) {
this._authToken = authToken;
localStorageUtils.setItem("Token", authToken);
} else {
this._authToken = undefined;
localStorageUtils.removeItem("Token");
}
}
@Action({ rawError: true })
public async login(login: Login): Promise<void> {
const response = await authenticationService.login(login);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async register(userCreateOrUpdate: UserCreate): Promise<void> {
const response = await authenticationService.register(userCreateOrUpdate);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async update(id: number, userUpdate: UserUpdate, file: any): Promise<void> {
const response = await userService.updateUser(id, userUpdate, file);
this.SET_CURRENT_USER(response);
}
@Action({ rawError: true })
public async logout(): Promise<void> {
await authenticationService.logout();
this.SET_AUTH_TOKEN(undefined);
this.SET_CURRENT_USER(undefined);
}
}
export default getModule(UserModule);
index.ts
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {},
});
modulesNames.ts :
const modulesNames = {
user: "user",
};
export default modulesNames;
我是 javascript 以及打字稿和前端框架的新手。
在 Whosebug 中多次尝试解决此问题后,还阅读了文档 ,我什么也没发现,所以我决定做更多的调试,我明白了 Vuex 操作仅接受一个参数,因此另一个参数值未定义