Vue.js自定义按钮禁用功能与样式失效 无法读取父组件表单字段求助
问题根因
- Vue组件默认作用域隔离,子组件无法直接读取父组件的data属性,你在CustomBtn中直接调用
this.email、this.signup属于非法调用,自然拿不到对应值。 - 父组件的
data选项中没有提前声明email、password、name等表单字段,直接在方法中赋值不会生成响应式属性,就算子组件能读到也无法触发视图更新。 - 自定义按钮属于通用组件,耦合具体表单的校验逻辑会导致组件完全无法复用,本身设计就不合理。
修复方案
第一步:修改父表单组件
先补全响应式字段,新增计算属性判断表单是否合法:
<template> <section> <div class="form"> <transition name="test" mode="out-in"> <form key="login" v-if="login" @submit.prevent="login"> <h1>Connexion</h1> <custom-input icon="fa-at" name="email" type="email" placeholder="email@gmail.com" @updated="updatedEmail" /> <custom-input icon="fa-lock" name="password" type="password" placeholder="Mot de passe" @updated="updatedPassword" /> <!-- 绑定disabled属性 --> <custom-btn :disabled="isBtnDisabled">Connexion</custom-btn> <p @click="login = !login">Déjà un compte ?</p> </form> <form action="" key="signup" v-else novalidate @submit.prevent="createAccount" > <h1>Inscription</h1> <custom-input icon="fa-at" name="email" type="email" placeholder="email@gmail.com" @updated="updatedEmail" /> <custom-input icon="fa-lock" name="password" type="password" placeholder="Mot de passe" @updated="updatedPassword" /> <custom-input icon="fa-lock" name="RepeatPassword" type="password" placeholder="Répéter votre mot de passe" @updated="updatedRepeatPassword" /> <custom-input icon="fa-user" name="name" type="text" placeholder="John" @updated="updatedName" /> <custom-file @change="onFileChanges"/> <!-- 绑定disabled属性 --> <custom-btn :disabled="isBtnDisabled">Inscription</custom-btn> <p @click="login = !login">Pas de compte?</p> </form> </transition> </div> </section> </template> <script> import CustomInput from "./Input.vue"; import CustomBtn from "./Button.vue"; import CustomFile from "./FileInput.vue"; export default { components: { CustomInput, CustomBtn, CustomFile, }, data() { return { login: true, file: null, // 提前声明所有表单字段,保证响应式 email: '', password: '', repeatPassword: '', name: '' }; }, computed: { // 新增计算属性判断按钮是否需要禁用 isBtnDisabled() { if (this.login) { // 登录场景校验:邮箱、密码不为空 return !(this.email && this.password) } else { // 注册场景校验:所有必填项不为空 return !(this.email && this.password && this.repeatPassword && this.name && this.file) } } }, methods: { onFileChanges(event) { let files = event.target.files || event.dataTransfer.files; if (!files.length) return; this.file = files[0]; }, updatedEmail(email) { this.email = email; }, updatedPassword(password) { this.password = password; }, // 拆分重复密码的更新方法 updatedRepeatPassword(password) { this.repeatPassword = password; }, updatedName(name) { this.name = name; }, }, }; </script> <style lang="scss" scoped> @import "../scss/main.scss"; section { padding: 2rem; .form { background: #ffff; box-shadow: 0px 15px 16.83px 0.17px rgb(0 0 0 / 5%); border-radius: 10px; padding: 2rem; h1 { text-align: center; font-size: 1.8rem; margin-bottom: 1rem; color: $secondary; } p { text-align: center; margin-top: 1rem; } } .test-enter-active, .test-leave-active { transition: opacity 0.5s; } .test-enter, .test-leave-active { opacity: 0; } } </style>
第二步:修改CustomBtn通用组件
删掉内部耦合的表单校验逻辑,直接用父组件传入的disabled属性控制状态即可:
<template> <button class="btn" :class="{ 'btn--disabled': disabled }" :disabled="disabled" > <slot></slot> </button> </template> <script> export default { props: { // 规范prop类型,默认不禁用 disabled: { type: Boolean, default: false } } }; </script> <style lang="scss" scoped> @import "../scss/main.scss"; .btn { width: 100%; margin: 1rem 0; background: $secondary; color: #ffff; border: none; padding: 1rem 2rem; } .btn--disabled { color: red; cursor: not-allowed; } </style>
内容的提问来源于stack exchange,提问作者Sebastien
相关产品推荐
相关产品推荐

