【问题标题】:How to read size and move hidden element before Vue transition starts on it?如何在 Vue 转换开始之前读取大小并移动隐藏元素?
【发布时间】:2017-07-26 06:36:09
【问题描述】:

如何在 Vue 过渡开始之前读取尺寸并移动隐藏的 div?例如,用户单击一个按钮,我想移动一个隐藏的 div 以显示在按钮下方并带有淡入过渡。在过渡开始之前,我需要能够读取尺寸并移动隐藏 div 的顶部/左侧位置。

假设我在 div 上使用 v-show="active",其中 active 是我想要设置为 true 并能够在转换开始之前移动 div 的反应数据属性。

这些我都试过了:

  • 先移动 div,然后在 nextTick 上设置 active = true。
  • 使用 javascript 挂钩 beforeEnter 尝试在转换开始之前移动 div。
  • 使用 javascript 钩子 enter(和“完成”回调)尝试在转换开始之前移动 div。
  • 在设置 active = true 之前,尝试使用新位置立即更新 DOM。 (换句话说,不是通过数据绑定,而是直接设置元素样式属性,如this.$refs.content.style.top = '500px' 以避免在虚拟 DOM 上的任何等待。)但是,理想情况下,我希望在不直接接触 DOM 的情况下完成此操作,而是使用 nextTicks 代替.两种方法都失败了。
  • 尝试使用 hacky transition: all .8ms ease-in, top 1ms, left 1ms 取得了一些成功。
  • 尝试先移动 div,然后在 setTimeout 中设置为活动状态。不过,这不是正确的解决方案。

更新
感谢接受的答案,我能够看到我可以在 nextTick 上读取尺寸(此时 v-show 已打开显示)。然而,事实证明我需要将过渡全部设为transition all .3s,这将导致包含移动。 DOM 将收集所有更改并将它们一起应用,这意味着它们被集中到稍后由 Vue 添加的转换中。最终的解决方案是我需要做出动作,然后先触发 DOM 重新绘制,然后触发 v-show 打开。这是一个示例方法:

startTransition () {
  this.$refs.content.offsetHeight // <-- Force DOM to repaint first.
  this.isContentActive = true     // <-- Turns on v-show.
},

【问题讨论】:

    标签: javascript vue.js css-transitions vuejs2


    【解决方案1】:

    使用v-bind:style 移动您的窗口,一切都会按预期进行。

    更新:要检查弹出窗口本身的大小,必须显示它,所以我使用v-show 而不是v-if。我做的第一件事就是让它可见;在下一个刻度上,我可以测量它并放置它。

    new Vue({
      el: '.container',
      data: {
        top: 0,
        left: 0,
        width: 0,
        show: false
      },
      methods: {
        showFloater: function(evt) {
          const t = evt.target;
    
          this.show = true;
          Vue.nextTick(() => {
            const fEl = this.$el.querySelector('.floating');
    
            this.top = t.offsetTop + 30;
            this.left = t.offsetLeft;
            this.width = fEl.offsetWidth;
            setTimeout(() => this.show = false, 1000);
          });
        }
      }
    });
    .container {
      position: relative;
    }
    
    .floating {
      border: thin solid black;
      padding: 3em;
      position: absolute;
    }
    
    .fade-enter-active, .fade-leave-active {
      transition: opacity .5s
    }
    .fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
      opacity: 0
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>
    <div class="container">
      <button @click="showFloater">Could go here</button>
      <button @click="showFloater">Or here</button>
      <transition name="fade">
        <div v-show="show" class="floating" v-bind:style="{
          top: top + 'px',
          left: left + 'px'
        }">
          This window is {{width}}px wide.
        </div>
      </transition>
    </div>

    【讨论】:

    • 我在这里注意到的一件事是你没有像我在问题中提到的那样阅读 div 大小(如高度)。但是,今天下午晚些时候,当我到达我的电脑时,我仍然会尝试您的答案。如果它有效,则在转换前尝试读取 div 大小时可能会发生中断。您可以为此更新您的代码并尝试一下吗?
    • @prograhammer 我应该阅读多大的 div?我正在获取按钮的 offsetTop 来选择弹出窗口的位置。由于v-if,弹出窗口本身在点击时不是 DOM 的一部分,因此它没有大小。
    • 没错。您需要暂时取消隐藏弹出窗口以获取大小,这很可能是转换故障的根源。想象一下,您需要通过读取其高度或宽度(实际用例)来确定该弹出窗口是否离开屏幕,以便您可以将其翻转到另一个方向。例如,只需 console.log 高度。但我敢肯定你的过渡现在会中断。
    • 不起作用。过渡开始,您会看到 div 缓慢移动到新位置并同时淡入。今晚我会做一个密码笔给你看。您是否自己尝试过发布的代码?感谢您的帮助!
    • 感谢您的帮助 Roy,您的回答解决了我的问题并帮助我解决了我需要的最后一点。查看我更新的问题(以帮助其他遇到此问题的人)。
    猜你喜欢
    • 2021-04-05
    • 2022-11-03
    • 1970-01-01
    • 2016-04-23
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 2021-04-27
    • 2020-10-12
    相关资源
    最近更新 更多