天天看點

vue3+TypeScript+vue-router使用

簡單使用

建立項目

vue-cli建立

$npm install -g @vue/cli
$vue --version
@vue/cli 4.5.15
$vue create my-project
           

然後的步驟:

  1. Please pick a preset

    選擇 Manually select features

  2. Check the features needed for your project

    選擇上

    TypeScript

    ,特别注意點空格是選擇,點回車是下一步
  3. Choose a version of Vue.js that you want to start the project with

    選擇 3.x (Preview)

  4. Use class-style component syntax

    直接回車

  5. Use Babel alongside TypeScript
  6. Pick a linter / formatter config
  7. Use history mode for router?
  8. Pick additional lint features
  9. Where do you prefer placing config for Babel, ESLint, etc.?
  10. Save this as a preset for future projects?

檔案結構:

my-project
+--- babel.config.js
+--- package-lock.json
+--- package.json
+--- public
|   +--- favicon.ico
|   +--- index.html
+--- README.md
+--- src
|   +--- App.vue
|   +--- assets
|   |   +--- logo.png
|   +--- components
|   |   +--- HelloWorld.vue
|   +--- main.ts
|   +--- shims-vue.d.ts
+--- tsconfig.json
+--- node_modules
|   +--- ...
           
入口檔案為

src/main.ts

vite建立

執行以下指令建立項目

$npm init vite-app <project-name>
$cd <project-name>
$npm install
$npm run dev
           
project-name
+--- index.html
+--- package-lock.json
+--- package.json
+--- public
|   +--- favicon.ico
+--- src
|   +--- App.vue
|   +--- assets
|   |   +--- logo.png
|   +--- components
|   |   +--- HelloWorld.vue
|   +--- index.css
|   +--- main.js
+--- node_modules
|   +--- ...
           

src/main.ts

注意: 由于使用vite方法建立的項目沒有vue的聲明檔案, 是以需要我們自定義, 否則會報錯.

src/shims-vue.d.ts

/* eslint-disable */
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}
           

安裝

vue-router

$npm install vue-router@4
           

至此,

package.json

如下:

{
  "name": "my-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0",
    "vue-router": "^4.0.12"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-typescript": "^7.0.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0",
    "typescript": "~4.1.5"
  }
}
           

建立/修改元件

  1. 建立

    src/router/index.ts

    import { createRouter, createWebHashHistory } from "vue-router"
    
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'
    import User from '../components/User.vue'
    
    const routes = [
    	// router參數詳細看下文
    	{
    		path: "/home",
    		name: "home",
    		component: Home
    	},
    	{
    		path: "/about",
    		name: "about",
    		component: About
    	},
    	{
    		path: "/user/:uid",  // 動态參數
    		name: "user",
    		component: User
    	}
    ]
    export const router = createRouter({
    	history: createWebHashHistory(),
    	routes: routes
    })
               
  2. 建立元件:

    Home.vue

    About.vue

    User.vue

    src/components/Home.vue

    <template>
      <div>home元件</div>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "Home",
      setup() {
    	return {
    	  // 傳回的資料
    	};
      },
    });
    </script>
               

    src/components/About.vue

    <template>
      <div>About元件</div>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "About",
      setup() {
    	return {
    	  // 傳回的資料
    	};
      },
    });
    </script>
    
               

    src/components/User.vue

    <template>
      <div>User元件</div>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "User",
      setup() {
    	return {
    	  // 傳回的資料
    	};
      },
    });
    </script>
               
  3. 修改

    App.vue

    <template>
      <div>{{ appMessage }}</div>
      <!-- router-link會被渲染成a标簽 -->
      <router-link to="/home">home</router-link>
      <router-link to="/about">about</router-link>
      <router-link to="/user/lczmx">user</router-link>
    
      <!-- 路由出口 -->
      <!-- 路由比對到的元件将渲染在這裡 -->
      <router-view></router-view>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
    	const appMessage = "App元件";
    	return {
    	  // 傳回的資料
    	  appMessage,
    	};
      },
    });
    </script>
    <style>
    /* 添加樣式 */
    #app {
      text-align: center;
      margin-top: 50px;
    }
    a {
      margin: 30px;
      display: inline-block;
    }
    </style>
               

