【问题标题】:Vue transition slide down for each item每个项目的Vue过渡向下滑动
【发布时间】:2021-07-30 23:20:59
【问题描述】:

我正在学习过渡如何与 vue 一起使用。我有一个价格估算,当点击每个选项卡时,它会显示每件商品的估算价格。我希望当项目出现时,有一个向下滑动的效果。我试图找出方法,并通过Enter / Leave & List Transitions 找到了方法。而且我也尝试过,但是效果还是不行。谁能帮我解决这个问题?

我在 Codesandbox 中的完整代码 => https://codesandbox.io/s/suspicious-almeida-rjyy9

PriceEstimation.vue

<template>
  <div class="card">
    <div class="card-header">Price Estimation</div>
    <div class="card-body px-0 pt-0">
      <transition name="slide">
        <div class="estimation-category" v-if="cart.total || isDropped">
          <div v-if="cart.storage && cart.storage.totalCost">
            <div class="bg-secondary d-flex justify-content-between p-2">
              <h5 class="text-white m-0">Storage</h5>
              <div>
                <span class="fas fa-pen text-success mr-2" @click="setTab('storage-calculator')"></span>
                <span class="fas fa-trash-alt text-danger" @click="deleteStorage()"></span>
              </div>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Server Name</span>
                <span class="ml-2">{{ cart.storage.serverName }}</span>
              </div>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Specification</span>
                <span class="ml-2">{{ cart.storage.specification.name }}</span>
              </div>
              <span>${{ cart.storage.specification.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Components</span>
              </div>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">vCPU</span>
                <span class="ml-2">{{ cart.storage.cpu.qty }} GHz</span>
              </div>
              <span>${{ cart.storage.cpu.value * cart.storage.cpu.qty }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">vRAM</span>
                <span class="ml-2">{{ cart.storage.ram.qty }} Gb</span>
              </div>
              <span>${{ cart.storage.ram.value * cart.storage.ram.qty }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Capacity</span>
                <span class="ml-2">{{ cart.storage.capacity.qty }}</span>
              </div>
              <span>${{ cart.storage.capacity.value * cart.storage.capacity.qty }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Server Qty</span>
                <span class="ml-2">{{ cart.storage.server.qty }}</span>
              </div>
              <span>${{ cart.storage.server.value * cart.storage.server.qty }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Storage Type</span>
                <span class="ml-2">{{ cart.storage.storageType.name }}</span>
              </div>
              <span>${{ cart.storage.storageType.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">OS</span>
                <span class="ml-2">{{ cart.storage.os.name }}</span>
              </div>
              <span>${{ cart.storage.os.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Database</span>
                <span class="ml-2">{{ cart.storage.database.name }}</span>
              </div>
              <span>${{ cart.storage.database.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Firewall</span>
                <span class="ml-2">{{ cart.storage.firewall.name }}</span>
              </div>
              <span>${{ cart.storage.firewall.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Estimate Cost</span>
              </div>
              <span>${{ cart.storage.totalCost }}</span>
            </div>
          </div>
          <div v-if="cart.service && cart.service.totalCost">
            <div class="bg-secondary d-flex justify-content-between p-2">
              <h5 class="text-white m-0">Service</h5>
              <div>
                <span class="fas fa-pen text-success mr-2" @click="setTab('service-calculator')"></span>
                <span class="fas fa-trash-alt text-danger" @click="deleteService"></span>
              </div>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Sub-service</span>
                <span class="ml-2">{{ cart.service.service.name }}</span>
              </div>
              <span>${{ cart.service.service.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Package-type</span>
                <span class="ml-2">{{ cart.service.package.name }}</span>
              </div>
              <span >${{ cart.service.package.value }}</span>
            </div>
            <div class="d-flex justify-content-between px-2">
              <div>
                <span class="font-weight-bold">Estimate Cost</span>
              </div>
              <span>${{ cart.service.totalCost }}</span>
            </div>
          </div>
          <div v-if="cart.deploy && cart.deploy.totalCost">
            <div class="estimation-category__title">
              <h5 class="m-0 font-size-18 txt-secondary">Cloud Safe</h5>
              <div>
                  <a href="" @click.prevent="setTab('deploy-cloud')"><span class="fas fa-pen text-success font-size-15 mr-2"></span></a>
                  <a href="" @click.prevent="deleteDeploy()"><span class="fas fa-trash-alt text-danger font-size-15"></span></a>
              </div>
            </div>
            <div class="estimation-category__item">
              <div class="font-size-14 txt-primary">
                <span class="txt-bold">CPU: </span>
                <span class="">{{ cart.deploy.cpuDeploy.name }}</span>
              </div>
              <span class="font-size-14 txt-secondary">${{ cart.deploy.cpuDeploy.value }}</span>
            </div>
            <div class="estimation-category__item">
              <div class="font-size-14 txt-primary">
                <span class="txt-bold">RAM: </span>
                <span class="">{{ cart.deploy.ramDeploy.name }}</span>
              </div>
              <span class="font-size-14 txt-secondary">${{ cart.deploy.ramDeploy.value }}</span>
            </div>
            <div class="estimation-category__item">
              <div class="font-size-14 txt-primary">
                <span class="txt-bold">Persistant Volume: </span>
                <span class="">{{ cart.deploy.persistant.name }}</span>
              </div>
              <span class="font-size-14 txt-secondary">${{ cart.deploy.persistant.value }}</span>
            </div>
            <div class="estimation-category__item">
              <div class="font-size-14 txt-primary">
                <span class="txt-bold">Storage Type: </span>
                <span class="">{{ cart.deploy.workerQty.name }}</span>
              </div>
              <span class="font-size-14 txt-secondary">${{ cart.deploy.workerQty.value }}</span>
            </div>
            <div class="estimation-category__item">
                <div class="border-cost">
                  <div class="txt-primary">
                      <span class="txt-bold font-size-16">Estimate Cost</span>
                  </div>
                  <span class="font-size-16 txt-secondary">${{ cart.deploy.totalCost }}</span>
              </div>
            </div>
          </div>
          <table class="table table-borderless">
            <tbody>
              <tr>
                <td>
                  <p>TOTAL</p>
                </td>
                <td class="text-right">
                  <p>${{ cart.total }}</p>
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </transition>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    setTab: {type: Function},
  },
  data: () => ({
    isDropped: false
  }),
  computed: {
    cart () {
      this.isDropped = !this.isDropped;
      return this.$store.getters.getCart;
    }
  },
  methods: {
    deleteStorage() {
      this.$store.commit('deleteStorage');
    },
    deleteService() {
      this.$store.commit('deleteService');
    },
    deleteDeploy() {
      this.$store.commit('deleteDeploy');
    }
  },
};
</script>

CSS

.slide-enter, .slide-leave-to{
  transform: scaleY(0);
}
.estimation-category{
  transform-origin: top;
  transition: transform .4s ease-in-out;
  overflow: hidden;
}

【问题讨论】:

  • 也许你在 if 条件和你的计算中错了
  • 应该怎么样? @欺诈

标签: javascript vue.js vuejs3 vue-transitions


【解决方案1】:

在 Vue 3 中,为了保持一致性,过渡类名称略有更改。阅读docs here

简而言之,两种转换类型(leaveenter)现在都从 {name}-{type}-from 开始,在 {name}-{type}-to 结束,并且在转换处于活动状态时应用了 {name}-{type}-active

这意味着您必须将.slide-enter 替换为.slide-enter-fromslide-enter 不再应用于 Vue 3)。例如:

.slide-enter-from,
.slide-leave-to {
  transform: scaleY(0);
}
.estimation-category {
  transform-origin: top;
  transition: transform .4s ease-in-out;
}

working here

修复了一个过渡。
如果您想为每个购物车项目单独转换,您可能希望使用 &lt;transition-group&gt; 而不是 &lt;transition&gt; 并在 cartItems 数组上运行 v-for,但动画几乎相同.
这是一个最小的例子:

const Cart = {
  data: () => ({
    items: []
  }),
  methods: {
    addItem() {
      const lastItemId = this.items.length
        ? this.items[this.items.length - 1].id 
        : -1;
      this.items.push({id: lastItemId + 1, name: `item-${lastItemId + 1}`})
    },
    removeItem(item) {
      this.items = this.items.filter(el => el.id !== item.id)
    }
  }
}

Vue.createApp(Cart).mount('#cart')
.cart-item-wrapper {
  max-height: 53px;
  transition: max-height .35s cubic-bezier(.4,0,.2,1), margin-bottom .35s cubic-bezier(.4,0,.2,1);
  margin-bottom: .5rem;
  background-color: #fff;
  box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%), 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%);
  overflow: hidden;
}
.slide-enter-from,
.slide-leave-to {
  max-height: 0;
  margin-bottom: 0;
}
.cart-item {
  padding: 1rem;
  display: flex;
  justify-content: space-between;
}
.cart-item button {
  margin-left: 1rem;
}
#cart {
  max-width: 360px;
}
button {
  cursor: pointer;
}
body {
  background-color: #f5f5f5;
}
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
<div id="cart">
  <transition-group name="slide">
    <div class="cart-item-wrapper"
         :key="item.id"
         v-for="(item, key) in items">
      <div class="cart-item">
        {{ item.name }}
        <button @click="removeItem(item)">X</button>
      </div>
    </div>
  </transition-group>
  <button @click="addItem">Add Item</button>
</div>

在上面的&lt;transition-group&gt; 示例中,我使用了与您不同的过渡,但这无关紧要。类名是重要的部分,并且项目由id 作为键,因此离开转换被正确映射(例如,如果我们使用它们在数组中的索引作为键,离开转换总是发生在最后一个元素)。

【讨论】:

  • 我喜欢第二个过渡,使用transition-group。但是它必须使用v-for吗?如果我仍然使用我的代码盒中的静态数据,我可以使用它吗?
  • 你可以使用任何你想要的过渡。如果你想使用v-for,你必须使用&lt;transition-group&gt;。当您只处理一项时,您使用&lt;transition&gt;。在这两者中,重要的一点是在 CSS 中将 .slide-enter 更改为 .slide-enter-from。其余的都是细节。
【解决方案2】:

我认为它不起作用,因为您使用了错误的 css 类。为您要使用的过渡命名,例如:

    <transition name="fade">
      <p v-if="show">hello</p>
    </transition>

fade 是此处过渡的名称,因此您可以像这样在 css 中使用它:

.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

【讨论】:

  • 不,我不想要淡入淡出效果。我已经在上面的帖子中解释过,我想要一个slide down 效果。我想问一下我的过渡标签的位置是正确的还是仍然是错误的?
【解决方案3】:

我相信您使用的是 Vue 2。您可以在文档中找到动态 CSS 类。我建议在过渡元素之外使用过渡控制器。另外,请确保transition 块内的内容完全为空,在您的情况下,仍然存在一些默认内容。 我在我的项目中使用了这个 CSS,它根据你的转换名称 slide 调整对我有用。

.slide-enter-active {
  @include transition-ease(all, .7s);
}

.slide-leave-active {
  @include transition-ease(all, .5s);
}

.slide-enter-to,
.slide-leave {
  max-height: 490px;
  overflow: hidden;
}

.slide-enter,
.slide-leave-to {
  overflow: hidden;
  max-height: 0;
}

【讨论】:

    【解决方案4】:

    Vue 转换包装器仅影响其直接子级。所以你应该根据这个来组织你的代码。 我创建了一个新的 show 属性和一个按钮来设置它以快速显示它是如何工作的: https://codesandbox.io/s/romantic-dirac-npi9s?file=/src/components/price-calculator/PriceEstimation.vue

    在这种情况下,.estimation-category 是动画的,但在原始示例中,您正在根据您的逻辑显示其子项。

    【讨论】:

      【解决方案5】:
      <transition-group name="slide">
            <li>        
                  item.name
            </li>
                  item2.name
            <li>
      </transition-group>
      

      您也可以在此处对 li 元素使用 v-for。

      这是样式:

      <style lang="scss" scoped>
      .slide-item {
        transition: all 1s;
      }
      .slide-enter {
        opacity: 0;
        transform: translateY(10px);
      }
      .slide-leave-to {
        opacity: 0;
        transform: translateY(-10px);
      }
      .slide-leave-active {
        position: absolute;
      }
      </style>
      

      【讨论】:

        猜你喜欢
        • 2020-11-03
        • 2021-01-18
        • 1970-01-01
        • 2020-12-25
        • 1970-01-01
        • 2019-04-07
        • 1970-01-01
        • 2022-10-24
        • 1970-01-01
        相关资源
        最近更新 更多