[solved] When is Dom ready for scroll?
-
I have multiple children and need to scroll to a certain child after loading the page. I can do so by setting a delay using
setTimeout
but I would prefer a better/ fail-proof solution. My current approach is to wait for all children to mount (and usenextTick
) and thought it should be ready for the scroll, but apparently not. Alternatively I can wait for all images to be loaded (as QImg has a@load
event), but that is really late, since manually I can already trigger a scroll while image boxes are already rendered but still loading. What is the best way to trigger at ‘the earliest possible moment’?Point-panel (parent):
new Vue({ el: '#q-app', template: ` <div id="point-panel" class='map-overlay column scroll'> <small-cards @child-mounted='cardsAreReady' v-for='(point, cardIndex) in picArray' :key="cardIndex" :point-object="point" :card-index="cardIndex"></small-cards> <q-btn @click.native="scrollToCenter" fab ripple class='fixed' size="10px" color="black" label="scroll" style="right: 18px; bottom: 120px" /> </div> </div> `, data() { return { parentMounted: false, selectedPointIndex: 6, picArray: ["https://image1", "https://image2, "https://image_etc."] } }, mounted: function() { let that = this that.$nextTick( function(){ that.parentMounted = true }) }, methods: { notify(msg) { this.$q.notify(msg) }, cardsAreReady(cardIndex) { console.log('one ready.......', `${cardIndex + 1} ...and total ${this.picArray.length}`) let that = this if (cardIndex + 1 === this.picArray.length) { console.log('....all cards MOUNTED!', cardIndex) setTimeout(() => { that.$nextTick(() => { console.log('..........trigger scroll NOW!') if (that.parentMounted === true) { that.scrollToCenter() } else { that.$q.notify('parent not yet ready!!') } }) }, 0) } }, scrollToCenter() { const that = this console.log('..........cardIndex: ', that.selectedPointIndex) function scrollFunction() { that.notify('scroll triggered!') const element = document.getElementsByClassName( that.selectedPointIndex.toString() ) const target = document.getElementById('point-panel') const iW = window.innerWidth const iH = window.innerHeight const myOffset = element[0].offsetLeft Quasar.utils.scroll.setHorizontalScrollPosition(target, myOffset, 0) } setTimeout(() => scrollFunction(), 0) } } })
Images/ small-cards (children):
Vue.component('small-cards', { props: { pointObject: { type: Object, required: true }, cardIndex: { type: Number, required: true, default: 0 } }, data() { return { selectedPointIndex: 6 } }, mounted: function() { let that = this that.$nextTick(function () { that.$emit('child-mounted', this.cardIndex) }) }, methods: { reportError(event) { console.log(`${event.name}: ${event.message}`); }, }, template: ` <div class="mycard" :class="{'active': cardIndex === selectedPointIndex, [cardIndex]: true}"> <q-img :src="pointObject" spinner-size="30px" style="background-color: rgba(255, 225, 215, 0.4)" @error="reportError"> </q-img> </div> ` })
Here you can find a jsfiddle showing the issue. I have added a scroll button to show that after loading you can trigger a scroll successfully (the 6th picture, i.e. ‘the Tiger’ is scrolled to the bottom-left corner).
To give the question somewhat more direction: The problem is that if
scroll
is triggered to soon the Dom is not yet rendered and thus the distance to scrol can not yet be determined. But I would think that aftermount
in combination with$nextTick
the Dom should be determined?! So why does current approach not work? -
After using
@load
for the scroll-element and adding anextTick
it seems to work as should. See this stackoverflow-issue .