Skip to content

Vue3二级路由案例

Vue3中使用bootstrap@3

  1. 安装Jquery
js
npm install jquery --save
  1. 配置Jquery:vue.config.js文件配置
js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
    transpileDependencies: true,
    devServer: {
        open: true,// 自动打开浏览器
        port: 8080,// 指定端口号
        host: "127.0.0.1",// 指定host
    },
    // 关闭编译时的特征标志
    chainWebpack: (config) => {
        config.plugin('define').tap((definitions) => {
            Object.assign(definitions[0], {
                __VUE_OPTIONS_API__: 'true',
                __VUE_PROD_DEVTOOLS__: 'false',
                __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
            })
            return definitions
        })
    }
})
const webpack = require("webpack")
module.exports = defineConfig({
    transpileDependencies: true,
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "windows.jQuery": "jquery",
                "windows.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    }
})
  1. 安装bootstrap:
js
npm install bootstrap@3
  1. 在入口文件引入:main.ts
js
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
import "../node_modules/bootstrap/dist/js/bootstrap.min.js"

问题:

js
这个引入就跟上面的vue2全局引入一样了
如果运行报如下错误,可以在项目根目录下新建一个.eslintignore文件
文件中只写一个 *
  1. 也可以按照html静态页面link引入:public->index.html
html
<!DOCTYPE html>
<html lang="">
  <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">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!--这里引入-->
    <link rel="stylesheet" href="/bootstrap.css">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

创建静态组件

  1. 创建入口文件:src->main.ts
tsx
import { createApp } from 'vue'
import App from './App.vue'

import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
import "../node_modules/bootstrap/dist/js/bootstrap.min.js"

import router from "@/router/"

createApp(App).use(router).mount('#app')
  1. 配置vue:vue.config.js
js
const { defineConfig } = require('@vue/cli-service')
const webpack = require("webpack")
module.exports = defineConfig({
    transpileDependencies: true,
    devServer: {
        open: true,// 自动打开浏览器
        port: 8080,// 指定端口号
        host: "127.0.0.1",// 指定host
    },
    // 关闭编译时的特征标志
    chainWebpack: (config) => {
        config.plugin('define').tap((definitions) => {
            Object.assign(definitions[0], {
                __VUE_OPTIONS_API__: 'true',
                __VUE_PROD_DEVTOOLS__: 'false',
                __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
            })
            return definitions
        })
    },
    // 配置Jquery
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "windows.jQuery": "jquery",
                "windows.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    },
})
  1. 主组件:src->App.vue
vue
<template>
    <div class="row">
        <div class="col-xs-offset-2 col-xs-8">
            <div class="page-header">
                <h2>Vue3 Router Demo</h2>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-2 col-xs-offset-2">
            <div class="list-group">
                <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
                <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
            </div>
        </div>
        <div class="col-xs-6">
            <div class="panel">
                <div class="panel-body">
                    <router-view></router-view>
                </div>
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup>

</script>

<style scoped></style>
  1. 首页:src->pages->Home->index.vue
vue
<template>
    <h2>Home组件内容</h2>
    <div>
        <ul class="nav nav-tabs">
            <li><router-link to="/home/newsList" exact-active-class="active" class="list-group-item">NewsList</router-link></li>
            <li><router-link to="/home/message" active-class="active" class="list-group-item">Message</router-link></li>
        </ul>
        <div>
            <router-view></router-view>
        </div>
    </div>
</template>

<script lang="ts" setup>

</script>

<style scoped></style>
  1. 二级页面NewsList:src->pages->Home->NewsList->index.vue
vue
<template>
    <h4>NewsList组件内容</h4>
    <ul>
        <li>
            <a href="/home/message/1">news001</a> &nbsp;&nbsp;
            <button>push</button> &nbsp;
            <button>replace</button>
        </li>
        <li><a href="/home/message/2">news002</a> &nbsp;&nbsp;<button>push
            </button> &nbsp;<button>
                replace
            </button>
        </li>
        <li><a href="/home/message/3">news003</a> &nbsp;&nbsp;<button>push
            </button> &nbsp;<button>
                replace
            </button>
        </li>
    </ul>
    <button>前进</button>
    <button>后退</button>
</template>

<script lang="ts" setup>

</script>

<style scoped></style>
  1. 二级页面Message:src->pages->Home->Message->index.vue
