Хук перехода VueJS JS-only требует setTimeout для CSS-перехода для работы - PullRequest
2 голосов
/ 20 марта 2019

Я работаю с чистыми JS-хуками для элемента <transition-group> в VueJS, и я весьма озадачен тем, как на самом деле работает хук enter. Исходя из документации, я понимаю, что мне придется позвонить done(), чтобы избежать синхронного вызова событий :

При использовании переходов только для JavaScript обратные вызовы done требуются для ловушек enter и leave. В противном случае крючки будут вызываться синхронно, и переход завершится немедленно.

Однако, даже когда я его использую, кажется, что переходы CSS не происходят при входящем переходе . Единственное решение, которое я нашел, - это использование window.setTimeout для установки стиля, который, я думаю, является запахом кода. Вот быстрое визуальное сравнение между кодом без тайм-аута и кодом с (тот, у которого тайм-аут является желаемым эффектом):

Неработающий вводный переход (без перехода на левый отступ и непрозрачность):

Broken enter transition

Желаемый ввод перехода:

Desired effect

В приведенном ниже примере я отображаю список, используя <transition-group>, и хотел использовать JS-хуки, чтобы я мог создавать разнесенные отступы для отдельных элементов списка. Кажется, работает с тем исключением, что при переходе enter переходы CSS в свойстве padding не работают.

new Vue({
  el: '#app',
  data: {
    items: [
      'Lorem',
      'Ipsum',
      'Dolor',
      'Sit',
      'Amet'
    ],
    toggle: false
  },
  computed: {
    filteredItems: function() {
      if (!this.toggle)
        return [];

      return this.items;
    }
  },
  methods: {
    toggleItems: function() {
      this.toggle = !this.toggle;
    },
    beforeEnter: function(el) {
      el.style.paddingLeft = '0px';
      el.style.opacity = '0';
    },
    enter: function(el, done) {
      el.style.paddingLeft = `${10 * +el.dataset.index}px`;
      el.style.opacity = '1';
      done();
    },
    beforeLeave: function(el) {
      el.style.paddingLeft = '0px';
      el.style.opacity = '0';
    }
  }
})
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

ul li {
  transition: all 500ms ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">

  <button @click="toggleItems">
    Toggle items
  </button>
  
  <transition-group
    tag="ul"
    @before-enter="beforeEnter"
    @enter="enter"
    @before-leave="beforeLeave">
    
    <li
      v-for="(item, i) in filteredItems"
      v-bind:key="i"
      v-bind:data-index="i">
      {{ item }}
    </li>
  </transition-group>
</div>

Если вы заключите всю логику внутри метода enter в произвольный тайм-аут, тогда он сработает:

enter: function(el, done) {
  window.setTimeout(() => {
    el.style.paddingLeft = `${10 * +el.dataset.index}px`;
    el.style.opacity = '1';
    done();
  }, 100);
},

И вот тут я немного растерялся: неужели крюк enter не ждет, пока beforeEnter не завершится первым? Рабочий фрагмент выглядит следующим образом

1 Ответ

2 голосов
/ 20 марта 2019

Изменение хука @enter на @after-enter должно исправить это

Я понятия не имею, почему хук @enter не работает для этого, так как, глядя на документацию, он должен но это должно как минимум избавиться от таймаута, не будучи хаком

new Vue({
  el: '#app',
  data: {
    items: [
      'Lorem',
      'Ipsum',
      'Dolor',
      'Sit',
      'Amet'
    ],
    toggle: false
  },
  computed: {
    filteredItems: function() {
      if (!this.toggle)
        return [];

      return this.items;
    }
  },
  methods: {
    toggleItems: function() {
      this.toggle = !this.toggle;
    },
    beforeEnter: function(el) {
      el.style.paddingLeft = '0px';
      el.style.opacity = '0';
    },
    afterEnter: function(el) {
      el.style.paddingLeft = `${10 * +el.dataset.index}px`;
      el.style.opacity = '1';
    },
    beforeLeave: function(el) {
      el.style.paddingLeft = '0px';
      el.style.opacity = '0';
    }
  }
})
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

ul li {
  transition: all 500ms ease-in-out;
}

li.v-enter-active {
  transition: none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">

  <button @click="toggleItems">
    Toggle items
  </button>

  <transition-group 
    tag="ul" 
    @before-enter="beforeEnter"
    @after-enter="afterEnter" 
    @before-leave="beforeLeave">
    <li v-for="(item, i) in filteredItems" v-bind:key="i" v-bind:data-index="i">
      {{ item }}
    </li>
  </transition-group>
</div>

В качестве примечания: если вы используете SCSS или SASS, вы можете достичь этого с помощью JavaScript, а не 1017 *

...