691 VueRouter4:URL的hash,H5的History,路由使用步驟,router-link,路由懶加載,動態路由,pathMatch,嵌套路由,編程式導航,query參數,router-link、router-view的v-slot,動態添加、刪除路由,導航守衛,historyApiFallback


認識前端路由


后端路由階段


前后端分離階段


URL的hash


hash-demo.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <div id="app">
    <a href="#/home">home</a>
    <a href="#/about">about</a>

    <div class="content">Default</div>
  </div>

  <script>
    const contentEl = document.querySelector('.content');

    // 【hashchange是window的方法,不是document的,寫document.addEventListener不能監聽hash的變化。】
    window.addEventListener("hashchange", () => {
      switch (location.hash) {
        case "#/home":
          contentEl.innerHTML = "Home";
          break;
        case "#/about":
          contentEl.innerHTML = "About";
          break;
        default:
          contentEl.innerHTML = "Default";
      }
    })
  </script>

</body>
</html>

HTML5的History



history-demo.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <a href="/home">home</a>
    <a href="/about">about</a>

    <div class="content">Default</div>
  </div>

  <script>
    const contentEl = document.querySelector('.content');

    const changeContent = () => {
      switch (location.pathname) {
        case "/home":
          contentEl.innerHTML = "Home";
          break;
        case "/about":
          contentEl.innerHTML = "About";
          break;
        default:
          contentEl.innerHTML = "Default";
      }
    }

    const aEls = document.getElementsByTagName("a");

    for (let aEl of aEls) {
      aEl.addEventListener("click", e => {
        e.preventDefault();

        const href = aEl.getAttribute("href");
        // 【pushState是history的方法,不是window的。】
        // history.pushState({}, "", href);
        history.replaceState({}, "", href);

        changeContent();
      })
    }

    window.addEventListener("popstate", changeContent)
  </script>
</body>
</html>

認識vue-router


路由的使用步驟


路由的基本使用流程


路由的默認路徑


history模式



路由懶加載


打包效果分析


路由的其他屬性


動態路由基本匹配


獲取動態路由的值


匹配多個參數


NotFound


匹配規則加*


路由的嵌套


路由的嵌套配置


代碼的頁面跳轉


query方式的參數


替換當前的位置


頁面的前進后退


router-link的v-slot


router-view的v-slot


動態添加路由


動態刪除路由


路由導航守衛


登錄守衛功能


其他導航守衛

https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html



main.js

import { createApp } from 'vue'
import router from './router'
import App from './App.vue'

const app = createApp(App)

app.use(router)
app.mount('#app')

// createApp(App).use(router).mount("#app") // 也可以這樣寫

router/index.js

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

// import Home from "../pages/Home.vue";
// import About from "../pages/About.vue";

// 配置映射關系
const routes = [
  { 
    path: "/", 
    redirect: "/home" 
  },
  // /home/shops
  { 
    path: "/home", 
    name: "home",
    component: () => import(/* webpackChunkName: "home-chunk" */"../pages/Home.vue"),
    meta: {
      name: "why",
      age: 18,
      height: 1.88
    },
    children: [
      {
        path: "",
        redirect: "/home/message" // redirect要拿完整的路徑做重定向
      },
      {
        path: "message",
        component: () => import("../pages/HomeMessage.vue")
      },
      {
        path: "shops",
        component: () => import("../pages/HomeShops.vue")
      }
    ]
  },
  { 
    path: "/about",
    name: "about",
    component: () => import("../pages/About.vue") 
  },
  { 
    path: "/user/:username/id/:id",
    component: () => import("../pages/User.vue") 
  },
  {
    path: "/login",
    component: () => import("../pages/Login.vue")
  },
  {
    path: "/:pathMatch(.*)", // 任意匹配,固定寫法
    component: () => import("../pages/NotFound.vue")
  }
];

// 創建一個路由對象router
const router = createRouter({
  routes,
  history: createWebHistory()
})

// 動態添加路由
const categoryRoute = {
  path: "/category",
  component: () => import("../pages/Category.vue")
}

// 添加頂級路由對象
router.addRoute(categoryRoute);

// 添加二級路由對象【即home/moment。】 【參數1:組件的name屬性值。】
router.addRoute("home", {
  path: "moment",
  component: () => import("../pages/HomeMoment.vue")
})

// 導航守衛beforeEach
let counter = 0;
// to: Route對象, 即將跳轉到的Route對象
// from: Route對象, 
/**
 * 返回值問題:
 *    1.false: 不進行導航
 *    2.undefined或者不寫返回值: 進行默認導航 【該去哪,就去哪,相當於這里啥也沒做。】
 *    3.字符串: 路徑, 跳轉到對應的路徑中
 *    4.對象: 類似於 router.push({path: "/login", query: ....})
 */
router.beforeEach((to, from) => {
  console.log('to---', to)
  console.log('from---', from)
  console.log(`進行了${++counter}路由跳轉`)

  // if (to.path.indexOf("/home") !== -1) {
  //   return "/login"
  // }
  
  if (to.path !== "/login") {
    const token = window.localStorage.getItem("token");
    if (!token) {
      return "/login"
    }
  }
})


