0625-vueRouter

102 阅读4分钟

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 配合是没有任何意义的。