如何在 Vue 转换开始之前读取大小并移动隐藏元素?

Posted

技术标签:

【中文标题】如何在 Vue 转换开始之前读取大小并移动隐藏元素?【英文标题】:How to read size and move hidden element before Vue transition starts on it? 【发布时间】: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.
,

【问题讨论】:

【参考方案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 widthpx wide.
    </div>
  </transition>
</div>

【讨论】:

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

以上是关于如何在 Vue 转换开始之前读取大小并移动隐藏元素?的主要内容,如果未能解决你的问题,请参考以下文章

当我将屏幕大小调整为移动设备时,我的网站移动视图在桌面上正确显示隐藏元素,但在我的手机上它们没有隐藏

大小端模式

过渡和变换之前的 CSS 位置元素

jQuery 如何获取到隐藏元素的高度?或者在dom元素可见性改变时能触发个事件也行。

v-show 在我挂载 Vue 之前不会隐藏元素

如何持久化 ExtJS 数据网格列隐藏/显示/移动/调整大小?