vue
<template>
    <h4>Message组件内容</h4>
    <div>
        <ul>
            <li v-for="item in state.films" :key="item.filmId">
                <router-link :to="{
                    path: '/home/message/' + item.filmId
                }">{{item.name}}</router-link> &nbsp;&nbsp;
                <button @click="goDetail(item.filmId)">push</button> &nbsp;
                <button @click="$router.replace('/home/message/'+item.filmId)">replace</button>
            </li>
        </ul>
        <button @click="$router.forward()">前进</button>
        <button @click="$router.back()">后退</button>
        <router-view></router-view>
    </div>
</template>

<script lang="js" setup>
import { onMounted,reactive } from 'vue'
import {getMessage} from '@/api/index'
import {useRouter} from 'vue-router'
let state = reactive({
    films: []
})
const $router = useRouter();

const goDetail = (filmId)=>{
    $router.push('/home/message/'+filmId)
}

onMounted(function(){
    getMessage().then(res => {
        state.films = res.data.films
    })
})


</script>

<style scoped></style>
  1. 三级页面Details:src->pages->Home->Message->Details->index.vue
vue
<template>
    <h4>Detail</h4>
    <h5>{{state.film.name}}</h5>
    <h5>{{ state.film.category }}</h5>
</template>

<script lang="js" setup>
import { onBeforeRouteUpdate, useRoute,useRouter } from "vue-router";
import { onMounted, reactive, watch } from "vue";
import { getMessageDetails } from '@/api/index.js'
// 方案一 导入router对象
import $router from "@/router"
console.log($router.currentRoute.value.params.filmId)
// 方案二 通过Route对象
const route = useRoute()
console.log(route.params.filmId)
// 方案三 通过Router对象
const router = useRouter()
console.log(router.currentRoute.value.params.filmId)

const state = reactive({
    film: {}
})

const getFilms1 = function (filmId){
    getMessageDetails(filmId).then(res => {
        state.film = res.data.film
    })
}
// 获取数据方案一
// 在路由更新前调用方法获取数据
onBeforeRouteUpdate(async function(to,from,next){
    await getFilms1(to.params.filmId )
    next();
})
// 在挂载路由后获取数据
onMounted(function (){
    getFilms1(route.params.filmId)
})

// 获取数据方案二- watch
watch(() => route.params.filmId, () => { 
        getFilms1(route.params.filmId) 
    },{
        immediate:true
    })
</script>

<style scoped></style>
  1. 路由配置文件:src->router->index.ts
tsx
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
// 生成路由组件的方法
const renderCom = function (name: string) {
    return () => import("@/pages/" + name + "/index.vue");
}

const routes = [
    {
        path: "/",
        redirect: "/home"
    }, 
    {
        path: "/home",
        component: () => import('@/pages/Home/index.vue'),
        children:[
            {
                path:'/home',
                redirect:'/home/newslist'
            },
            {
                path: "/home/message",
                component: () => import("@/pages/Home/Message/index.vue"),
                children: [
                    {
                        path: "/home/message/:filmId",
                        component: renderCom("Home/Message/Details")
                    }
                ]
            },
            {
                path: "/home/newsList",
                component: () => import("@/pages/Home/NewsList/index.vue")
            },
        ]
    },
    {
        path: "/about",
        component: () => import('@/pages/About/index.vue')
    },
    {
        // vue-router@4不支持以下代码实现404
        // path:"*",
        // component:NotFount

        // 需要借助params形式实结合正则实现404
        path: "/:pathMath(.*)",
        component: () => import('@/pages/NotFount/index.vue')
    }
]
// 3- 创建router
const router = createRouter({
    // 相当于Vue2当中的mode:"history"
    history: createWebHistory(),
    // 相当于Vue2当中的mode:"hash"
    // history:createWebHashHistory(),
    routes,
    scrollBehavior() {
        return {
            left: 0,// 相当于之前的x
            top: 0// 相当于之前的y
        }
    }
    // 
})
export default router
  1. 封装request:src->request->mz.js
js
import axios from 'axios'
import nprogress from 'nprogress'
import 'nprogress/nprogress.css'
const mzlist = axios.create({
    baseURL: "https://m.maizuo.com/",
    timeout: 10000,
    headers: {
        "X-Client-Info": '{"a":"3000","ch":"1002","v":"5.2.1","e":"172535550811886210322530305","bc":"440300"}',
        "X-Host": "mall.film-ticket.film.list"
    }
});

