如何在 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 转换开始之前读取大小并移动隐藏元素?的主要内容,如果未能解决你的问题,请参考以下文章
当我将屏幕大小调整为移动设备时,我的网站移动视图在桌面上正确显示隐藏元素,但在我的手机上它们没有隐藏