main.js
import { createApp } from 'vue'
// import App from './App.vue'
// 导入路由实例
import Router from './routes'
const app = createApp({});
// app.use() { install(app, options){ 肯定这个 router 实例 对传递的参数 app 进行了某些设置 }}
app.use(Router);
// console.log(app.config.globalProperties.$router === Router); true
// console.log(app.config.globalProperties.$route); 这个对象当中是不是都空的
// <router-link> 这个自定义标签了 customElements 创建出来的自定义标签, @click 当点击时,除了切换相对应的子组件外
// 解析当前 window.location.pathname 中的 字符串,将解析出来的相关属性 挂载到 route 这个对象上。
app.mount('#app');
// createApp(App).mount('#app')
自己创建一个js文件,命名为routes.js
// 引入 Vue 路由模块
import { createRouter, createWebHistory } from 'vue-router'
// 引入我们自己所需要的 子组件块
// 子组件,导入出来之后,好像并不是一个 单纯性的对象
import HomeComponent from "./components/HomeComponent.vue";
import AboutComponent from "./components/AboutComponent.vue";
import UserComponent from "./components/UserComponent.vue";
import UserClassComponent from "./components/UserClassComponent.vue";
// 定义一个路由配置列表
const routes = [
{ path: '/', name: 'home', component: HomeComponent },
{ path: '/about', name: 'about', component: AboutComponent },
{ path: '/user/:id', name: 'user', component: UserComponent },
{ path: '/user/:id/school/:class_id', name: 'user_class', component: UserClassComponent },
// 更深层次的路由,它可以访问 /user/:id 也可以 带有它的
// 当前学校 /user/:id/school/:class_id 它会传递两个动态参数
]
// 3、创建了一个 类似于 插件的 路由实例
const router_app = createRouter({
// 路由实例创建时提供的配置项
history: createWebHistory(),
routes
});
// 4 将创建的路由实例 导出
export default router_app
创建两个无关紧要的子组件 HomeComponent.vue & AboutComponent.vue
HomeComponent.vue
<template lang="pug">
div HomeComponent
</template>
<script>
import Router from '../routes'
export default {
name: "HomeComponent",
// mounted()
// {
// // this.$router 它就是我们使用 createRouter 创建出来的 router_app
// console.log('mounted', this.$router);
// // this.$route 它是一个被解析后的路由对象。
// console.log('mounted', this.$route);
// }
}
</script>
<script setup>
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const Router = useRouter();
const Route = useRoute();
// console.log('Router:', Router);
// console.log('Route:', Route);
// 通过 this.$route 与 使用 useRoute 之间的区别, this 获取的 $route 它是一个普通对象
// 使用 useRoute 获取的对象是一个 Proxy 响应对象
// 创建一个计算属性
const username = computed(() => Route.params.username)
// 创建一个方法
function goToDashboard()
{
// if(isAuth)
}
</script>
<style scoped>
</style>
AboutComponent.vue
<template lang="pug">
div AboutComponent
</template>
<script>
export default {
name: "AboutComponent",
}
</script>
<style scoped>
</style>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app">
<p>#app:</p>
<!-- router-view 区域外为公共区域,比如菜单 -->
<p><router-link to="/">Go to Home</router-link></p>
<p><router-link to="/about">Go to About</router-link></p>
<p><router-link to="/user/10001">Go to User/10001</router-link></p>
<p><router-link to="/user/10002/school/505">Go to User/10002/School/505</router-link></p>
<p><router-link to="/user/10005/school/701">Go to User/10005/School/701</router-link></p>
<p>发现一个小问题(暂时的问题): 在相同的路渲染的子组件下,传递不同参数 渲染 相同的 Component 子组件将不自动更新 update.</p>
<h4>参数类型:</h4>
<ol>
<li>我们现在解析是 由 URL路径所传递的 参数. 参数是URL地址中的一部分.</li>
<li>通过 get 方法所传递的参数 ?xxx=xxx&xx=xx 特点是 以 ? 开头 以 & 来进行链接, 它是完全在地址栏暴露的.</li>
<li># 开头的 锚点参数 页面跳转之后, 直接到跳转到 #xxx, id 为 xxx 的位置上.</li>
</ol>
<p>url 参数 通过使用 :xxx 定义动态参数,以 / 目录层级符号 解析分段 在 $route当中 使用 params 这个参数来进行传递.</p>
<p>get参数</p>
<router-view></router-view>
<!-- router-view 区域为动态区域,用来切换页面,与 window.location.pathname 结合,动态切换子组件 -->
<!-- 路由插件当中定义出来的两个 CustomElement -->
<!-- customElements( defineCustomElement({ Vue app Options }) ) -->
<!-- 1、 router-link 其实就是创建 一个 a 标签 填写合适的 path 并且 阻止 event.preventDefault(); 阻止其默认行为。 -->
<!-- 2、 渲染子组件,当前的 customElement 被定义为一个 动态子组件. -->
<!-- 除了去定义这些 动态的子组件的公共属性 app.config.globalProperties.$router 定义为当前 router 的实例 -->
<!-- router 实例对应 一个 Vue app 现在我们还不清楚 component 的 app 从哪访问,如果能访问到 那么子组件也可以对应一个 router ,但是它是没意义的。 -->
<!-- 因为它和本地的 window.location.pathname 配合是没有任何意义的。 想法: 一个站点(全部页面) 是定义一个app其它全部使用组件,还是 每一个页面使用一个app呢? -->
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
修改vite.congig,js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
alias: { 'vue': 'vue/dist/vue.esm-bundler.js' }
})
基本路子跑通了……
涉及到同一个组件的复用
创建两个子组件
userComponent.vue
<template lang="pug">
p 在这个位置测试一下什么是动态路由
p 从现在开始,我才慢慢的明白 什么叫 #[strong "前后端分离"]
p 以前后端负责的路由 开始交于前端进行处理,前端页面 采用单独服务器提供服务,后端仅提供 API 接口。
p 路由 router 是发送给 服务器, 服务器根据前前拆解的路径进行渲染
p 现在 路由 router 根据 本地的 window.location.pathname 来进行处理,不同的路径 对应不同的 Vue子组件.
p 以数据的形式传递所有的 页面信息,然后统一由本地进行 VNode 解析,对于填充性的数据,我们在由Vue通过 向数据服务器请求 来获取.
hr
p 即然是一个路由,那么就必须要具有动态参数,动态的参数的写法就是 :xxx
p 路由中的 /user/:id 匹配 a 标签中的 /user/10001 那么 router模块就帮我们把 /user/后边的字符串解析为一个动态变量.
p 通过对 路由的动态参数解析,读取到当前访问路径中的用户ID: {{ user_id }}
</template>
<script>
export default {
name: "UserComponent"
}
</script>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute();
// console.log(route); // 由路模块 router 是用来解析当前浏览器中的 网址栏中的 地址的.
// 对应的就是 window.location.pathname
// 对某种特定的格式进行解析。
// route 就是对当前 这个路由解析以后的 结果对象。
// 我们就可以通过 route 来查看 当前路由解析 的结果。
// 以上的描述 整体来看获取一个 router 的基本功能:
// 1、 对特定的路由进行解析,根据解析的结果 渲染对应的 动态子组件
// 2、 将解析后的结果,以 route 的方式挂载到 this(vm对象)的属性上,以便我们从子组件中去读取对当前 浏览器地址的 解析结果。
// route.params route路径解析后的结果 params 参数 就是 路径解析后的 参数
// console.log(route.params); // 它将输出一个 参数的 对象 匹配路由中 如果存在 动态参数(:xxx) 那么这个对象为: { xxx: 值 }
const user_id = route.params.id;
// 直接发送 axios 请求,向 数据服务器 获取当前 id下的 详细 用户信息,并解析 到 template 模板中。
// 以前 服务器解析某一个文件 / 这个杠的意思是 目录层级
// 到现在为止 虽然 web 技术已经非常普通的 动态了,但是这个 / 杠 仍然代表 目录层级意思
// 在同一个 url 当中,我们可以设置各种不同的层级.
</script>
<style>
html
{
font-size: 14px;
}
</style>
<style scoped>
</style>
UserClassComponent.vue
<template lang="pug">
h3 User 带有 Class 动态参数的子组件
p 路由的动态参数解析结果:
ul
li 用户id: {{ page_data.user_id }}
li 班级id: {{ page_data.class_id }}
p 同一个路由使用不同的参数进行访问,虽然参数不同,但是页面上的 动态子组件是一样的.
p 默认情况下,同一个子组件, url 参数变化,子组件是不会去调用它的生命周期钩子的. 对于同一个子组件的 使用 相比 销毁再创建,那就不如 复用它了.
</template>
<script>
export default {
name: "UserClassComponent",
mounted() {
// 使用 data 需要加 value 么?
// 不需要了 自动浅解构了.
// 提升当前作用域 apply
// console.log(this.$route); // 普通对象
}
}
</script>
<script setup>
import { watch, ref, reactive } from 'vue'
import { useRoute, onBeforeRouteUpdate } from 'vue-router'
const route = useRoute();
const page_data = ref({user_id: route.params.id, class_id: route.params.class_id});
console.log(route); // proxy
// set 拦截器当中添加一个 副作用函数
// let page_data_example = reactive({ user_id: route.params.id, class_id: route.params.class_id });
// const x = { a: 1, b: 2};
// ref { value: 12321 } 大盒子的地址 写在一张名片上给别人
// const { id: user_id, class_id } = route.params;
watch(() => ({ user_id: route.params.id, class_id: route.params.class_id }), (newValue) => {
page_data.value = newValue;
// 去更新一个 reactive 对象
// page_data_example = newValue;
// page_data_example 中存储的是一个名片 这个名片指向的地址是 一个 proxy 对象
// 如果我把这个 page_data_example = newValue newValue 从 watch source 这个函数中来的. 所以我们就把这个 page_data 中存储的 这个proxy对象(用于响应页面更新的对象)给替换掉了
// 替换成一个 watch source 侦听函数中 创建的 普通对象了.
// 那怎么更新啊?
// page_data_example.value.user_id = newValue.user_id;
// page_data_example.value.class_id = newValue.class_id;
// 其实说实话,它两个值更新时间很短, 所以说 proxy 代理它也会检测 update 子组件的刷新(更新)频率,在两个定义 很短的时间内,它决对不会 重复更新两次.
// 但是这么写 真没必要. 如果你传递10个参数呢?
});
// 为什么访问 url 指向 相同的子组件,它不更新.
// 子组件更新 原理是什么啊? 有相关数据发生改变 相关数据必须是一个 响应式对象(proxy对象) 因为这个对象上有一个 get\set 拦截器 当某一个数据发生set 设置值 这种情况发生的时候
// 它就要知道,这个相关的数据 发生了改变 我的页面也跟着更新。
// proxy 里边的 set() 这个拦截器 里边一定有这么一句话 set() { 清除现在 |子组件| 中的所有VNode元素,执行 render函数 创建新的VNode元素 }
// $route 这个属性是从哪来的?
// vue 里边来的?
// 它是在 app.use(route_app) 时,在 app.config.globalProperties 上定义的.
// 定义的时候,它是有一个固定的对象的. 里边的数据是随着 window.location.pathname 发生改变,将解析后的 数据挂载到自身属性上。
// $route 它不是一个新对象,它是在 app.use() 期间就已经挂载上了。
// 为了让这个$route 与后面我们挂载上的 component 子组件之间产生联系,那我们就必须使用一个 侦听函数去 侦听它。
// 在这个变量发生改变的时候,我们就 更新当前子组件自身。
// onBeforeRouteUpdate((to, from) => {
// // to newValue
// // from oldValue
// // 在这个 导航守卫 功能里边,你也搞不清楚 是哪一个具体的参数 发生变化.
// // page_data.value =
// })
// script setup 是在组件创建 create beforeCreated 这个阶段执行的.它将执行一次 就停掉了.
// 后边的更新 跟它也没关系了.
// 要么就设置一个监听函数 后期这个值如果发生变化那么我们就对其进行响应,否则 就设置一个 导航守卫
// 通过对这个名称进行 理解 beforeRouteUpdate 它是不是就是绑我们设置了一个 watch 监听函数呢?
</script>
<style scoped>
</style>
代码纪录结束,知识点更新
router-view 区域为动态区域,用来切换页面,与 window.location.pathname 结合,动态切换子组件
路由插件当中定义出来的两个 CustomElement
customElements( defineCustomElement({ Vue app Options }) )
1、 router-link 其实就是创建 一个 a 标签 填写合适的 path 并且 阻止 event.preventDefault(); 阻止其默认行为。
2、 渲染子组件,当前的 customElement 被定义为一个 动态子组件.
除了去定义这些 动态的子组件的公共属性 app.config.globalProperties.$router 定义为当前 router 的实例
router 实例对应 一个 Vue app 现在我们还不清楚 component 的 app 从哪访问,如果能访问到 那么子组件也可以对应一个 router ,但是它是没意义的。
因为它和本地的 window.location.pathname 配合是没有任何意义的。