const mzinfo = axios.create({
    baseURL: "https://m.maizuo.com/",
    timeout: 10000,
    headers: {
        "X-Client-Info": '{"a":"3000","ch":"1002","v":"5.2.1","e":"172535550811886210322530305","bc":"440300"}',
        "X-Host": "mall.film-ticket.film.info"
    }
});


mzlist.interceptors.request.use(config => {
    nprogress.start()
    return config;
})

// 设置响应拦截器
mzlist.interceptors.response.use(res => {
    nprogress.done()
    return res.data;
})

mzinfo.interceptors.request.use(config => {
    nprogress.start()
    return config;
})

// 设置响应拦截器
mzinfo.interceptors.response.use(res => {
    nprogress.done()
    return res.data;
})

export {
    mzlist,
    mzinfo
}
  1. 封装api:src->api->index.js
js
import {mzlist, mzinfo} from '@/request/mz'

// 获取三个热映的电影
const getMessage = () => {
    return mzlist.get('/gateway?cityId=440300&pageNum=1&pageSize=3&type=1&k=93408')
}

// 根据ID获取电影详情
const getMessageDetails = (filmId) => {
    return mzinfo.get('/gateway?filmId=' + filmId +'&k=7455076')
}

export {
    getMessage,
    getMessageDetails
}

数据渲染

  1. 渲染Message组件中的数据:src->pages->Home->Message->index.vue
vue
<template>
    <ul>
        <li v-for="item in state.films" :key="item.filmId">
            <router-link :to="{
                path:'/home/message/'+item.filmId
            }">{{item.name}}</router-link> &nbsp;&nbsp;
            <button>push</button> &nbsp;
            <button>replace</button>
        </li>
    </ul>
    <button>前进</button>
    <button>后退</button>
    <hr/>
    <router-view></router-view>
</template>
  1. 渲染Details组件中的数据:src->pages->Home->Message->Detail->index.vue
vue
<template>
    <h4>Detail</h4>
    <h5>{{state.film.name}}</h5>
    <h5>{{ state.film.category }}</h5>
</template>

<script lang="js" setup>
import { onBeforeRouteUpdate, useRoute,useRouter } from "vue-router";
import { onMounted, reactive, watch } from "vue";
import { getMessageDetails } from '@/api/index.js'
// 方案一 导入router对象
import $router from "@/router"
console.log($router.currentRoute.value.params.filmId)
// 方案二 通过Route对象
const route = useRoute()
console.log(route.params.filmId)
// 方案三 通过Router对象
const router = useRouter()
console.log(router.currentRoute.value.params.filmId)

const state = reactive({
    film: {}
})

const getFilms1 = function (filmId){
    getMessageDetails(filmId).then(res => {
        state.film = res.data.film
    })
}
// 获取数据方案一
// 在路由更新前调用方法获取数据
onBeforeRouteUpdate(async function(to,from,next){
    await getFilms1(to.params.filmId )
    next();
})
// 在挂载路由后获取数据
onMounted(function (){
    getFilms1(route.params.filmId)
})

// 获取数据方案二- watch
watch(() => route.params.filmId, () => { 
    getFilms1(route.params.filmId) 
    console.log('watch is running')
    },{
        immediate:true
    })
</script>

<style scoped></style>

编程式导航

  1. src->pages->Home->Message->index.vue
vue
<template>
    <h4>Message组件内容</h4>
    <div>
        <ul>
            <li v-for="item in state.films" :key="item.filmId">
                <router-link :to="{
                    path: '/home/message/' + item.filmId
                }">{{item.name}}</router-link> &nbsp;&nbsp;
                <button @click="goDetail(item.filmId)">push</button> &nbsp;
                <button @click="$router.replace('/home/message/'+item.filmId)">replace</button>
            </li>
        </ul>
        <button @click="$router.forward()">前进</button>
        <button @click="$router.back()">后退</button>
        <router-view></router-view>
    </div>
</template>

<script lang="js" setup>
import { onMounted,reactive } from 'vue'
import {getMessage} from '@/api/index'
import {useRouter} from 'vue-router'
let state = reactive({
    films: []
})
const $router = useRouter();

const goDetail = (filmId)=>{
    $router.push('/home/message/'+filmId)
}

onMounted(function(){
    getMessage().then(res => {
        state.films = res.data.films
    })
})


</script>

<style scoped></style>