Vue3二级路由案例
Vue3中使用bootstrap@3
- 安装Jquery
js
npm install jquery --save
- 配置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"]
})
]
}
})
- 安装bootstrap:
js
npm install bootstrap@3
- 在入口文件引入:main.ts
js
import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
import "../node_modules/bootstrap/dist/js/bootstrap.min.js"
问题:
js
这个引入就跟上面的vue2全局引入一样了
如果运行报如下错误,可以在项目根目录下新建一个.eslintignore文件
文件中只写一个 *
- 也可以按照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>
创建静态组件
- 创建入口文件: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')
- 配置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"]
})
]
},
})
- 主组件: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>
- 首页: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>
- 二级页面NewsList:src->pages->Home->NewsList->index.vue
vue
<template>
<h4>NewsList组件内容</h4>
<ul>
<li>
<a href="/home/message/1">news001</a>
<button>push</button>
<button>replace</button>
</li>
<li><a href="/home/message/2">news002</a> <button>push
</button> <button>
replace
</button>
</li>
<li><a href="/home/message/3">news003</a> <button>push
</button> <button>
replace
</button>
</li>
</ul>
<button>前进</button>
<button>后退</button>
</template>
<script lang="ts" setup>
</script>
<style scoped></style>
- 二级页面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>
<button @click="goDetail(item.filmId)">push</button>
<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>
- 三级页面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>
- 路由配置文件: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
- 封装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
}
- 封装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
}
数据渲染
- 渲染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>
<button>push</button>
<button>replace</button>
</li>
</ul>
<button>前进</button>
<button>后退</button>
<hr/>
<router-view></router-view>
</template>
- 渲染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>
编程式导航
- 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>
<button @click="goDetail(item.filmId)">push</button>
<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>