Add a "Back to Top" button for long-scrolling pages

This commit is contained in:
An Phan 2016-04-04 21:01:55 +08:00
parent 35b8c86b06
commit 1751600824
7 changed files with 97 additions and 1 deletions

View file

@ -12,6 +12,8 @@
| limitBy numOfItems" :album="item"></album-item>
<span class="item filler" v-for="n in 6"></span>
<to-top-button :showing="showBackToTop"></to-top-button>
</div>
</section>
</template>

View file

@ -11,6 +11,8 @@
| limitBy numOfItems" :artist="item"></artist-item>
<span class="item filler" v-for="n in 6"></span>
<to-top-button :showing="showBackToTop"></to-top-button>
</div>
</section>
</template>

View file

@ -4,7 +4,7 @@
<span>{{ greeting }}</span>
</h1>
<div class="main-scroll-wrap">
<div class="main-scroll-wrap" v-el:wrapper @scroll="scrolling">
<div class="top-sections">
<section v-show="topSongs.length">
<h1>Most Played Songs</h1>
@ -76,6 +76,8 @@
<span class="item filler" v-for="n in 3"></span>
</div>
</section>
<to-top-button :showing="showBackToTop"></to-top-button>
</div>
</section>
</template>
@ -90,12 +92,18 @@
import userStore from '../../../stores/user';
import queueStore from '../../../stores/queue';
import preferenceStore from '../../../stores/preference';
import infiniteScroll from '../../../mixins/infinite-scroll';
import albumItem from '../../shared/album-item.vue';
import artistItem from '../../shared/artist-item.vue';
export default {
components: { albumItem, artistItem },
/**
* We're not really using infinite scrolling here, but only the handy "Back to Top" button.
* @type {Array}
*/
mixins: [infiniteScroll],
data () {
return {

View file

@ -173,5 +173,14 @@
}
}
}
@media only screen and (max-width: 375px) {
> section {
// Leave some space for the "Back to top" button
.main-scroll-wrap {
padding-bottom: 64px;
}
}
}
}
</style>

View file

@ -59,6 +59,7 @@
</table>
<song-menu v-ref:context-menu :songs="selectedSongs"></song-menu>
<to-top-button :showing="showBackToTop"></to-top-button>
</div>
</template>

View file

@ -0,0 +1,58 @@
<template>
<div class="to-top-btn-wrapper" v-show="showing" transition="fade">
<button @click="$parent.scrollToTop()">
<i class="fa fa-arrow-circle-up"></i>
Top
</button>
</div>
</template>
<script>
export default {
props: ['showing'],
};
</script>
<style lang="sass">
@import "../../../sass/partials/_vars.scss";
@import "../../../sass/partials/_mixins.scss";
.to-top-btn-wrapper {
position: fixed;
width: 100%;
bottom: $footerHeight + 16px;
left: 0;
text-align: center;
z-index: 9999;
&.fade-transition {
opacity: 1;
transition: opacity .5s;
}
&.fade-enter {
opacity: 0;
}
&.fade-leave {
opacity: 0;
}
button {
border-radius: 18px;
padding: 8px 16px;
background: rgba(0, 0, 0, .5);
border: 1px solid $colorMainText;
i {
margin-right: 4px;
}
}
}
@media screen and (min-width: 376px) {
.to-top-btn-wrapper {
display: none;
}
}
</style>

View file

@ -1,5 +1,7 @@
import $ from 'jquery';
import toTopButton from '../components/shared/to-top-button.vue';
/**
* Add a "infinite scroll" functionality to any component using this mixin.
* Such a component should:
@ -8,10 +10,13 @@ import $ from 'jquery';
* - have the array of all objects named as `items`, either as data, computed, or a prop
*/
export default {
components: { toTopButton },
data() {
return {
numOfItems: 30, // Number of currently loaded and displayed items
perPage: 30, // Number of items to be loaded per "page"
showBackToTop: false,
};
},
@ -24,6 +29,8 @@ export default {
if ($wrapper.scrollTop() + $wrapper.innerHeight() >= $wrapper[0].scrollHeight - 32) {
this.displayMore();
}
this.showBackToTop = $wrapper.scrollTop() > 64;
},
/**
@ -32,11 +39,20 @@ export default {
displayMore() {
this.numOfItems += this.perPage;
},
/**
* Scroll to top fo the wrapper.
*/
scrollToTop() {
$(this.$els.wrapper).animate({ scrollTop: 0}, 500);
this.showBackToTop = false;
}
},
events: {
'koel:teardown': function () {
this.numOfItems = 30;
this.showBackToTop = false;
},
},
};