使用Quasar框架,我有多个孩子,并且在加载页面后需要滚动到某个孩子。我可以通过使用setTimeout
设置延迟来做到这一点,但我希望有一个更好的/防故障的解决方案。我当前的方法是等待所有孩子挂载(并使用nextTick
),并认为应该为滚动做好准备,但显然不是。另外,我可以等待所有图像加载(因为QImg具有@load
event),但这确实很晚,因为手动操作我可以在图像框已经渲染但仍在加载时触发滚动。在“最早的可能时刻”触发的最佳方法是什么?
点面板(父):
new Vue({
el: '#q-app',
template: `
<div id="point-panel" class='map-overlay column scroll'>
<small-cards @hook:mounted="cardsAreReady(cardIndex, picArray.length)"
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: function() {
return {
selectedPointIndex: 6,
picArray: ["https://image1", "https://image2, "https://image_etc."]
}
},
methods: {
notify(msg) {
this.$q.notify(msg)
},
cardsAreReady(cardIndex, total) {
console.log('one ready.......', `${cardIndex} ...and total ${total}`)
let that = this
if (cardIndex + 1 === total) {
console.log('....all cards MOUNTED!', cardIndex)
setTimeout(() => {
that.$nextTick(() => {
console.log('..........trigger scroll NOW!')
that.scrollToCenter()
})
}, 0)
}
},
scrollToCenter() {
const that = this
console.log('..........cardIndex: ', that.selectedPointIndex)
that.notify('scroll triggered!')
function scrollFunction() {
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)
}
}
})
图片/小卡片(儿童):
Vue.component('small-cards', {
props: {
pointObject: {
type: Object,
required: true
},
cardIndex: {
type: Number,
required: true,
default: 0
}
},
data: function() {
return {
selectedPointIndex: 6
}
},
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>
`
})
在这里您可以找到显示问题的jsfiddle。我添加了一个滚动按钮,显示加载后可以成功触发滚动(第6张图片,即“老虎”被滚动到左下角)。
编辑:为问题提供更多指导:问题是,如果scroll
很快被触发,则尚未渲染Dom,因此无法确定滚动距离。但是我认为
mount
应该确定Dom吗?那么为什么当前的方法行不通?
答案 0 :(得分:1)
编辑/新答案:
我终于能够使它正常工作...这是我必须解决的问题:
$nextTick
可以使这一点更加一致! OP也可以在没有包装器组件的情况下正常工作small-cards
组件现在emits
在图像加载完成后发生了一个事件small-cards
的{{1}}组件创建了一个“包装器” small-cards-wrapper
:1)props
,图像源数组2)items
,您想滚动到{{1}的索引号} scrollToIndex
组件将接收发出的事件(来自mount
组件),并检查它是否是您要滚动到的索引-如果是,我们滚动对此。我确定您可以在查看代码后看到我所做的更改,但是如果您有任何疑问,请告诉我!
[NEWEST JSFiddle (with $nextTick
)]
原始答案:
我在small-cards-wrapper
期间触发了small-cards
方法,并从模板中删除了scrollToCenter()
逻辑。
我已注释了代码中所做的上述更改,以便您可以准确地看到我所做的事情。
如果您不希望滚动在安装后2秒钟内发生,您可以删除mount
-这样做是为了显示它在加载后如何滚动(让您有时间看到它的发生)。 >
这是您要寻找的吗?
hook.mounted
setTimeout
Vue.component('small-cards', {
props: {
pointObject: {
type: Object,
required: true
},
cardIndex: {
type: Number,
required: true,
default: 0
},
},
data: function() {
return {
selectedPointIndex: 6
}
},
methods: {
reportError(event) {
console.log(`${event.name}: ${event.message}`);
},
handleLoad() {
this.$emit('loaded-card', true);
}
},
template: `
<div class="mycard" :class="{[cardIndex]: true}">
<q-img :src="pointObject"
@load="handleLoad"
spinner-size="30px"
style="background-color: rgba(255, 225, 215, 0.4)"
@error="reportError">
</q-img>
</div>
`
});
Vue.component('small-cards-wrapper', {
props: {
items: {
type: Array,
required: true,
},
scrollToIndex: {
type: Number,
required: false
}
},
methods: {
isLoaded(x) {
if (Number(x) === Number(this.scrollToIndex)) {
this.$nextTick(() => {
const element = document.getElementsByClassName(x.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)
this.$q.notify("Scroll Triggered!");
})
}
}
},
template: `
<div id="point-panel" class='map-overlay column scroll'>
<small-cards
v-for='(point, cardIndex) in items'
:key="cardIndex"
:point-object="point"
:card-index="cardIndex"
@loaded-card="isLoaded(cardIndex)"
></small-cards>
</div>
`
})
new Vue({
el: '#q-app',
data: function() {
return {
selectedPointIndex: 6,
picArray: ["https://images.takeshape.io/86ce9525-f5f2-4e97-81ba-54e8ce933da7/dev/144069dc-7390-4022-aa0f-abba022d3a2f/spec.jpg?auto=compress%2Cformat", "https://natureconservancy-h.assetsadobe.com/is/image/content/dam/tnc/nature/en/photos/prescribed_burn_oregon.jpg?crop=0,120,5760,3600&wid=1640&hei=1025&scl=3.5121951219512195", "https://orig11.deviantart.net/1062/f/2015/315/9/6/abstract__7_by_thejsyve1-d9gciwk.jpg", "https://natureconservancy-h.assetsadobe.com/is/image/content/dam/tnc/nature/en/photos/Brown_County_Hills_Leonetti.jpg?crop=33,0,1192,656&wid=4000&hei=2200&scl=0.29818181818181816", "https://www.telegraph.co.uk/content/dam/Travel/galleries/travel/destinations/northamerica/usa/US%20national%20parks/AP84847745_Yosemite_General-xlarge.jpg", "https://dehayf5mhw1h7.cloudfront.net/wp-content/uploads/sites/183/2016/09/15173325/Brown_County_Indiana_Estados_Unidos_2012-10-14_DD_10.jpg", "https://s-media-cache-ak0.pinimg.com/originals/19/e9/58/19e9581dbdc756a2dbbb38ae39a3419c.jpg", "https://cdn.pixabay.com/photo/2015/12/01/20/28/green-1072828_960_720.jpg", "https://www.alwareness.org/wp-content/uploads/2018/10/Bomen-Bos.jpg", "https://www.campz.be/info/wp-content/uploads/header-pic-mountain.jpeg", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSUzRyiSPfzeIogLgkY1P8ugrvzls23SMhOcJi7vmUfCe4r1nKa", "https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg", "https://farm6.staticflickr.com/5720/22076039308_4e2fc21c5f_o.jpg"]
}
},
template: `
<div>
<h4>Scroll now occurs on 'mount'</h4>
<small-cards-wrapper
:items="picArray"
:scroll-to-index="selectedPointIndex"
></small-cards-wrapper>
</div>
`,
})