修改入口ts

src/main.ts

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

import { router } from './router'

// 建立應用 傳回對應的執行個體對象
const app = createApp(App)

// 安裝 vue-router 插件
app.use(router)
// 調用mount方法
app.mount('#app')
           

啟動vue

$npm run serve

> [email protected] serve
> vue-cli-service serve 

 INFO  Starting development server...
98% after emitting CopyPlugin

 DONE  Compiled successfully in 6387ms                                                                                               下午4:14:30

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.43.12:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

No issues found.
           

在浏覽器中通路

根據提示, 通路

http://localhost:8080/

, 如下圖

vue3+TypeScript+vue-router使用

檔案結構圖檔

vue3+TypeScript+vue-router使用

綜合使用

動态參數

假如我們需要的路由是:

/user/lczmx

/user/jack

, 但是我們明顯不可能為這兩個路由定義兩個不同的元件, 最好的方法就是使用動态參數:

const routes = [
  // 動态段以冒号開始
  { path: '/users/:id', component: User },
  // 使用正規表達式  `()` 裡面的東西會傳給前面的pathMatch
  // 值在route.params.pathMatch下
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
]
           

比對時, 會将參數映射到

router

執行個體的

currentRoute.value.params

注意vue2中: 由于在

setup

無法使用

this.$route

this.$router

至于如何擷取, 看我的另一篇部落格: vue3擷取目前路由 和 官網: Vue Router 和 組合式 API

比對清單

比對模式 比對路徑 目前路由的參數

/users/:username

/users/eduardo

{ username: 'eduardo' }

/users/:username/posts/:postId

/users/eduardo/posts/123

{ username: 'eduardo', postId: '123' }

在使用帶有參數的路由時需要注意: 由于相同的元件執行個體将被重複使用,是以元件的生命周期鈎子不會被調用

但是我們可以對路由進行監聽

使用watch監聽動态參數

src/components/User.vue

:

<template>
  <div>User元件</div>
  <p>目前使用者: {{ uid }}</p>

  <router-link to="/user/lczmx">lczmx</router-link>
  <router-link to="/user/jack">jack</router-link>
</template>

<script lang="ts">
import { defineComponent, watch, ref } from "vue";
import { useRouter } from "vue-router";

export default defineComponent({
  name: "User",
  setup() {
    const router = useRouter();
    const uid = ref(router.currentRoute.value.params.uid);
    watch(
      // 監聽非響應式資料
      () => router.currentRoute.value,
      (val) => {
        // 修改uid
        uid.value = val.params.uid;
      }
    );
    return {
      // 傳回的資料
      uid,
    };
  },
});
</script>
           
vue3+TypeScript+vue-router使用

使用組合API監聽動态參數

https://next.router.vuejs.org/zh/guide/advanced/composition-api.html

重定向

下面使用

router

的全部參數:

const routes = [
    {
        path: "/",
        // 寫法1 寫死url
        // redirect: "/home", // 通路 "/" 時 跳轉到 "/home"

        // 寫法2 跳轉到對應的命名路由
        redirect: { name: "home" },

        // 寫法3 定義一個方法
		// 該方法亦可以 傳回一個相對路徑
        /*
        redirect: to => {
            // 方法接收目标路由作為參數 "to"

            // return 重定向的字元串路徑/路徑對象
			
			// query指定參數
            return { path: '/home', query: { q: to.params.searchText } }
        },
        */
    },
    {
        path: "/home",
        name: "home",
        component: Home
    }
]

           
注意, 重定向不會觸發 導航守衛
另附官網的例子: Named Views - Vue Router 4 examples

命名與别名

命名路由

