Commit 0f936915 authored by Evan You's avatar Evan You

loading indicator

parent eb6450f8
<template>
<svg class="spinner" :class="{ show: show }" width="44px" height="44px" viewBox="0 0 44 44">
<circle class="path" fill="none" stroke-width="4" stroke-linecap="round" cx="22" cy="22" r="20"></circle>
</svg>
</template>
<script>
export default {
props: ['show']
}
</script>
<style>
.spinner {
opacity: 0;
transition: opacity .3s ease;
animation: rotator 1.4s linear infinite;
animation-play-state: paused;
}
.spinner.show {
opacity: 1;
animation-play-state: running;
}
@keyframes rotator {
0% { transform: scale(0.5) rotate(0deg); }
100% { transform: scale(0.5) rotate(270deg); }
}
.spinner .path {
stroke: #4fc08d;
stroke-dasharray: 126;
stroke-dashoffset: 0;
transform-origin: center;
animation: dash 1.4s ease-in-out infinite;
}
@keyframes dash {
0% { stroke-dashoffset: 126; }
50% {
stroke-dashoffset: 32;
transform:rotate(135deg);
}
100% {
stroke-dashoffset: 126;
transform:rotate(450deg);
}
}
</style>
......@@ -9,7 +9,7 @@ import About from '../views/About.vue'
export default new Router({
mode: 'history',
routes: [
{ path: '/news/:page', component: News },
{ path: '/news/:page(\\d+)', component: News },
{ path: '/about', component: About },
{ path: '*', redirect: '/news/1' }
]
......
......@@ -8,7 +8,7 @@ const inBrowser = typeof window !== 'undefined'
// if in browser, use pre-fetched state injected by SSR
const state = (inBrowser && window.__INITIAL_STATE__) || {
storiesPerPage: 30,
storiesPerPage: 20,
topStoryIds: [],
items: {}
}
......
<template>
<div>
<h2>News</h2>
<h2>News <spinner :show="loading"></spinner></h2>
<ul>
<li>
<router-link v-if="page > 1" :to="'/news/' + (page - 1)">prev</router-link>
......@@ -12,7 +12,7 @@
</li>
</ul>
<transition :name="transition">
<div class="news-list" :key="$route.params.page">
<div class="news-list" v-if="!loading" :key="$route.params.page">
<transition-group tag="ul" name="item">
<news-item v-for="item in news" :key="item.id" :item="item">
</news-item>
......@@ -23,6 +23,7 @@
</template>
<script>
import Spinner from '../components/Spinner.vue'
import NewsItem from '../components/NewsItem.vue'
const fetchData = store => {
......@@ -35,6 +36,7 @@ export default {
name: 'news',
prefetch: fetchData,
components: {
Spinner,
NewsItem
},
data () {
......@@ -49,20 +51,27 @@ export default {
page () {
return Number(this.$route.params.page)
},
hasMore () {
maxPage () {
const { storiesPerPage, topStoryIds } = this.$store.state
return this.page < Math.ceil(topStoryIds.length / storiesPerPage)
return Math.floor(topStoryIds.length / storiesPerPage)
},
hasMore () {
return this.page < this.maxPage
},
loading () {
return this.news.length < this.$store.state.storiesPerPage
}
},
created () {
if (typeof window !== 'undefined') {
mounted () {
fetchData(this.$store)
if (this.page > this.maxPage) {
this.$router.push('/')
}
},
watch: {
'$route' (to, from) {
this.$store.dispatch(`FETCH_NEWS`)
this.transition = to.params.page > from.params.page
this.transition = Number(to.params.page) > Number(from.params.page)
? 'slide-left'
: 'slide-right'
}
......@@ -77,12 +86,10 @@ export default {
}
.slide-left-enter, .slide-right-leave-active {
opacity: 0;
-webkit-transform: translate(30px, 0);
transform: translate(30px, 0);
}
.slide-left-leave-active, .slide-right-enter {
opacity: 0;
-webkit-transform: translate(-30px, 0);
transform: translate(-30px, 0);
}
.item-move, .item-enter-active, .item-leave-active {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment