JSFiddle - React, Tailwind, and code Playground

by darkylmnx

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.js"></script>
<div id="app">
  <nav>
    <ul>
      <li>
        <router-link to="/">
          home
        </router-link>
      </li>
      <li v-for="one in list">
        <router-link :to="{name: 'anime', params: {id: one.mal_id}}">
          Item {{ one.mal_id }}
        </router-link>
      </li>
    </ul>
  </nav>
  
 <keep-alive max="3">
   <router-view :key="$route.fullPath"></router-view> 
 </keep-alive>
 
 <div class="loader" v-show="shared.isLoading">
   loading
 </div>
</div>


<template id="home" style="display:none">
	<div>
  	<h1>I'm home</h1>
  </div>
</template>

<template id="anime" style="display:none">
	<div>
  	<h1>I'm an anime page</h1>
    
    <div v-if="item">
      <h2>title: {{ item.title }}</h2>
    </div>
  </div>
</template>

CSS

body,
html,
h1,
h2,
ul,
li,
nav {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
  display: flex;
}

ul li {
  height: 100%;
}

ul a {
  height: 100%;
  color: #fff;
  display: block;
  text-decoration: none;
  font-size: 12px;
  background: #000;
  padding: 2px;
  margin-right: 2px;;
}

.loader {
  position: fixed;
  z-index: 9999;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.9);
  color: #fff;
  font-size: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

Vue

const APIlist = 'https://api.jikan.moe/v3/search/anime?q=?q=shingeki'
const APIItem = 'https://api.jikan.moe/v3/anime/'

const shared = {
	isLoading: false
}

const ComponentAnime = {
	template: '#anime',
  data() {
  	return {
    	cached: false,
    	shared,
    	item: null
    }
  },
  methods: {
  	callAPI() {
    	this.shared.isLoading = true

      fetch(APIItem + this.$route.params.id)
        .then(resp => resp.json())
        .then(json => (this.item = json))
        .then(() => (this.shared.isLoading = false))
        .catch(() => (this.shared.isLoading = false))
    }
  },
  created() {
  	console.log('created')
  	this.callAPI()
  },
  activated() {
  	console.log('activated')

    if (this.cached === false) {
    	this.cached = Date.now()
    } else {
    	// time diff since cache, in seconds
    	const diff = (Date.now() - this.cached) / 1000
      
      // if cache is older than 30 seconds, invalidate
      if (diff > 10) {
      	this.cached = false
      	this.callAPI()
      }
    }
  }
}

const router = new VueRouter({
	routes: [
  	{
    	name: 'home',
      path: '/',
      component: {
      	template: '#home'
      }
    },
    {
    	name: 'anime',
      path: '/anime/:id',
      component: ComponentAnime
    }
  ]
})

const app = new Vue({
	el: '#app',
  router,
  data: {
  	shared,
  	list: []
  },
  created() {
  	this.shared.isLoading = true
  
  	fetch(APIlist)
    	.then(resp => resp.json())
      .then(json => {
      	this.list = json.results.splice(0, 5)
      })
      .then(() => (this.shared.isLoading = false))
      .catch(() => (this.shared.isLoading = false))
  }
})