为什么我的 vue Leave 过渡不起作用?

Why my vue Leave transition not working?

我正在使用 vee validate 进行表单验证。我正在使用 vue transition 来显示这样的验证错误:

 <input type="text" name="name" v-validate="'required'">
<transition name="slide-fade">
  <div v-show="errors.has('name')">{{ errors.first('name') }}</div>
</transition>

Css:

    .slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
  transform: translateX(10px);
  opacity: 0;
}

现在,当错误进入时,过渡正常,但当错误消失时,过渡不工作。 为什么会这样?

过渡正常。你看到它突然变成空白,因为没有 errors.first('name') 可以显示了。

当你沿着 errors.first('name') 添加一些其他字符串时,比如 Error:,它变得清晰。

Vue.use(VeeValidate);
new Vue({
  el: '#demo'
})
.slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
  transform: translateX(10px);
  opacity: 0;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js"></script>

<div id="demo">
  Type something and then erase. And then type again.
  <input type="text" name="name" v-validate="'required'">
  <transition name="slide-fade">
    <div v-show="errors.has('name')">Errors: {{ errors.first('name') }}</div>
  </transition>
</div>


如果你真的必须...

考虑额外代码的数量,但如果您真的必须这样做,则必须将 watch 添加到 input 的值和 记录第一个错误 当它发生时。

vee-validate 不提供错误的侦听器,所以这是目前最好的。请参阅下面的演示。

Vue.use(VeeValidate);
new Vue({
  el: '#demo',
  data: {
    name: "Erase me",
    nameError: ""
  },
  watch: {
    name() {
      // two ticks at least, because vee-validate takes one tick to validate
      Vue.nextTick().then(Vue.nextTick()).then(() => {
        if (this.errors.has('name')) { this.nameError = this.errors.first('name'); }
      });
    }
  }
})
.slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
  transform: translateX(10px);
  opacity: 0;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js"></script>

<div id="demo">
  Erase and error will appear. Type again and error will leave.<br>
  <input type="text" name="name" v-validate="'required'" v-model="name">
  <transition name="slide-fade">
    <div v-show="errors.has('name')">Errors: {{ nameError }}</div>
  </transition>
</div>

这是一个有点老的话题,但我想出了一个更简单的解决方案,它只需要最少的代码,适用于仍在寻找解决方案的每个人。

它的作用是在每次按下输入键(@keypress 事件)时检查错误消息,将其保存到一个变量中,该变量与实际错误消息一起显示在div,使用 OR,确保 error.message 变量永远不会得到 undefined。 OR 保证会显示某些内容,即使实际错误(由 VeeValidate 给出的错误)不可用,直到动画完成。

Vue.use(VeeValidate);
new Vue({
  el: '#demo',

  data() {
    return {
      error: {
        name: null,
      },
    }
  },

  methods: {
    updateError() {
      const message = this.errors.first('name');

      if (message) { // check if message isn't undefined
        this.error.name = message;
      }
    },
  },
});
.slide-fade-enter-active {
  transition: all .3s ease;
}

.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}

.slide-fade-enter,
.slide-fade-leave-to {
  transform: translateX(10px);
  opacity: 0;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js"></script>

<div id="demo">
  Type something and then erase. And then type again.
  <input type="text" name="name" v-validate="'required'" @keypress="updateError()"><!-- added keypress event -->
  <transition name="slide-fade">
    <div v-show="errors.has('name')">Errors: {{ errors.first('name') || error.name }}</div><!-- OR -->
  </transition>
</div>

如果您有多个输入,您可以这样做:在 updateError() 函数中传递 '$event' 变量(变为 updateError($event)),并在声明中接受它。然后,使用 srcElement 获取启动该按键事件的源元素(在我们的例子中是输入),并获取它的 name/class/id/whatever;取决于此,您可以修改其各自的变量(在我们的例子中为 error.nameerror.email)。剩下的就直说了。

Vue.use(VeeValidate);
new Vue({
  el: '#demo',

  data() {
    return {
      error: {
        name: null,
        email: null,
      },
    }
  },

  methods: {
    updateError(e) {
      const input = e.srcElement.name;
      const message = this.errors.first(input);

      if (message) { // check if message isn't undefined
        if (input === 'name') {
          this.error.name = message;
        } else if (input === 'email') {
          this.error.email = message;
        }
      }
    },
  },
});
.row {
  display: flex;
  flex-wrap: wrap;
}

.col {
  flex: 0 0 45%;
  max-width: 45%;
}

.slide-fade-enter-active {
  transition: all .3s ease;
}

.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}

.slide-fade-enter,
.slide-fade-leave-to {
  transform: translateX(10px);
  opacity: 0;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js"></script>

<div id="demo" class="row">
  <div class="col">
    Type a name and then erase. And then type again.
    <input type="text" name="name" v-validate="'required'" @keypress="updateError($event)">
    <!-- added keypress event -->
    <transition name="slide-fade">
      <div v-show="errors.has('name')">Errors: {{ errors.first('name') || error.name }}</div>
      <!-- OR -->
    </transition>
  </div>

  <div class="col" style="border-left: 2px solid black; padding-left: 10px">
    Type an email and then erase. And then type again.
    <input type="text" name="email" v-validate="'required'" @keypress="updateError($event)">
    <!-- added keypress event -->
    <transition name="slide-fade">
      <div v-show="errors.has('email')">Errors: {{ errors.first('email') || error.email }}</div>
      <!-- OR -->
    </transition>
  </div>
</div>

希望对您有所帮助!