DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • html

  • css

  • javascript

  • jquery

  • UI库

  • 第一次学vue

    • 基础语法(1)
    • 基础语法(2)
    • Vue生命期钩子
    • 基础语法(3)
    • Vue-cli
    • 插件的使用(1)
      • 编写vue插件
        • plugins/index.js
        • main.js
        • App.vue
      • 样式库
        • bootstrap
        • Element-Ui
        • Element Plus
      • vue-route
        • 安装
        • 快速上手
        • URL传值 - query
        • URL动态参数 - params
        • 嵌套
        • 路由导航
        • 声明式导航
        • 编程式导航
        • 回顾嵌套
        • 示例: 登陆跳转
        • 含顶部
        • 不含顶部
        • 导航守卫(全局)
    • 插件的使用(2)
    • 总结
  • 第二次学vue

  • 前端
  • 第一次学vue
DC
2023-11-16
目录

插件的使用(1)

# 编写vue插件

安装第三方插件时, 都需要在main.js中调用下.

比如: Vue.use(ElementUi); Vue.use(Vuex); Vue.use(Router); 这样就算是完成了对三个插件的安装.
我们就可以在组件中调用 this.$router、this.$route、this.$store、this.$alert()(ElementUI的弹窗组件)参数(方法)

Q: 同样是插件, 为什么有些插件要有install方法才能正常运行(如VueRouter),有一些却可以没有install方法也可以使用(如axios)
A: 简单来说,因为axios是基于Promise封装的库,是完全独立于Vue的,根本不需要挂载在Vue上也能实现发送请求.
   而因为VueRouter需要为我们提供$router、$routers之类的属性,要依赖与Vue或者操作Vue实例才能实现.
   ★★★ Vue.use实际上就是Vue实例与插件的一座桥梁

使用插件就是用于增强Vue!!
参考文档(了解即可!): https://juejin.cn/post/6844903946343940104#heading-7
1
2
3
4
5
6
7

那我们自己如何编写一个插件呢?

Step1: 在vue项目的src目录下新建 plugins文件夹, 在plugins文件夹下创建 index.js文件
Step2: 在plugins/index.js中编写代码, 定义插件
Step3: 在main.js中写两行代码使用插件!

# plugins/index.js

1> 可通过Vue.prototype在vue原型上放 变量、函数/方法等. 这些变量函数都可以在所有的vm、vc上使用!!

特别注意, 示例中只涉及到对Vue.prototype中变量的使用!! 更新啥的就别探究了,用到了再说. Ps: 若需要对Vue.prototype中里放的变量进行修改的话, 需考虑下该变量的类型..
我实验了下, 发现更新后, 页面上的插值不能响应式的更新.我找了半天也没解决. 需要用的时候再说吧!!

import Vue from "vue";
import axios from "axios";