給路由一個名稱, 可以在其他路由中使用, 如:

redirect

router-link

const routes = [
  {
    path: '/user/:username',
    name: 'user',
    component: User
  }
]

           

redirect

的使用如上文, 而

router-link

<template>
  <div>User元件</div>
  <p>目前使用者: {{ uid }}</p>

  <router-link :to="{ name: 'user', params: { uid: 'lczmx' } }"
    >lczmx</router-link
  >
  <router-link :to="{ name: 'user', params: { uid: 'jack' } }"
    >jack</router-link
  >
</template>
           

router.push

(

router

router

對象)中使用:

router.push({ name: 'user', params: { uid: 'lczmx' } })
           

命名視圖

即, 我們可以

router-view

定義一個名字, 已達到實作可複用的效果

我們可以使用這個功能實作 一個側邊欄等

舉個例子

  1. 定義路由:
    import { createRouter, createWebHashHistory } from "vue-router"
    
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'
    import User from '../components/User.vue'
    
    const routes = [
    	{
    		path: "/",
    		components: {
    			default: Home,  // 預設用Home元件
    			a: About,  // a用About元件
    			b: User,  // b用User元件
    		},
    
    	},
    	{
    		path: "/home",
    		components: {
    			default: About,   // 預設用About元件
    			a: Home,  // a用Home元件
    			b: User,  // b用User元件
    		},
    
    	},
    ]
    
    
    export const router = createRouter({
    	history: createWebHashHistory(),
    	routes: routes
    })
               
  2. App.vue

    <template>
      <div>{{ appMessage }}</div>
    
      <!-- router-link會被渲染成a标簽 -->
      <router-link to="/">/</router-link>
      <router-link to="/home">/home</router-link>
    
      <!-- 路由出口 -->
      <!-- 路由比對到的元件将渲染在這裡 -->
      <!-- default -->
      <router-view></router-view>
      <router-view name="about"></router-view>
      <router-view name="user"></router-view>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    export default defineComponent({
      name: "App",
      setup() {
    	const appMessage = "App元件";
    	return {
    	  // 傳回的資料
    	  appMessage,
    	};
      },
    });
    </script>
    <style>
    /* 添加樣式 */
    #app {
      text-align: center;
      margin-top: 50px;
    }
    a {
      margin: 30px;
      display: inline-block;
    }
    </style>
               
  3. 其他元件

    About.vue

    <template>
      <div>about元件</div>
    </template>
               

    Home.vue

    <template>
      <div>home元件</div>
    </template>
               

    User.vue

    <template>
      <div>user元件</div>
    </template>
               
  4. 啟動服務并通路vue

    如圖:

    vue3+TypeScript+vue-router使用
假如不指定視圖名, 那麼為

default

别名

