首页 > 解决方案 > 如何在 Vue.js 中实现类似 Svelte 的延迟转换?

问题描述

我基本上在寻找像 Sveltein:receiveout:receive.

您可以在 Svelte 教程中看到它的作用:https ://svelte.dev/tutorial/deferred-transitions 。它完美地将待办事项从一个列表移动到另一个列表。

Vue.js 中有类似的东西吗?

我浏览了这个页面:https ://vuejs.org/v2/guide/transitions.html ,但没有找到任何东西。

标签: javascriptvue.jssveltesvelte-3

解决方案


似乎 Vue 没有对所谓的延迟转换技术的内置支持。但是您可以利用 <transition-group> 来获得与交叉淡入淡出相同的效果。

这是vue的实现。我使用 setTimeout 和 FLIP 技术来实现交叉淡入淡出效果。

这里的基本逻辑是我们记录发送部分和接收部分的位置,并使用 setTimeout 来延迟转换(如果我们不这样做,我们就不能使用FLIP 技术)。

访问代码笔链接查看最终效果

<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> -->
<template>
  <div id="flip-list-demo" class="demo">
  <button @click="shuffle">shuffle</button>
  <input type="text" @keyup.enter="add" />
  <div style="display: flex; flex-direction: row">
    <transition-group
      @before-enter="beforeEnter"
      @enter="enter"
      @leave="leave"
      name="list"
      tag="div"
    >
      <li
        class="list-item"
        v-for="(item, index) in validList"
        v-bind:key="item.value"
        :ref="item.value"
        @click="goInvalid"
        :data-item="item.value"
      >
        {{ item.value }}
      </li>
    </transition-group>
    <transition-group
      name="list"
      @before-enter="beforeEnter"
      @enter="enter"
      @leave="leave"
      tag="div"
    >
      <li
        :ref="item.value"
        class="list-item"
        v-for="(item, index) in invalidList"
        :key="item.value"
        @click="goValid"
        :data-item="item.value"
      >
        {{ item.value }}
      </li>
    </transition-group>
  </div>
</div>
</template>

<script>
  const items = (function () {
  const val = [];
  for (let i = 0; i < 10; i++) {
    val.push({
      value: i,
      valid: true
    });
  }
  return val;
})();
const sendRectMap = new Map();
const receiveRectMap = new Map();

export default {
  data: {
    items
  },
  computed: {
    invalidList: function () {
      return this.items.filter((i) => !i.valid);
  },
  validList: function () {
    return this.items.filter((i) => i.valid);
  }
},
methods: {
  beforeEnter(el) {
     el.style.opacity = 0;

    setTimeout(() => {
      const item = el.dataset.item;
      const to = receiveRectMap.get(item);
      const from = sendRectMap.get(item);

      const dx = from.left - to.left;
      const dy = from.top - to.top;
      const dw = from.width / to.width;
      const dh = from.height / to.height;
      const d = Math.sqrt(dx * dx + dy * dy);

      el.style.transition = "all 0ms";
      el.style.transform = `translate(${dx}px, ${dy}px)`;
    }, 0);
  },
  enter(el, done) {
    console.log("enter");
    console.log(el);
    console.log(el.getBoundingClientRect());

    const to = el.getBoundingClientRect();
    const item = el.dataset.item;

    // get receiving part position in 'enter' and put it into receiveRectMap(that is 
    how Sevlet does in cross-fade)
    receiveRectMap.set(item, to);

    setTimeout(() => {
      el.style.transition = "all 300ms";
      el.style.transform = "";
      el.style.opacity = 1;
      el.style.display = "block";
    }, 20);

    done();
  },

  leave(el, done) {
    console.log("before leave");
    const rect = el.getBoundingClientRect();
    console.log(rect);

    // get sending part position in 'leave' function and put it into 
    receiveRectMap(that is how Sevlet does in cross-fade)
    sendRectMap.set(el.dataset.item, rect);

    el.style.display = "none";

  },

  goInvalid(e) {
    const el = e.target;
    const item = el.dataset.item;
    const index = this.items.findIndex((i) => i.value.toString() === item);
    this.$set(
      this.items,
      index,
      Object.assign({}, this.items[index], { valid: false })
    );
  },
  goValid(e) {
    const el = e.target;
    const item = el.dataset.item;
    const index = this.items.findIndex((i) => i.value.toString() === item);
    this.$set(
      this.items,
      index,
      Object.assign({}, this.items[index], { valid: true })
    );
  },
  shuffle: function () {
    this.items = _.shuffle(this.items);
  },
  add(e) {
    const value = e.target.value;
    this.items.push({ value, valid: true });
    this.items = Object.assign([], this.items);
  }
 }
};
</script>

<!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> -->
<style>


.list-item {
  transition: all 500ms;
  border: 1px solid #111111;
  height: 50px;
  width: 100px;
  margin: 10px 10px;
}

.list-leave-active {
  position: absolute;
}
</style>

代码笔链接


推荐阅读