Vuetify v-dialog 在使用后多次挂载,不在循环内
Vuetify v-dialog is mounted multiple times after use and is not within a loop
我有两个对话框;登录注册。该对话框使用 :value="dialog"
而不是 v-model:dialog
因为它 dialog
是计算数据。 dialog
取自 vuex 模块(弹出窗口)。对话框是在没有激活器的情况下完成的(由 Vuetify 提供)。
如果在 PopupSignIn
组件中单击“注册”按钮,它将自行关闭并通过调用 togglePopupAccountSignInSignUp
打开 PopupSignUp
,反之亦然。 对话框可以很好地切换 但是 ONCE 我填写一个表格来登录或注册并执行操作。它让我登录,Vue 给出了一个错误(第一个)。然后在注销并再次打开“登录”对话框时出现另一个(第二个)错误。
错误
第一个错误
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in nextTick: "TypeError: Cannot read property 'focus' of undefined"
found in
---> <VDialog>
<PopupSignIn> at src/components/popup/SignIn.vue
<VApp>
<App> at src/App.vue
<Root>
第二个错误
Uncaught RangeError: Maximum call stack size exceeded.
我做了什么
- 将 :retain-focus="false" 添加到两个对话框。它消除了错误但是
对话框仍然多次安装
- 将
v-if="!this.user"
替换为 v-show="!this.user"
;仍然安装多次
- 在关闭对话框之前使用 setTimeout,然后使用 router.push
- 每次用户注销时重新加载页面。虽然这 工作 ,但我需要经常刷新
每次使用对话框
location.reload();
return false;
App.vue
<!-- There is no loop going on within the header tag -->
<header>
...
<PopupSignIn v-if="!this.user" />
<PopupSignUp v-if="!this.user" />
...
</header>
popup.js
export const namespaced = true;
export const state = {
account: {
signIn: false,
signUp: false
}
};
export const mutations = {
SET_POPUP_ACCOUNT_SIGN_IN(state, bool) {
state.account.signIn = bool;
},
SET_POPUP_ACCOUNT_SIGN_UP(state, bool) {
state.account.signUp = bool;
}
};
export const actions = {
updatePopupAccountSignIn({ commit }, bool) {
commit("SET_POPUP_ACCOUNT_SIGN_IN", bool);
},
updatePopupAccountSignUp({ commit }, bool) {
commit("SET_POPUP_ACCOUNT_SIGN_UP", bool);
},
togglePopupAccountSignInSignUp({ commit, state }) {
commit("SET_POPUP_ACCOUNT_SIGN_IN", !state.account.signIn);
commit("SET_POPUP_ACCOUNT_SIGN_UP", !state.account.signIn);
}
};
SignIn.vue(弹出登录)
<template>
<div>
<v-btn @click.stop="updatePopupAccountSignIn(true)">
<v-icon>
mdi-account
</v-icon>
Sign In
</v-btn>
<v-dialog
:value="dialog"
:retain-focus="false"
@click:outside="updatePopupAccountSignIn(false)"
>
<v-card>
<v-card-title>
<div>Sign In</div>
</v-card-title>
<v-card-text>
<v-form
ref="form"
v-model="valid"
lazy-validation
@submit.prevent="login"
>
<!-- Rest of the form -->
<v-btn
type="submit"
:loading="loading"
:disabled="loading"
>Sign In</v-btn
>
</v-form>
<div>
<p>Don't have an account?</p>
<v-btn
@click.stop="togglePopupAccountSignInSignUp"
>Sign Up</v-btn
>
</div>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
computed: {
...mapState("popup", {
dialog: state => state.account.signIn
})
},
methods: {
...mapActions("account", ["signIn"]),
...mapActions("popup", [
"updatePopupAccountSignIn",
"updatePopupAccountSignUp",
"togglePopupAccountSignInSignUp"
]),
async login() {
try {
this.loading = true;
await this.signIn({
email: this.email,
password: this.password.value
});
...
setTimeout(() => {
this.updatePopupAccountSignIn(false);
this.updatePopupAccountSignUp(false);
this.$router.push("/your/profile");
}, 2000);
} catch (error) {
...
}
}
}
};
</script>
SignUp组件流程与SignIn组件流程大致相同,唯一不同的是它用于注册。
我不确定是什么导致对话框被多次安装。非常感谢任何解决此问题的帮助。
我尝试了一种不同的方法来使用 Vue .sync
修饰符并删除 vuex 方法来获得预期结果。更多内容可阅读 Jithil Jishad's blog.
App.vue
<template>
<header>
...
<PopupSignIn
v-if="!user"
:dialog.sync="dialog.signIn"
:dialogSignUp.sync="dialog.signUp"
/>
<PopupSignUp
v-if="!user"
:dialog.sync="dialog.signUp"
:dialogSignIn.sync="dialog.signIn"
/>
...
</header>
</template>
<script>
export default {
...
data() {
return {
dialog: {
signIn: false,
signUp: false
}
};
},
...
};
</script>
SignIn.vue
<template>
<v-dialog
v-model="dialog"
@click:outside.stop="$emit('update:dialog', false)"
>
<v-card>
<v-card-text>
<!-- FORM -->
<p>Don't have an account?</p>
<v-btn @click.stop="toggleDialog">Sign Up</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
export default {
props: {
dialog: Boolean,
dialogSignUp: Boolean
},
beforeDestroy() {
this.$emit("update:dialog", false);
},
methods: {
toggleDialog() {
this.$emit("update:dialog", false);
this.$emit("update:dialogSignUp", true);
}
}
};
</script>
我有两个对话框;登录注册。该对话框使用 :value="dialog"
而不是 v-model:dialog
因为它 dialog
是计算数据。 dialog
取自 vuex 模块(弹出窗口)。对话框是在没有激活器的情况下完成的(由 Vuetify 提供)。
如果在 PopupSignIn
组件中单击“注册”按钮,它将自行关闭并通过调用 togglePopupAccountSignInSignUp
打开 PopupSignUp
,反之亦然。 对话框可以很好地切换 但是 ONCE 我填写一个表格来登录或注册并执行操作。它让我登录,Vue 给出了一个错误(第一个)。然后在注销并再次打开“登录”对话框时出现另一个(第二个)错误。
错误
第一个错误
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in nextTick: "TypeError: Cannot read property 'focus' of undefined"
found in
---> <VDialog>
<PopupSignIn> at src/components/popup/SignIn.vue
<VApp>
<App> at src/App.vue
<Root>
第二个错误
Uncaught RangeError: Maximum call stack size exceeded.
我做了什么
- 将 :retain-focus="false" 添加到两个对话框。它消除了错误但是 对话框仍然多次安装
- 将
v-if="!this.user"
替换为v-show="!this.user"
;仍然安装多次 - 在关闭对话框之前使用 setTimeout,然后使用 router.push
- 每次用户注销时重新加载页面。虽然这 工作 ,但我需要经常刷新 每次使用对话框
location.reload();
return false;
App.vue
<!-- There is no loop going on within the header tag -->
<header>
...
<PopupSignIn v-if="!this.user" />
<PopupSignUp v-if="!this.user" />
...
</header>
popup.js
export const namespaced = true;
export const state = {
account: {
signIn: false,
signUp: false
}
};
export const mutations = {
SET_POPUP_ACCOUNT_SIGN_IN(state, bool) {
state.account.signIn = bool;
},
SET_POPUP_ACCOUNT_SIGN_UP(state, bool) {
state.account.signUp = bool;
}
};
export const actions = {
updatePopupAccountSignIn({ commit }, bool) {
commit("SET_POPUP_ACCOUNT_SIGN_IN", bool);
},
updatePopupAccountSignUp({ commit }, bool) {
commit("SET_POPUP_ACCOUNT_SIGN_UP", bool);
},
togglePopupAccountSignInSignUp({ commit, state }) {
commit("SET_POPUP_ACCOUNT_SIGN_IN", !state.account.signIn);
commit("SET_POPUP_ACCOUNT_SIGN_UP", !state.account.signIn);
}
};
SignIn.vue(弹出登录)
<template>
<div>
<v-btn @click.stop="updatePopupAccountSignIn(true)">
<v-icon>
mdi-account
</v-icon>
Sign In
</v-btn>
<v-dialog
:value="dialog"
:retain-focus="false"
@click:outside="updatePopupAccountSignIn(false)"
>
<v-card>
<v-card-title>
<div>Sign In</div>
</v-card-title>
<v-card-text>
<v-form
ref="form"
v-model="valid"
lazy-validation
@submit.prevent="login"
>
<!-- Rest of the form -->
<v-btn
type="submit"
:loading="loading"
:disabled="loading"
>Sign In</v-btn
>
</v-form>
<div>
<p>Don't have an account?</p>
<v-btn
@click.stop="togglePopupAccountSignInSignUp"
>Sign Up</v-btn
>
</div>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
computed: {
...mapState("popup", {
dialog: state => state.account.signIn
})
},
methods: {
...mapActions("account", ["signIn"]),
...mapActions("popup", [
"updatePopupAccountSignIn",
"updatePopupAccountSignUp",
"togglePopupAccountSignInSignUp"
]),
async login() {
try {
this.loading = true;
await this.signIn({
email: this.email,
password: this.password.value
});
...
setTimeout(() => {
this.updatePopupAccountSignIn(false);
this.updatePopupAccountSignUp(false);
this.$router.push("/your/profile");
}, 2000);
} catch (error) {
...
}
}
}
};
</script>
SignUp组件流程与SignIn组件流程大致相同,唯一不同的是它用于注册。
我不确定是什么导致对话框被多次安装。非常感谢任何解决此问题的帮助。
我尝试了一种不同的方法来使用 Vue .sync
修饰符并删除 vuex 方法来获得预期结果。更多内容可阅读 Jithil Jishad's blog.
App.vue
<template>
<header>
...
<PopupSignIn
v-if="!user"
:dialog.sync="dialog.signIn"
:dialogSignUp.sync="dialog.signUp"
/>
<PopupSignUp
v-if="!user"
:dialog.sync="dialog.signUp"
:dialogSignIn.sync="dialog.signIn"
/>
...
</header>
</template>
<script>
export default {
...
data() {
return {
dialog: {
signIn: false,
signUp: false
}
};
},
...
};
</script>
SignIn.vue
<template>
<v-dialog
v-model="dialog"
@click:outside.stop="$emit('update:dialog', false)"
>
<v-card>
<v-card-text>
<!-- FORM -->
<p>Don't have an account?</p>
<v-btn @click.stop="toggleDialog">Sign Up</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
export default {
props: {
dialog: Boolean,
dialogSignUp: Boolean
},
beforeDestroy() {
this.$emit("update:dialog", false);
},
methods: {
toggleDialog() {
this.$emit("update:dialog", false);
this.$emit("update:dialogSignUp", true);
}
}
};
</script>