可以實作 不同url 通路同一路由的效果
const routes = [
    // 可以通路 "/home" 也可以通路 "/"
    // 且通路的路徑不會改變
    {
        path: "/home",
        name: "home",
        component: Home,
        alias: "/"
    }
           

嵌套路由

之前我們在

App.vue

中定義

router-view

, 讓其他元件在哪裡渲染

但假如我們需要在其他元件中渲染的話, 就需要嵌套路由了

使用

children

嵌套路由, 它的值是路由資料, 就好像外部的

router

那樣定義

例子:

  • router.index.ts

    import { createRouter, createWebHashHistory } from "vue-router"
    
    import Home from '../components/Home.vue'
    import About from '../components/About.vue'
    import User from '../components/User.vue'
    import UserHome from '../components/UserHome.vue'
    import UserSettings from '../components/UserSettings.vue'
    import UserProfile from '../components/UserProfile.vue'
    
    const routes = [
    	// 可以通路 "/home" 也可以通路 "/"
    	// 且通路的路徑不會改變
    	{
    		path: "/home",
    		name: "home",
    		component: Home,
    		alias: "/"
    	},
    	{
    		path: "/about",
    		name: "about",
    		component: About
    	},
    	{
    		path: "/user/:uid",  // 動态參數
    		name: "user",
    		component: User,  // 内部有router-view渲染要嵌套的路由
    		children: [
    			// 比對形如 /user/lczmx 的url
    			{ path: "", component: UserHome },
    
    			// 比對形如 /user/lczmx/settings 的url
    			{ path: "settings", component: UserSettings, name: "user-settings" },
    
    			// 比對形如 /user/lczmx/profile 的url
    			{ path: "profile", component: UserProfile, name: "user-profile" }
    		]
    	}
    ]
    
    
    export const router = createRouter({
    	history: createWebHashHistory(),
    	routes: routes
    })
    
               
    注意: 假如

    children

    中沒有

    path: ""

    的話, 那麼通路

    /user/lczmx

    , 隻能得到一個頁面空白
  • User.vue

    <template>
      <div>
    	<router-link :to="{ name: 'user-settings' }">settings</router-link>
    	<router-link :to="{ name: 'user-profile' }">profile</router-link>
      </div>
    
      <router-view></router-view>
    </template>
               
  • UserHome.vue

    <template>
      <div>使用者首頁</div>
    </template>
               
  • UserProfile.vue

    <template>
      <div>使用者詳細資訊頁面</div>
    </template>
    
               
  • UserSettings.vue

    <template>
      <div>使用者設定頁面</div>
    </template>
               
  • 啟動并通路

    在浏覽器中測試:

    vue3+TypeScript+vue-router使用

程式設計式路由

即不通過a标簽, 而是通過

js/ts

改變路由, 原理是向

history

棧添加一個新的記錄

在vue3中, 有以下寫法

<template>
  <div>about元件</div>
  <button @click="changeRouter">修改路由</button>
</template>


<script lang="ts">
import { defineComponent } from "vue";

import { useRouter } from "vue-router";

export default defineComponent({
  name: "About",
  setup() {
    // 獲得router對象
    const router = useRouter();

    const changeRouter = () => {
      /* 修改路由的例子 */

      // 1 字元串路徑
      router.push("/users/lczmx");

      // 2 帶有路徑的對象
      router.push({ path: "/users/lczmx" });

      // 3 命名的路由,并加上參數,讓路由建立 url
      router.push({ name: "user", params: { username: "lczmx" } });

      // 4 帶查詢參數,結果是 /register?plan=private
      router.push({ path: "/register", query: { plan: "private" } });

      // 5 帶 hash,結果是 /about#team
      router.push({ path: "/about", hash: "#team" });

      // 6 我們可以手動建立 url,但我們必須自己處理編碼
      const username = "lczmx";
      router.push(`/user/${username}`); // -> /user/lczmx
      // 同樣
      router.push({ path: `/user/${username}` }); // -> /user/lczmx
      // 如果可能的話,使用 `name` 和 `params` 從自動 URL 編碼中獲益
      router.push({ name: "user", params: { username } }); // -> /user/lczmx

      // 7 `params` 不能與 `path` 一起使用, 否則 `params` 将會被忽略
      router.push({ path: "/user", params: { username } }); // -> /user

      // 8 replace為true 不向history 中添加
      router.push({ path: "/home", replace: true });
      // 等同于
      router.replace({ path: "/home" });

      // 9 橫跨曆史
      // 向前移動一條記錄,與 router.forward() 相同
      router.go(1);
      // 傳回一條記錄,與router.back() 相同
      router.go(-1);
      // 前進 3 條記錄
      router.go(3);
      // 如果沒有那麼多記錄,靜默失敗
      router.go(-100);
      router.go(100);
    };
    return {
      // 傳回的資料
      changeRouter,
    };
  },
});
</script>

<style>
button {
  margin: 30px;
}
</style>
           
更多見vue-router4官網: Vue Router

本文來自部落格園,作者:403·Forbidden,轉載請注明原文連結:https://www.cnblogs.com/lczmx/p/15763999.html