export default {
    // install: function (a) {}
    // 其实这个a参数就是vue实例!!
    install(a) {
        // ★ 在vue原型上放东西 所有vc和vm都可以用hello
        Vue.prototype.func1 = () => {
            console.log("This is func1");
        };
        Vue.prototype.s_value = "bingo"
        Vue.prototype.dict_obj = {'number': 30}
        Vue.prototype.arr_obj = [1]

        //  ★ 定义混入,一旦该插件在main.js中使用后,所有vc和vm都可调用混入里的东西
        Vue.mixin({
            data() {
                return {
                    city: '成都',
                    age: 20,
                };
            },
            methods: {
                // 注意一点哦, 若组件的data里定义了age,会优先使用组件里的.
                myMixin() {
                    console.log(this.city, this.name, this.age)
                }
            },
        });

        // ★ 可以将axios对象放到vue实例上 - 开发中是会这样使用!!
        Vue.prototype.$http = axios
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

可细细揣摩下 Vue中Vue.prototype : 参考文档 - https://juejin.cn/post/6978378505402712071

# main.js

通过 Vue.use() 使用插件!!

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false


import plugins from "@/plugins"
// 需要写在 new Vue({}) 之前.
Vue.use(plugins)

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# App.vue

在实例被创建之前就可以使用 插件里的东西!!

<template>
  <div id="father">
    {{ s_value }}
    <button @click="myMixin">点击触发mixin</button>
  </div>
</template>

<style>
#father {
  width: 500px;
  margin: auto;
  padding: 10px;
  border: 1px solid bisque;
}
</style>

<script>
export default {
  name: 'App',
  data() {
    return {
      name: "app",
      age: 21,
    }
  },
  methods: {},
  // ★★★ 在实例被创建之前就可以使用!!
  /* 小插曲(不是很重要,暂且不必深究):
     你可发现,在生命周期beforeCreate函数里修改s_value的值,插值中可以成功渲染.
     但当开始创建vue实例/也就是生命周期beforeCreate函数往后, 修改其值,插值里的数据不会同步更新.
  * */
  beforeCreate() {
    this.func1()
    console.log(this.s_value, this.dict_obj, this.arr_obj)
    this.s_value = "1111"
  },
  created() {
    this.$http.get('http://127.0.0.1:8000/user/').then(res => {
      console.log(res)
      this.s_value = "222"
    })
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 样式库

web端/pc端 常用第三方库: Element、iview
小程序、安卓app 常用第三方库: uni-app、vant 通常会两个结合一起使用.

uni-app的项目案例: https://uniapp.dcloud.net.cn/case.html#

iview        https://www.iviewui.com/view-ui-plus/guide/introduce
element-ui   https://element.eleme.cn/#/zh-CN
vant3        https://vant-contrib.gitee.io/vant/v3/#/zh-CN/home  (app移动端的ui组件库)
  
vue2和vue3引入jQuery和bootstrap3 参考文档: https://www.cnblogs.com/Neeo/articles/17311333.html
1
2
3
4
5

# bootstrap

▲ 安装
# -- 执行两条命令 通过cnpm安装jquery和bootstrap@3 
#    -S 代表在myfirstvue目录下生效,会加到项目的package.json中!!
One_Piece@DC的MacBook myfirstvue % cnpm install jquery -S 
One_Piece@DC的MacBook myfirstvue % cnpm install bootstrap@3 -S


▲ 使用
# -- step1: 在项目的入口文件main.js中写代码
#    已经安装的模块,不需要写路径,直接导入即可!自定义的模块的导入才需要写路径!
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap-theme.min.css'

# -- 因为bootstrap依赖于jquery,还要对jquery进行配置
#    step2: 在项目根目录的 vue.config.js文件中写入代码,没有该文件就新建
const webpack = require("webpack");

module.exports = {
    configureWebpack: {
        plugins: [
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "window.jQuery": "jquery",
                "window.$": "jquery",
                Popper: ["popper.js", "default"]
            })
        ]
    }
};


# ★ 注意:
# 虽然在vue中引入了jquery,但往往不会通过jquery的ajax发送请求!!若非要用,会在created(){$.ajax()}周期中使用!!
# vue是不推荐使用jquery的,但像bootstrap等第三方库依赖于jquery.. So,要使用bootstrap就得在vue中配置jquery.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# Element-Ui

每啥好说的, 看官方文档就行. https://element.eleme.cn/#/zh-CN/component/installation

Ps: vue3.0版本 用的升级版 element plus

▲ 安装
# -- 开发项目建议直接安装,不建议使用CDN
One_Piece@DC的MacBook myfirstvue % cnpm install element-ui -S


▲ 引入
# -- 在项目的入口文件中写以下代码
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

直接copy官网的示例代码就可以使用啦!!
1
2
3
4
5
6
7
8
9
10
11
12

# Element Plus

每啥好说的, 看官方文档就行. https://element-plus.org/zh-CN/guide/quickstart.html#完整引入

Ps: vue3.0版本 用的升级版 element plus

▲ 安装
安装element-plus
npm install element-plus --save (建议,通过该命令安装的版本新一些)

▲ 引入 main.js
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

createApp(App).use(store).use(router).use(ElementPlus).mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13

# vue-route

此篇幅会阐述vue-route的必备操作 (使用的是vue3的语法)

vue-route的应用场景 (我问的chatgpt4,简单概括下)
1> SPA单页面应用
   构建单页应用,其中所有页面都在同一个HTML页面中加载,通过Vue Router进行路由切换,实现无刷新的页面切换和导航效果.
2> 可以配置url参数,配置这玩意儿有何用?
   - 搜索功能、分页功能、筛选功能、排序功能等
     Ps:就分页而言,前后端不分离分页器是后端实现的,前后端分离的话,分页器是前端实现的. 
     "内心os: 哇,别比较了,在学前后端分离,那就先别想着前后端分离.. 以前后端分离为主!!学完后,再对比加深记忆!! :-D"
3> 多级嵌套的路由
4> 导航守卫
1
2
3
4
5
6
7
8
9

vue是单应用/单页面开发, 可以简单理解就是App.vue组件!! 项目不管访问什么地址一直都在展示App.vue!!
既然展示的都是App.vue,那么为啥不同地址呈现的App.vue不一样呢?是因为路由的配置.
根据路由index.js的配置,配置中一级路由对应的组件通通都会渲染到 App.vue的<router-view>处!! 
若一级路由有children属性,那么该属性下配置的二级路由都会渲染到当前一级路由对应组件的<router-view>处!!

# 安装

安装好后, 让我们来看看默认展示的页面样子是什么样的, 其内部的逻辑又是如何的.

方式一: npm install vue-route --save 并需手动创建文件和进行配置
方式二: vue add router (会自动创建文件并进行配置) 选它!!

执行vue add router命令后,会让你选择是否使用历史模式.
使用历史模式(history mode)的路由器允许您在Web应用程序中使用普通、清晰的URL,而不是默认的基于哈希(hash-based)的URL.
这意味着您可以使用类似`www.example.com/home`而不是`www.example.com/#/home`这样的URL.
1
2
3

router_d

来, 理一理逻辑!! about路由的逻辑跟home路由的逻辑一样, 就未在截图中标注.
★ 简单来说, App.vue会根据<router-link>跳转的地址去router/index.js配置文件中找到相应路由,
并将该路由对应的模版渲染到<router-view />的位置!!

补充一下: <router-link>会被渲染成a标签.. <router-view /> 是为路由渲染的组件占位.

image-20231014142156216

# 快速上手

v_1

粘贴下关键代码截图, 截图下面是完整代码

image-20231014154403418

src/router/index.js

import {createRouter, createWebHistory} from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
    // 想要路由后缀为空,或者/home的时候,都跳转到HomeView组件,注意一点,name的设置不能一样!
    {
        path: '/',
        name: 'Index',
        component: HomeView
    },
    {
        path: '/home',
        // 习惯于将首字母大写区分name和path,当然你写成小写也没问题
        name: 'Home',
        component: HomeView
    },
    {
        path: '/course',
        name: 'Course',
        component: () => import('../views/CourseView.vue')
    },
    {
        path: '/news',
        name: 'News',
        component: () => import('../views/NewsView.vue')
    },
]


