Search code examples
vue.jsvuejs3vue-routersingle-page-applicationrouter

Use vuejs 3 without router


I created a vuejs3 single page application "WITHOUT" router and routing and also without "url" change ( want to always showing home in address bar) But need help to do it in a correct way.

I want to

  1. have a main html page on page have links, buttons or so, that at run time page is filed (how???)
  2. on start page be filled with the first home page
  3. on click of each link or buttons the selected component to be replace in the page

index.html page:

 <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite + Vue</title>
      </head>
      <body>
        <div id="app"></div>
        <script type="module" src="/src/main.js"></script>
      </body>
    </html>
main.js
import { createApp } from 'vue'
    import App    from './App.vue'
    import store  from './store'
    import './style.css'
    const app = createApp(App)
    app.use(store)
    app.mount('#app')

app.vue file

 <template>
        <div>
            <h1>Hello world</h1>
            <button type="button" @click="changeView(0)"> Home 1 </button>
            <button type="button" @click="changeView(1)"> Home 2 </button>
            <button type="button" @click="changeView(2)"> Home 3 </button>
        </div>
        <Suspense v-if="isLoggedIn">
            <template #default>
                <changeViews />
            </template>
            <template #fallback>
                <p>loading...</p>
            </template> 
        </Suspense>
        <changeViews v-if="showIt" />
    </template>
    <script setup>
        import { defineAsyncComponent, ref, markRaw } from 'vue'
        const menus = [
            {
                name: "home"
                ,url: "home"
            },
            {
                name: "about"
                ,url: "about"
            },
            {
                name: "contact"
                ,url: "contact"
            },
        ]
        let showIt = ref(false)
        let changeViews = ref(null)
        changeViews.value = markRaw(defineAsyncComponent((loc) => 
            import(`./components/${menus[0].url}/index.vue`)
        ))
        function changeView(ja){
            showIt.value = false
            if(ja===1) {
                showIt.value = true
                changeViews.value = defineAsyncComponent((loc) => 
                    import(`./components/${menus[ja].url}/index.vue`)
                )
            }
        }
    </script>

Pages (home, about, contact) are very simple:

<template>
        <h2> Home </h2>
        <div class="card">
            <button type="button" @click="count++">count is {{ count }}</button>
            <button type="button" @click="count++">count is {{ count }}</button>
            <button type="button" @click="count++">count is {{ count }}</button>
        </div>
    </template>
    <script lang="ts" setup>
        import { ref } from 'vue'
        const count = ref(0)
    </script>

It is working, but it seems messy and I have no idea how to do it in a good way.

I have searched but every where they talk about how to use routing, while I want to avoid routing and no url-change


Solution

  • I think you need to use dynamic components. You can dynamically specify which component to render at a single place.

    <template>
      <component :is="currentPage" />
    </template>
    
    <script setup>
    import PageA from '@/components/PageA.vue'
    import PageB from '@/components/PageB.vue'
    import PageC from '@/components/PageC.vue'
    
    const currentPage = ref('PageA')
    
    function changeView(page) {
      currentPage.value = page
    }
    </script>