【问题标题】:How can I achieve something like Svelte's deferred transitions in Vue.js?如何在 Vue.js 中实现类似 Svelte 的延迟转换?
【发布时间】:2021-04-08 15:05:52
【问题描述】:

我基本上是在寻找像 Svelte 的 in:receiveout:receive 这样的东西。

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

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

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

【问题讨论】:

  • Sarah Drasner 写了一篇关于这些原生类型转换的整篇文章,在这些转换中元素从一个位置平滑地移动到另一个位置。 Here you go 它使用 <transition-group> 像 Svelte 一样应用翻转,它的文档是 here
  • 那是一篇好文章。我的问题是我不知道我的 todo 会去哪里。因此,我不能像她那样使用变换。我对 Svelte 实现该动画的轻松程度印象深刻。

标签: javascript vue.js svelte svelte-3


【解决方案1】:

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

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

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

访问code pen link查看最终效果

<!-- 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>

code pen link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 2016-11-20
    • 1970-01-01
    • 2011-07-01
    • 2019-01-03
    相关资源
    最近更新 更多