JSFiddle - React, Tailwind, and code Playground

by skirtle

HTML

<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.global.js"></script>
<div id="app">
  <router-link to="/">Home</router-link> - 
  <router-link to="/other">About</router-link>
  <div class="main" :class="{ loading }">
    <router-view v-slot="{ Component }">
      <template v-if="Component">
        <transition mode="out-in">
          <keep-alive>
            <suspense
              @pending="loading = true"
              @resolve="loading = false"
            >
              <component :is="Component"></component>
              <template #fallback>
                <div>
                  Loading...
                </div>
              </template>
            </suspense>
          </keep-alive>
        </transition>
      </template>
    </router-view>
  </div>
</div>

CSS

#app, .main {
  padding: 20px;
  margin: 20px;
  border: 1px solid red;
}

.v-enter-from, .v-leave-to {
  opacity: 0;
}

.v-enter-active, .v-leave-active {
  transition: opacity 500ms;
}

.loading {
  position: relative;
}

.loading::after {
  background: #ccc;
  bottom: 0;
  content: '';
  left: 0;
  opacity: 0.5;
  position: absolute;
  right: 0;
  top: 0;
}

JavaScript

const resolveComponent = name => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({
        template: `<div>${name} - created {{ time }} seconds ago</div>`,
        data () {
          return {
            time: 0
          }
        },
        created () {
          setInterval(() => {
            this.time++
          }, 1000)
        }
      })
    }, 2000)
  })
}

const app = Vue.createApp({
  data () {
    return {
      loading: false
    }
  }
})

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes: [
    {
      path: '/',
      // component: () => resolveComponent('Home'),
      component: {
        render: () => Vue.h(Vue.resolveComponent('Home')),
        components: {
          Home: Vue.defineAsyncComponent(() => resolveComponent('Home'))
        }
      }
    }, {
      path: '/other',
      // component: () => resolveComponent('About'),
      component: {
        render: () => Vue.h(Vue.resolveComponent('About')),
        components: {
          About: Vue.defineAsyncComponent(() => resolveComponent('About'))
        }
      }
    }
  ]
})

app.use(router)

app.mount('#app')