-
position: sticky (by css)
-> スクロールして画面上部で固定。弟要素が上にかぶさる -
Intersection Observer (by js)
-> 画面表示領域内への出入りでアニメーション用のクラス追加・削除 -
opacity (by css)
-> Intersection Observerに伴うクラスによって表示/非表示アニメーション
の3点を組み合わせると、
上へのスクロールはできるけど、下へのスクロールができなくなる。
(上へのスクロールは通常だけど、下へスクロールは弟要素が画面下でバウンスして戻ってくる)
なんでだろう……。
どれか2個までの組み合わせなら動くんだけどな~。
この3つになると動かない…
↓書いたもの(一部省略)
parent.vue
<template>
<div class="l-page">
<section class="list">
<Widgets-component
v-for = "item in items"
:item = "item"
class = "item"
:key = "item.id"
:ref = "'item'"
/>
</section>
</div>
</template>
<script>
export default {
data() {
return {
items: [//**省略**//]
}
},
updated() {
let targets = [];
this.$refs.item.forEach(el => targets.push(el.$el));
const observer = new IntersectionObserver((entries) => {
let className_active = 'is-show';
entries.forEach((entry) => {
if (entry.intersectionRatio >= 0.8) {
entry.target.classList.add(className_active);
} else {
entry.target.classList.remove(className_active);
}
});
}, {
root: null,
rootMargin: '0px',
threshold: 1
});
targets.forEach((target) => {
observer.observe(target);
});
}
}
</script>
<style lang="scss" scoped>
.list {
height: 100%;
overflow-y: auto;
scroll-snap-type: y mandatory;
}
.item {
position: sticky;
top: 0;
height: 82vh;
scroll-snap-align: start;
scroll-snap-stop: always;
}
.disc-item::v-deep {
.item-body, .item-footer {
opacity: 0;
transition: opacity 600ms ease;
}
&.is-show {
.item-body, .item-footer{
opacity: 1;
}
}
}
</style>
child.vue
<template>
<div>
<div class="item-thumb">
<img :src="item.images.url" />
</div>
<div class="item-body">
some body element
</div>
<div class="item-footer">
some footer element
</div>
</div>
</template>
<script>
export default {
props: {
item: { type: Object }
}
}
</script>
ちなみにopacityじゃなくて、backgroundだと普通に動くんだよな~。
なんか別の理由かな~。
parent.vue
<style lang="scss" scoped>
.disc-item::v-deep {
.item-body, .item-footer {
background: red;
}
&.is-show {
.item-body, .item-footer{
background: blue;
}
}
}
</style>