const router = createRouter({
    history: createWebHistory(process.env.BASE_URL),
    routes
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

src/App.vue

<template>
  <div>
    <div class="menu">
      <div class="container">
        <router-link to="/">源代码教育</router-link>
        <router-link to="/home">首页</router-link>
        <router-link to="/course">课程</router-link>
        <router-link to="/news">咨讯</router-link>
      </div>
    </div>
    <div class="container">
      <router-view/>
    </div>
  </div>
</template>

<style>
body {
  margin: 0;
}

.menu {
  height: 48px;
  line-height: 48px;
  background-color: #499ef3;
}

.container {
  width: 980px;
  margin: 0 auto;
}

.menu a {
  display: inline-block;
  color: white;
  text-decoration: none;
  padding: 0 10px;
}


</style>

<script setup>
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

src/views/HomeView.vue
src/views/CourseView.vue
src/views/NewsView.vue

<!-- src/views/HomeView.vue -->
<template>
  <div><h1>首页</h1></div>
</template>

<script>
export default {
  name: 'HomeView',
}
</script>


<!-- src/views/CourseView.vue -->
<script>
export default {
  name: "CourseView"
}
</script>

<template>
  <div><h1>课程页面</h1></div>
</template>


<!-- src/views/NewsView.vue -->
<script>
export default {
  name: "NewsView"
}
</script>

<template>
  <div><h1>新闻页面</h1></div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# URL传值 - query

若我在url中通过?的形式get传递参数,要解决两个问题:
1> 前端/vue 如何携带? -- 点击后,url发生变化.
2> 对应 界面/vue组件 如何接收? -- url对应的组件应该接受url中携带的数据.

url_1

敲黑板

在前后端不分离的业务场景中,也可以在url中通过?的形式get传递参数,当然也可以使用动态路由,将参数写在路由中,.
最后进行路由匹配,执行对应的是视图函数,在函数中处理业务逻辑,将数据渲染到对应模版中,再将渲染好的模版返回给前端!!
★ 再次提醒: 在Django中的dtl模版语法,渲染是在后端完成的!! 而此处vue中{{name}}的渲染是由客户端浏览器来完成的!!
  也就是说,你得清楚的明白一点,前后端分离的开发场景中.在浏览器地址栏中输入一个网址,展示出的页面是浏览器渲染出来的.
1
2
3
4

稍微了解下vue2中的路由 以及 vue3路由的变化

在vue2中,有 $router 和 $route
参考链接: https://juejin.cn/post/7006289875674595365
- this.$router 表示一个全局的路由对象,vue-router 的实例,提供addRoutes、back等方法,相当于一个路由的管理者角色
  this.$router.push('/home') : 进行路由跳转到路径为 /home 的路由
- this.$route表示当前路由对象,包含具体的路由名称、path、query 、params 等属性. 
             其实就是routes(new Router时声明的routes)里面的一条具体的路由
  this.$route.path :     只返回路径部分,不包括查询参数或哈希片段.
  this.$route.fullPath : 获取完整的URL(包括查询参数和哈希片段)
  this.$route.query :    对象,包含路由中query参数的键值对. 如“..?name=qq&age=18”会得到{name:"qq","age":18}
  
以 CompositionAPI 的方式来使用 VueRouter 首要注意的就是无法在 setup 中通过 this 来访问组件实例!!
由于 setup 中无法通过 this 来访问组件实例, 因此无法直接访问 this.$router 与 this.$route !!
作为替代,我们可使用 useRouter 函数来分别获取路由记录对象(route)和路由器对象(router) !!
const {route, router} = useRouter();
1
2
3
4
5
6
7
8
9
10
11
12
13
14

url传值过程中, 必遇到的问题: vue 同一路由跳转同一路由,页面不刷新,why? *(结合下面 url动态参数 那里红色文字的阐述来理解!!).

vue官网详细解释说明使用同一路由携带不同参数,本质上是<重用相同的组件实例>.
默认在跳转路由时会采用缓存策略,并不会刷新当前路由组件因此不会调用组件的生命周期挂钩.
此处解释下何为复用: 同一个组件在不同路由间切换时,不会销毁和重新创建组件实例,而是复用之前的实例

解决方案: 使用watch (暂略) ; 使用onBeforeRouteUpdate
onBeforeRouteUpdate: 
  简单来说,当路由仅是路径参数、query、hash 发生改变, 而不是 path 发生改变时, 便会触发 onBeforeRouteUpdate
  <在组件复用时>,onBeforeRouteUpdate 钩子函数会被触发,可以用于在<路由更新之前>执行一些操作,比如重新获取数据、更新组件状态等.
  onBeforeRouteUpdate 钩子函数可接收三个参数:
  - to: 即将进入的目标路由对象
  - from: 当前导航正要离开的路由对象
  - next: 必须调用该函数来 resolve 这个钩子函数,可以传递一个参数来指示路由的行为
 
参考链接: 
   https://juejin.cn/post/6844904197326897159
   https://juejin.cn/post/7002832430658764830
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

image-20231015142057246

Ps: 获取url中的参数,通常紧接着携带获取到的数据发送ajax请求,但此处我们从简,直接将获取的url中的数据展示在页面上!!!

具体代码如下:

App.vue

<template>
  <div>
    <div class="menu">
      <div class="container">
        <router-link to="/">源代码教育</router-link>
        <router-link to="/home">首页</router-link>
        <!-- 这三种写法是等同的!!
          <router-link to="/course">课程</router-link>
          <router-link :to="{path:'/course'}">课程_bindToPath</router-link>
          <router-link :to="{name:'Course'}">课程_bindToName</router-link>
        -->
        <router-link to="/course">课程</router-link>
        <router-link :to="{path:'/course',query:{size:10,page:11}}">课程_pathQuery</router-link>
        <router-link :to="{name:'Course',query:{size:20,page:21}}">课程_nameQuery</router-link>

        <router-link to="/news">咨讯</router-link>
      </div>
    </div>
    <div class="container">
      <router-view/>
    </div>
  </div>
</template>

<style>
body {
  margin: 0;
}

.menu {
  height: 48px;
  line-height: 48px;
  background-color: #499ef3;
}

.container {
  width: 980px;
  margin: 0 auto;
}

.menu a {
  display: inline-block;
  color: white;
  text-decoration: none;
  padding: 0 10px;
}


</style>

<script setup>
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

CourseView.vue

<template>
  <div>
    <h1>课程页面</h1>
    数量:{{ size }} | 当前页:{{ page }}
  </div>
</template>


<!--
<script setup>这样就无需在传统的export default{}中写setup函数
而且还不必像以往一样return模版中的数据.
<script>
import {ref} from 'vue'
export default {
  name: "CourseView"
  setup(){
    const nums = ref(0)
    return {nums,}
  }
}
</script>
-->
<script setup>
/* eslint-disable */ // eslint语法提醒
import {ref} from 'vue'
import {useRoute, onBeforeRouteUpdate} from "vue-router"

const route = useRoute()
console.log(route.query)  // {size: '10', page: '11'}
console.log(route.path)   // course
console.log(route.fullPath)  // /course?size=10&page=11


// ★ 获取url中的参数,通常紧接着携带获取到的数据发送ajax请求,但此处我们从简,直接将获取的url中的数据展示在页面上
// or语法 有真为真
const page = ref(route.query.page || 0);
const size = ref(route.query.size || 0);


/* 从其他页面跳转到course页面,没有任何问题.但从course页面切换到course页面时,就会出现问题!!
* 比如,通过点击,url可以从 /course?size=10&page=11 切换到 /course?size=20&page=21
* 对应的course组件,获取到的url中的参数不会从 {size: '10', page: '11'} 变成 {size: '20', page: '21'}
* 如何解决?需要借助onBeforeRouteUpdate
* */
onBeforeRouteUpdate((to, from) => {
  console.log(to)
  console.log(from)
  page.value = to.query.page;
  size.value = to.query.size;
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

HomeView.vue

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>
<script setup>
import {ref} from 'vue'

let message = ref('Hello, world!')

function increment() {
  message.value += '!';
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

NewsView.vue

<script>
export default {
  name: "NewsView"
}
</script>

<template>
  <div><h1>新闻页面</h1></div>
</template>
1
2
3
4
5
6
7
8
9

# URL动态参数 - params

若我想通过id值跳转到指定的 详细页 , 如何实现呢?

url_2

仔细观察运行过程, 控制台的打印, 同一组件间路由切换, 是复用!! (在url传值小节我忽略的问题, 在这里突然注意到了.)
简单来说, 如果导航目的地和当前路由相同, 只有参数发生了改变 (比如从一个用户资料到另一个 /users/1 -> /users/2).
那么就需要 组件复用, 组件复用意味着组件的生命周期钩子函数不会被调用 !
代码里console.log(route.query)和console.log(route.params)都只输出了一次, 就能很好的证明!!
那么我是否也可以认为, let v1 = reactive(route.query) 在页面切换的时候, 也没有重新的执行!
所以就导致了 同一组件间路由切换, 页面数据没有刷新!!
而 onBeforeRouteUpdate 使得我们可以 在页面切换/刷新之前, 可以额外做一些操作.. 比如改变变量的值!!

Ps: 手动改变url, 然后按回车刷新页面是强行发送请求重新加载..(基本不会这么做) 是不会出现上述问题的, 别被误导了..

关键代码如下:

image-20231015152238153

http://192.168.2.106:8080/detail/99?size=40&page=41
route.query  对应 ?size=40&page=41
route.params 对应 99
1
2
3

# 嵌套

嵌套路由指的是在渲染的路由组件页面中包含了下级路由渲染出口(<router-view>),
浏览器的URL 中各段动态路径也按某种结构对应嵌套的各层组件.

路由之间出现嵌套 相当于设置了主菜单和子菜单(类似于后台管理界面,当然不局限于2级,还可以更多级)

一定要先明白一点!! 在项目的app.vue 文件中<router-view>是最顶层的出口, 渲染最高级路由匹配到的组件!!

<div id="app">
  <router-view></router-view>
</div>
1
2
3

可以先看看网上已有的案例, 掘金网站.. 红框的需求在前面我们已经学会如何做, 黄框的需求要实现需要学会 路由嵌套.

image-20231015193304148

我们实现一个简单的版本,效果如下: (主要关注点击一级菜单中"沸点"按钮后, 展示出来的二级菜单!! 务必注意下url的变化!!)

qiantao

如何实现, 代码逻辑如下: (别忘了看截图上面的注释!!)

image-20231015204611904

关于截图中蓝色标注的部分需要单独说一下:

进入http://192.168.2.106:8080/pins后,PinsView.vue中的<router-view/>部分自动显示的是NewView.vue这个最新组件的内容.
如何实现的? 关键代码如下:
1> 有两种方式实现,任选其一即可
   进一步阐述下重定向. 路由配置{ path: '/a', redirect: '/b' }, 指当用户访问 /a时, 路由跳转到b路由, URL 将会被替换成 /b
2> 因为访问/pins页面时,代码会根据方式一或者方式二自动加载到/pins/new页面
   所以在浏览器的控制台会提示 name:'Pins' 简单来说,完全可以不设置它,没有啥用武之地. 我们索性将其注释掉!
{
    path: '/pins',
    // name: 'Pins',
    component: () => import('../views/PinsView.vue'),
    children:[
        {
            path:'',
            // 方式一: 匹配到 /pins后, 后面啥也没加, 默认展示NewView.vue这个子页面
            // component: () => import('../views/NewView.vue'),
            // 方式二: 路由重定向,自动跳转
            redirect:{name:'New'},
        },
        {
            path:'new',
            name:'New',
            component: () => import('../views/NewView.vue'),
        },
        {
            path:'hot',
            name:'Hot',
            component: () => import('../views/HotView.vue'),
        },
        {
            path:'following',
            name:'Following',
            component: () => import('../views/FollowingView.vue'),
        },
    ]
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 路由导航

路由导航分为 声明式导航和编程式导航
前面示例中的 App.vue都是通过router-link使用的是 声明式导航!!
编程式导航 基于 router对象 来实现!

router.push()
  会向history栈添加一个新的记录,所以当用户点击浏览器后退按钮时,则回到之前的 URL !!
router.replace() 
  跟router.push很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样,替换掉当前的 history 记录 !!
  
这篇博客写的挺好的,可阅读下: https://blog.csdn.net/zhouzuoluo/article/details/84874389
1
2
3
4
5
6

ψ(`∇´)ψ 以一个小案例来 回顾下上面vue-router相关的知识点, 并加上编程式导航的使用.

页面 + 对应代码, 截图对比理解.

# 声明式导航

image-20231016162532862

简单点,App.vue/根组件 就是 一开始页面/根页面/"http://localhost:8080/" 展示的内容!!
这里注意几个点:
  1> 点击编程式导航和首页,都展现的是 Home.vue 组件的内容! "Hello World!"
     观察这两次点击,发现其url都是 http://localhost:8080/,其原因,要看index.js中路由的配置!关键在于 redirect 重定向!
  2> App.vue组件中用 声明式导航写了 5个<router-link>
     这5个点击 会将对应组件的模版 渲染到 App.vue的 <router-view/> 的位置!!
    (★ 若是访问了 '/course-info/:courseId' CourseInfo组件也会渲染到 App.vue的 <router-view/> 的位置 !!)
1
2
3
4
5
6
7
# 编程式导航

dao

image-20231016192400949

你可以看到 App.vue 跳转到 CourseView.vue, 然后又跳转到 CourseInfoView.vue
那么跳转过去的组件 加载在哪呢? 加载的位置 在router的index.js文件中就已经写好了!!!
router的index.js文件 可以看出一开始就使用了路由嵌套
const routes = [{},{},..] routes数组中的配置的一个个路由都是 根路由"/" 的子路由.
通过浏览器上url的变化也能够证明!!
(当然配置的一个个路由里还可以用children属性写关联的子路由!都是一样的道理.)
1
2
3
4
5
6
# 回顾嵌套

qian

截图中的逻辑,其实在 嵌套 的小节已经说的很明白了!
再次提出来,是为了说明一点: 
  其实无论是通过 router-link 还是 router对象 跳转过去,对应的组件渲染的位置 在index.js配置文件中写的很明白啦!!
  (★ PinkView.vue中不写<router-view/>的话,New、Hot、Following这三个子路由对应的组件是不会显示的!!)
1
2
3
4

# 示例: 登陆跳转

关于登陆跳转的页面展示, 一般分为两种: 含顶部、不含顶部!!
这两种最主要的区别在于 - 路由嵌套不一样!!

需求: 登陆成功后, 跳转首页.

image-20231016222600769

# 含顶部

lo

没啥好说的, 知识点都是刚学过的, 代码截图如下:

image-20231016210233039

# 不含顶部

简单来说, 就是不能让 登陆路由 跟 资讯、直播 这些路由处于同一级.

ll_2

代码截图如下:

image-20231016220255774

★ 对比分析下: (这个分析过程对单页面的进一步思考理解还蛮重要的!! 有点顿悟的感觉)

vue是单应用/单页面开发, 可以简单理解就是App.vue组件!! 项目不管访问什么地址一直都在展示App.vue!!
既然展示的都是App.vue,那么为啥不同地址呈现的App.vue不一样呢?是因为路由的配置.
根据路由index.js的配置,配置中一级路由对应的组件通通都会渲染到 App.vue的<router-view>处!!
若一级路由有children属性,那么该属性下配置的二级路由都会渲染到当前一级路由对应组件的<router-view>处!!
  
不含顶部和含顶部相比,其实就是多了个MenuView.vue组件,将原本写在App.vue中的写在了该组件里.
App.vue组件里啥也没有,就剩下一个<router-view>!! 
意味着,每次往App.vue的<router-view>加载的组件就是该组件原本的内容.
所以,该登陆跳转的页面就不含顶部啦!!!
1
2
3
4
5
6
7
8
9

# 导航守卫(全局)

有些路由需要登陆后才能访问, 此时就需要导航守卫! - 可以类比于Django中的中间件,其他框架里的拦截器.

需求: 访问的路由需登录才能访问, 若未登录,访问该路由时, 重定向到登陆界面. (这里的登陆跳转不含顶部)
解决: 使用全局的导航守卫, 所有的请求在访问时都会提前执行它!
Ps: 当然还有单页面的导航守卫, 一般开发不会涉及到, 暂不讨论.

shouw

router/index.js 关键代码如下:

const router = createRouter({
    history: createWebHistory(process.env.BASE_URL),
    routes
})

router.beforeEach((to, from, next) => {
    /*
    * to 即将访问的的路由对象
    * from 当前要离开的路由对象
    * next() 继续向后执行,去to的页面
    * next(false) 不跳转,还在当前页面
    * next("/xxx") next({name:"xxx"}) next({path:"/xxx"}) 跳转指定的页面
    * */
    // 白名单 
    // to.name name是路由配置中给路由设置的name
    if (to.name === "Login" || to.name === "Index" || to.name === "Home") {
        next()
        return  // 此处有return,白名单的话不会往后执行的
    }
    let token = sessionStorage.getItem("isLogin");
    if (token) {
        // 登陆成功,往后执行
        next()
    } else {
        // 未登陆,重定向到登陆界面
        next({name: "Login"})
    }
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

记得登陆成功时, 在浏览器的sessionStorage中加入登陆成功的凭证

function doLogin() {
  if (username.value.length > 0 && password.value.length > 0) {
    alert("登陆成功.")
    sessionStorage.setItem('isLogin', "true")  // ★
    router.replace({name: 'Home'})
  } else {
    alert("用户名或密码错误.")
  }
}
1
2
3
4
5
6
7
8
9

Vue-cli
插件的使用(2)

← Vue-cli 插件的使用(2)→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式