首页 > 解决方案 > 子组件值绑定到同一个 vue 组件的另一个实例的属性

问题描述

我对自定义组件有疑问。这是问题所在:

密码显示问题

这个屏幕实际上是同一个 Vue 组件的 3 倍:

<div class="passwords__form">
            <InputField class="passwords__field" label="Mot de passe actuel" :password="true" v-model="currentPassword" />
            <InputField class="passwords__field" label="Nouveau mot de passe" :password="true" v-model="newPassword" />
            <InputField class="passwords__field" label="Répéter le nouveau mot de passe" :password="true" v-model="repeatedPassword" />
            <Button title="Changer le mot de passe" @click="updatePassword"/>
</div>

这是组件代码:

<template>
  <div
    class="field__container"
    :class="{ 'field__container--disabled': disabled }"
  >
    <label
      :for="this._uid"
      class="field__label"
      :class="{ 'field__label--disabled': disabled }"
      v-if="labelEnabled"
      >{{ label }}</label
    >
    <input
      :id="this._uid"
      class="field__input"
      :class="{
        'left-rounded': !labelEnabled && !password,
        'right-rounded': !buttonEnabled && !password
      }"
      :value="value"
      :placeholder="placeholder"
      @input="$emit('input', $event.target.value)"
      @keyup.enter="$emit('keyup-enter')"
      :disabled="disabled"
      :type="fieldType"
    />
    <input
      v-if="password && enableShowPassword"
      type="checkbox"
      v-model="showPassword"
      id="password-checkbox"
      class="field__password-checkbox"
    /><label
      v-if="password && enableShowPassword"
      for="password-checkbox"
      class="field__password-checkbox-label"
      :class="{
        'right-rounded': !buttonEnabled,
      }"
    ><span v-if="enableShowPassword && showPassword"><EyeSlash class="field__password-checkbox-icon"/></span><span v-if="!showPassword" ><Eye class="field__password-checkbox-icon field__password-checkbox-icon--eye " /></span></label>
    <a
      v-if="buttonEnabled"
      class="field__button"
      @click.stop="$emit('button-click')"
    >
      {{ button }}
    </a>
  </div>
</template>

<script lang="ts">
import Component from "vue-class-component";
import Vue from "vue";
import { Prop } from "vue-property-decorator";
import Eye from "../assets/images/icons/eye-regular.svg"
import EyeSlash from "../assets/images/icons/eye-slash-regular.svg"

@Component({
  components: {
    Eye,
    EyeSlash
  }
})
export default class InputField extends Vue {
  @Prop({ default: "", required: false })
  label!: string;

  @Prop({ required: true })
  value!: string;

  @Prop({ default: "", required: false })
  placeholder!: string;

  @Prop({ default: "", required: false })
  button!: string;

  @Prop({ default: false, required: false })
  disabled!: boolean;

  @Prop({ default: false, required: false })
  password!: boolean;

  @Prop({ default: true, required: false })
  enableShowPassword!: boolean;

  showPassword = false;

  get fieldType(): string {
    if (this.password && !this.showPassword) {
      return "password";
    }
    return "text";
  }

  get labelEnabled(): boolean {
    return this.label !== "";
  }

  get buttonEnabled(): boolean {
    return this.button !== "";
  }
}
</script>

<style lang="scss">
.field {
  &__container {
    display: flex;
    flex-direction: row;
    border: 1px solid $color-grey-7;
    font-size: 1.6rem;
    transition: all 0.3s;

    &:hover:not(&--disabled),
    &:focus:not(&--disabled) {
      border: 1px solid $color-complementary;

      & > .field__label {
        background: $color-complementary;
      }
    }

    &--disabled {
      cursor: not-allowed;
    }
  }
  &__label {
    text-align: center;
    padding: 0.5rem 2rem;
    border-right: 1px solid $color-grey-8;
    background-color: $color-grey-8;
    transition: all 0.3s;

    &--disabled {
      cursor: not-allowed;
    }
  }
  &__input {
    flex-grow: 2;
    border: none;

    color: $color-grey-1;
    transition: all 0.3s;
    padding: 0 1rem;

    &:hover,
    &:focus {
      outline: none;
    }

    &--disabled {
      cursor: not-allowed;
    }
  }

  &__button {
    text-align: center;
    padding: 0.5rem 2rem;
    border-left: 1px solid $color-grey-7;
    transition: all 0.3s;

    &:hover,
    &:active {
      background: $color-grey-7;
    }
  }

  &__password-checkbox {
    display: none;
  }

  &__password-checkbox-label {
    background-color: $color-grey-9;
    padding: 0.6rem 1rem;
    cursor: pointer;

    &:hover,
    &:active {
      background-color: $color-complementary-lighter;
    }
  }

  &__password-checkbox-icon {
    width: 1.5rem;

    &--eye {
      position: relative;
      top: 1px;
    }
  }
}
</style>

我认为问题来自v-model复选框上的属性。据我所知,v-model 绑定到showPasswordInputField 的第一个实例的属性,而不是绑定到 InputField 的当前实例。

我不确定它为什么会这样,我的错误是什么,以及如何纠正它/以正确的方式去做。有人有线索吗?

标签: vue.jsdata-bindingcomponentsmultiple-instances

解决方案


我想你应该对输入 type="password"使用一个唯一的id:id="this._uid" ,就像你对通常的输入所做的那样,因为在 HTML 页面上,所有id在元素中声明的 ' 都必须是唯一的。


推荐阅读