前端技术栈--vuecli页面固定思路解密,与vue-router技术栈信息

沉淀一下对vue-cli的基本认识

图片是一个基本的,使用vue-cli开发的界面

这里,我基于这个界面讲解几个疑惑点

这里在做一个前提介绍,一个vue文件

在我看来就是一个div集合了css,和js的操作。

的一小块内容。

1.同样都是vue页面,如何做到有些vue文件是固定的 有些vue文件是可以变化的。

1.1固定页面的实现原理

放两张图。

原理讲如下:

非常好的问题!App.vue 是整个应用的根组件,是所有组件的"老祖宗"。让我用层级关系帮你理清楚:

完整的组件层级结构

vue 复制代码
<!-- App.vue - 最顶层容器 -->
<template>
  <div id="app">
    <!-- 这里只有最基础的全局内容 -->
    <router-view />  <!-- 关键:路由视图的"根出口" -->
  </div>
</template>

实际的渲染层级:

复制代码
浏览器挂载点 (#app)
    ↓
App.vue(根组件,永远存在)
    ↓
<router-view />(App.vue里的第一个路由出口)
    ↓
根据当前URL决定显示什么:
    - 如果URL是 /login → 显示 Login.vue
    - 如果URL是 / 或 /dashboard → 显示 Layout.vue
    ↓
Layout.vue(布局组件)
    ↓
Layout里的 <router-view />(第二个路由出口)
    ↓
显示具体的页面组件(Dashboard.vue、Users.vue等)

具体代码示例:

1. App.vue - 唯一的根组件

vue 复制代码
<!-- App.vue -->
<template>
  <div id="app">
    <!-- 可以放一些全局的东西,比如加载进度条、全局提示等 -->
    <GlobalLoading />
    <GlobalToast />
    
    <!-- 最关键:路由的根出口 -->
    <router-view />
  </div>
</template>

2. 路由配置体现层级

javascript 复制代码
// router/index.js
const routes = [
  {
    path: '/login',
    component: () => import('@/views/Login.vue')
    // 登录页会直接替换 App.vue 里的 router-view
  },
  {
    path: '/',
    component: Layout,  // Layout会替换 App.vue 里的 router-view
    children: [
      {
        path: 'dashboard',
        component: () => import('@/views/Dashboard.vue')
        // Dashboard会替换 Layout 里的 router-view
      }
    ]
  }
]

渲染流程可视化:

复制代码
URL: /login
App.vue 渲染:
┌─────────────────────────┐
│      App.vue            │
│  ┌───────────────────┐  │
│  │  router-view      │  │
│  │  ┌─────────────┐  │  │
│  │  │ Login.vue   │  │  │
│  │  └─────────────┘  │  │
│  └───────────────────┘  │
└─────────────────────────┘

URL: /dashboard
App.vue 渲染:
┌─────────────────────────┐
│      App.vue            │
│  ┌───────────────────┐  │
│  │  router-view      │  │
│  │  ┌─────────────┐  │  │
│  │  │ Layout.vue  │  │  │
│  │  │ ┌─────────┐ │  │  │
│  │  │ │router-view│ │  │  │
│  │  │ │Dashboard │ │  │  │
│  │  │ └─────────┘ │  │  │
│  │  └─────────────┘  │  │
│  └───────────────────┘  │
└─────────────────────────┘

App.vue 的核心作用:

  1. 唯一的根组件 - main.js 中挂载的就是它

    javascript 复制代码
    // main.js
    new Vue({
      render: h => h(App)  // App作为根组件
    }).$mount('#app')
  2. 提供最外层的路由出口 - 决定显示登录页还是后台布局

  3. 放置全局性的东西

    • 全局样式(不用在每个组件重复写)
    • 全局加载进度条
    • 全局消息提示
    • 权限控制守卫

对比理解:

  • App.vue:整个房子的地基和框架,永远不变
  • Layout.vue:客厅的布局(沙发、电视墙固定)
  • views/xxx.vue:茶几上的摆件(可以随时更换)
  • components/xxx.vue:固定的家具(沙发、电视)

2.siber里面的两个问题

1.为什么可以渲染路由信息

2.为什么点击可以实现路由效果

1. 这个组件是如何渲染出来的?

渲染流程(从根到叶)

vue 复制代码
<!-- App.vue (根组件) -->
<template>
  <div id="app">
    <!-- 路由出口 -->
    <router-view />
  </div>
</template>
javascript 复制代码
// router/index.js (路由配置)
const routes = [
  {
    path: '/',
    component: Layout,  // 访问根路径,渲染Layout组件
    children: [
      // ... 子路由
    ]
  }
]
vue 复制代码
<!-- Layout.vue (布局组件,包含侧边栏+内容区) -->
<template>
  <div class="layout">
    <!-- 关键点!SideMenu组件被硬编码在这里 -->
    <SideMenu />
    
    <div class="main-content">
      <!-- 这里是动态内容的出口 -->
      <router-view />
    </div>
  </div>
</template>

<script>
import SideMenu from './SideMenu.vue'  // 导入你写的菜单组件

export default {
  components: {
    SideMenu  // 注册组件
  }
}
</script>

渲染过程:

  1. main.jsApp.vue 挂载到 #app 容器
  2. App.vue 中的 <router-view/> 根据 URL 决定显示什么
  3. 当 URL 是 //dashboard 时,路由匹配到 Layout 组件
  4. Layout.vue 渲染时,硬编码<SideMenu /> 标签
  5. SideMenu 组件按照你的模板代码,渲染出完整的菜单 HTML

关键点: 你的 SideMenu 组件不是通过路由动态渲染的,而是直接在 Layout.vue硬编码引入 的,所以它会永远固定显示在左侧。


2. 为什么点击可以实现页面跳转?

核心机制:Vue Router 的编程式导航

你在代码中做了两件事,共同实现了跳转:

① 点击事件绑定
vue 复制代码
<el-menu-item @click="handleMenuClick('/article/list')">
  文章列表
</el-menu-item>
② 跳转逻辑
javascript 复制代码
methods: {
  handleMenuClick(path) {
    this.$router.push(path)  // 关键代码!
  }
}

this.$router.push() 的工作流程

javascript 复制代码
// 当你点击"文章列表"时:
handleMenuClick('/article/list')
  ↓
this.$router.push('/article/list')
  ↓
// Vue Router 内部做了这些事:
// 1. 改变浏览器 URL(不刷新页面,使用 history.pushState)
// 2. 查找路由配置,找到 path: '/article/list' 对应的组件
// 3. 触发重新渲染,将目标组件显示到 <router-view/> 中
// 4. 更新 $route 对象,触发你写的 watch 监听器

对比传统 Web 应用

传统 <a> 标签 你的 @click + $router.push
<a href="/article/list"> @click="handleMenuClick('/article/list')"
浏览器刷新页面 无刷新,单页应用体验
重新请求 HTML、CSS、JS 只替换 <router-view/> 的内容
丢失所有 Vue 状态 保持状态(比如菜单的激活状态)

为什么不用 <router-link>

你可能会问:为什么不用更简洁的 <router-link>

vue 复制代码
<!-- 更 Vue 的方式 -->
<router-link to="/article/list">
  <el-menu-item>文章列表</el-menu-item>
</router-link>

你当前用 @click + $router.push 的原因:

  • el-menu-item 是 Element UI 组件,包裹 <router-link> 可能出现样式冲突
  • 需要额外处理 activeIndex(激活状态),用 @click 可以统一控制
  • 更灵活的跳转逻辑(比如跳转前可以做权限判断)
javascript 复制代码
handleMenuClick(path) {
  // 可以在跳转前做各种事情
  if (this.hasPermission(path)) {
    this.$router.push(path)
  } else {
    this.$message.error('无权限访问')
  }
}

可视化总结

复制代码
你的 SideMenu 组件
    │
    ├── 渲染方式:硬编码在 Layout.vue 中(不是路由决定的)
    │   └── Layout.vue 渲染 → 加载 SideMenu → 生成 DOM
    │
    └── 跳转原理:编程式导航
        ├── 点击菜单 → 触发 @click
        ├── 调用 this.$router.push(path)
        ├── Vue Router 改变 URL 和视图
        └── 右侧 <router-view/> 内容更新

一句话总结:

  • 渲染Layout.vue 直接引用了你的组件,所以它永远在左侧
  • 跳转this.$router.push() 告诉 Vue Router 切换页面,但菜单本身不动

3.views文件

为什么使用这个方法 this.$router.push('/article/list') ,可以实现页面切换

非常好的问题!这触及了 Vue Router 的核心原理。让我用图解+代码的方式彻底讲清楚 this.$router.push() 为什么能实现页面切换。

核心答案:因为 Vue Router 维护了一个响应式的当前组件

1. 先理解 $router$route 是什么

javascript 复制代码
// Vue Router 安装时,会在每个 Vue 实例上注入两个对象:
this.$router  // 路由器实例,包含 push(), replace(), go() 等方法
this.$route   // 当前路由信息,包含 path, params, query, matched 等

2. 关键原理:<router-view> 是一个响应式组件

vue 复制代码
<!-- 这是 Vue Router 内置的 <router-view> 组件的简化版原理 -->
<template>
  <component :is="currentComponent" />
</template>

<script>
export default {
  computed: {
    currentComponent() {
      // 核心!这个计算属性依赖 this.$route
      // 当 this.$route 变化时,Vue 会重新计算并重新渲染
      const component = matchRoute(this.$route.path)
      return component
    }
  }
}
</script>

3. push() 执行后发生了什么?(完整流程)

javascript 复制代码
// 你调用这个方法
this.$router.push('/article/list')

// === Vue Router 内部执行流程 ===

// 第1步:更新浏览器 URL(不刷新页面)
window.history.pushState({}, '', '/article/list')

// 第2步:更新内部维护的响应式数据
this.currentRoute = reactive({  // 这是一个响应式对象
  path: '/article/list',
  params: {},
  query: {},
  matched: [...]  // 匹配到的路由记录
})

// 第3步:触发响应式更新
// 因为 $route 是响应式的,而 <router-view> 依赖它
// 所以 Vue 会重新执行 <router-view> 的 render 函数

// 第4步:重新匹配组件
const newComponent = routeTable['/article/list']  // 找到 ArticleList 组件

// 第5步:重新渲染
// <router-view> 把旧的组件替换成新的组件

4. 可视化流程图

复制代码
你点击菜单
    ↓
this.$router.push('/article/list')
    ↓
┌─────────────────────────────────────────┐
│  Vue Router 内部                          │
│  ┌────────────────────────────────────┐  │
│  │ 1. 改变 URL (history.pushState)    │  │
│  │ 2. 更新响应式数据 $route           │  │
│  │    - path: '/article/list'         │  │
│  │    - component: ArticleList        │  │
│  └────────────────────────────────────┘  │
└─────────────────────────────────────────┘
    ↓
Vue 检测到响应式数据变化
    ↓
重新执行 <router-view> 的 render
    ↓
把 ArticleList 组件渲染出来
    ↓
页面切换完成(无刷新!)

5. 用简单代码模拟核心原理

javascript 复制代码
// 这是一个简化版的 Vue Router 实现
class SimpleRouter {
  constructor(routes) {
    this.routes = routes
    // 核心!创建一个响应式的当前路由对象
    this._currentRoute = Vue.observable({
      path: window.location.pathname,
      component: null
    })
  }
  
  push(path) {
    // 1. 改变浏览器 URL
    window.history.pushState({}, '', path)
    
    // 2. 找到对应的组件
    const route = this.routes.find(r => r.path === path)
    
    // 3. 更新响应式数据(这会触发视图更新!)
    this._currentRoute.path = path
    this._currentRoute.component = route.component
  }
  
  get route() {
    return this._currentRoute
  }
}

// 在你的组件中
this.$router = new SimpleRouter(routes)

// <router-view> 简化版
Vue.component('router-view', {
  render(h) {
    // 依赖 this.$router.route.component
    // 当它变化时,Vue 自动重新渲染
    return h(this.$router.route.component)
  }
})

6. 验证:watch 监听 $route 变化

你之前写的代码中就有证据:

javascript 复制代码
watch: {
  '$route'(to) {  // ← 这个监听器能工作,说明 $route 是响应式的
    const path = to.path
    if (path.startsWith('/article')) {
      this.activeIndex = '2'
    }
    // ...
  }
}

如果 $route 不是响应式的,这个 watch 永远不会触发!

7. 完整的数据流

复制代码
┌─────────────────────────────────────────────────────────┐
│                        你的代码                           │
│  this.$router.push('/article/list')                     │
└────────────────────┬────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────────────┐
│                 Vue Router 内部                          │
│  ┌───────────────────────────────────────────────────┐  │
│  │  transitionTo('/article/list')                    │  │
│  │    ↓                                              │  │
│  │  更新 _route 响应式对象                            │  │
│  │    ↓                                              │  │
│  │  Object.assign(this._route, {                    │  │
│  │    path: '/article/list',                        │  │
│  │    matched: [Layout, ArticleList]                │  │
│  │  })                                               │  │
│  └───────────────────────────────────────────────────┘  │
└────────────────────┬────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────────────┐
│                 Vue 响应式系统                           │
│  检测到 this._route 变化                                 │
│    ↓                                                    │
│  通知所有依赖 this._route 的组件重新渲染                  │
└────────────────────┬────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────────────┐
│              <router-view> 组件                         │
│  重新执行 render() 函数                                  │
│    ↓                                                    │
│  从 this.$route.matched 获取新组件                       │
│    ↓                                                    │
│  渲染 ArticleList 组件                                   │
└─────────────────────────────────────────────────────────┘

总结一句话

this.$router.push() 能切换页面,是因为它更新了一个响应式的 $route 对象,而 <router-view> 组件依赖这个对象来决定渲染哪个组件,Vue 的响应式系统自动完成了视图更新。

这就是 Vue 的数据驱动视图 思想的最佳体现:你不需要手动操作 DOM,只需要改变数据($route),视图(<router-view>)会自动更新。

相关推荐
hresh2 小时前
两个 Chrome 窗口各 20 多个 tab 后,我把 tab-out 改成了更顺手的 TabNest
前端·chrome·后端
shadowcz0072 小时前
CHI 2026 归来:AI/LLM 正在重写人机交互的底层语法
前端·人工智能·html·人机交互
Moment2 小时前
面试官:LangChain中 TS 和 Python 版本有什么差别,什么时候选TS ❓❓❓
前端·javascript·后端
JarvanMo2 小时前
SINT能否取代GetX?
前端
Mintopia2 小时前
深入理解计算机架构:从硬件到软件的桥梁
前端
大尚来也2 小时前
HTTPS的性能优化:从握手延迟到会话复用
前端
尘埃落定wf2 小时前
LangChain AgentExecutor 完全指南:ReAct循环+Memory+LLM实战
前端·javascript·react.js
数智前线2 小时前
百灵大模型认领“Elephant”:Ling-2.6-flash定价每百万token 0.1美元
前端·javascript·microsoft
weixin199701080162 小时前
《采购与招标商品详情页前端性能优化实战》
前端·性能优化