export default router

App.vue

<template>
  <div id="app">
    <!-- props: href 跳轉的鏈接 -->
    <!-- props: route對象 -->
    <!-- props: navigate導航函數 -->
    <!-- props: isActive 是否當前處於活躍的狀態 -->
    <!-- props: isExactActive 是否當前處於精確的活躍狀態 -->
    <router-link to="/home" v-slot="props" custom>
      <button @click="props.navigate">{{ props.href }}</button>
      <button @click="props.navigate">哈哈哈</button>
      <span :class="{ active: props.isActive }">{{ props.isActive }}</span>
      <span :class="{ active: props.isActive }">{{ props.isExactActive }}</span>
      <!-- <p>{{props.route}}</p> -->
    </router-link>
    <router-link to="/about">關於</router-link>
    <router-link to="/user/kobe/id/111">用戶</router-link>
    <router-link to="/category">分類</router-link>

    <button @click="jumpToAbout">關於</button>
    <button @click="forwardOneStep">前進一步</button>

    <router-view v-slot="props">
      <!-- <transition name="why"> -->
      <keep-alive>
        <component :is="props.Component"></component>
      </keep-alive>
      <!-- </transition> -->
    </router-view>
  </div>
</template>

<script>
  import { useRouter } from 'vue-router'
  import NavBar from './components/NavBar.vue'

  export default {
    name: 'App',
    components: {
      NavBar,
    },
    methods: {
      // jumpToAbout() {
      //   // router
      //   this.$router.push("/about")
      // }
    },
    setup() {
      const router = useRouter()

      const jumpToAbout = () => {
        // router.push("/about")
        // router.push({
        //   path: "/about",
        //   query: {
        //     name: "why",
        //     age: 18
        //   }
        // })
        // router.replace("/about")
      }

      const forwardOneStep = () => {
        router.go(1)
        // router.go(-1)
        // router.forward()
        // router.back()
      }

      return {
        jumpToAbout,
        forwardOneStep,
      }
    },
  }
</script>

<style>
  .why-active {
    color: red;
  }

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

  .why-enter-active,
  .why-leave-active {
    transition: opacity 1s ease;
  }
</style>

Home.vue

<template>
  <div>
    <h2>Home</h2>
    <ul>
      <li>home的內容1</li>
      <li>home的內容2</li>
      <li>home的內容3</li>
    </ul>
    <router-view />

    <router-link to="/home/message">消息</router-link>
    <router-link to="/home/shops">商品</router-link>
    <router-link to="/home/moment">動態</router-link>
  </div>
</template>

<script>
  export default {}
</script>

<style scoped></style>

HomeShops.vue

<template>
  <div>
    <h2>商品組件</h2>
    <ul>
      <li>shops1</li>
      <li>shops2</li>
      <li>shops3</li>
    </ul>
  </div>
</template>

<script>
  export default {}
</script>

<style scoped></style>

HomeMessage.vue

<template>
  <div>
    <h2>消息組件</h2>
    <ul>
      <li>messasge1</li>
      <li>messasge2</li>
      <li>messasge3</li>
    </ul>
  </div>
</template>

<script>
  export default {}
</script>

<style scoped></style>


HomeMoment.vue

<template>
  <div>
    <h2>HomeMoment</h2>
  </div>
</template>

<script>
  export default {}
</script>

<style scoped></style>

About.vue

<template>
  <div>
    <h2>About: {{ $route.query.name }}-{{ $route.query.age }}</h2>
  </div>
</template>

<script>
  export default {}
</script>

Login.vue

<template>
  <div>
    <button @click="loginClick">登錄</button>
  </div>
</template>

<script>
  import { useRouter } from 'vue-router'

  export default {
    setup() {
      const router = useRouter()

      const loginClick = () => {
        window.localStorage.setItem('token', 'why')

        router.push({
          path: '/home',
        })
      }

      return {
        loginClick,
      }
    },
  }
</script>

NotFound.vue

<template>
  <div>
    <h2>Page Not Found</h2>
    <p>您打開的路徑頁面不存在, 請不要使用我們家的應用程序了~</p>
    <h1>{{ $route.params.pathMatch }}</h1>
  </div>
</template>

<script>
  export default {}
</script>

User.vue

<template>
  <div>
    <h2>User: {{ $route.params.username }}-{{ $route.params.id }}</h2>
  </div>
</template>

<script>
  import { useRoute } from 'vue-router'

  export default {
    created() {
      // 【username是在router/index.js中自定義的,兩者要保持一致。】
      console.log(this.$route.params.username)
    },
    setup() {
      const route = useRoute()
      console.log(route.params.username)
    },
  }
</script>

<template>
  <div>
    <h2>{{ title }}</h2>
  </div>
</template>

<script>
  export default {
    props: {
      title: String,
    },
  }
</script>

historyApiFallback

https://github.com/bripkens/connect-history-api-fallback



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM