惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
有赞技术团队
有赞技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Threat Research - Cisco Blogs
L
LangChain Blog
Simon Willison's Weblog
Simon Willison's Weblog
Project Zero
Project Zero
Latest news
Latest news
S
Schneier on Security
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
C
Check Point Blog
IT之家
IT之家
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
G
Google Developers Blog
T
Tor Project blog
T
Threatpost
D
DataBreaches.Net
博客园 - 【当耐特】
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Troy Hunt's Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
NISL@THU
NISL@THU
P
Privacy & Cybersecurity Law Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
博客园_首页
S
Securelist
T
The Exploit Database - CXSecurity.com
Last Week in AI
Last Week in AI
量子位
U
Unit 42
Know Your Adversary
Know Your Adversary
Hugging Face - Blog
Hugging Face - Blog
S
Security Affairs
Google Online Security Blog
Google Online Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
Webroot Blog
Webroot Blog
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
N
News and Events Feed by Topic
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志

Aimee's Blog

微服务与服务拆分:何时拆、怎么拆 异步与事件驱动架构:把协作从「打电话」改成「发消息」 高可用设计:怎么让系统尽量不宕机 可扩展性设计:怎么让系统加机器就能扛更多 缓存架构:多级缓存怎么搭 高并发三板斧:限流、熔断、降级 架构设计到底在设计什么 —— 从单体到微服务的演进 服务成本账:一个服务一个月烧多少钱 可观测性:线上出问题怎么查 API 设计:好接口长什么样 消息队列:为什么要 MQ,以及丢失、重复、顺序怎么破 查询优化:慢查询怎么治 —— 索引 + 预聚合 缓存:为什么快、三大坑、和数据库怎么保持一致 存储与基建选型 —— 传统业务 vs AI 大模型时代 权限系统怎么设计?—— 从 RBAC 到 Google Zanzibar 鉴权怎么落地?—— 常见业务场景的方案选型与避坑 JWT、OAuth、Token 刷新 —— 一个全栈工程师的鉴权入门笔记 我把跑了五年的旧博客升级到了 3.0 大模型 AIGC 满天飞 推荐一些学习和资料网站 2024 冒个泡 冒个泡 阿里云新机器安装 自定义配置 vue 的 webpack.config.js 从输入url到页面展示 React API 使用demo 欢迎加入 aimee前端技术交流群 github actions 自动化部署 很久以前的美食美荟 无穷之路纪录片还不错哦 vue 模板编译和组件化 vue2 响应式原理 vue2 虚拟DOM原理 vue2 源码解析-初始化 防抖和节流 Proxy 和 Object.defineProperty git rebase
vue2.0 router及简易实现
Aimee · 2021-12-28 · via Aimee's Blog

分类

hash

  • URL中 # 后面的内容作为路径地址
  • hash的模式是基于锚点,以及onhashchange 事件
  • 根据当前路由地址找到对应组件重新渲染

history

  • history 模式是基于html5中的history api
  • history.pushState() ie10 以后才支持
  • history.replaceState()
  • 通过history.pushState()方法改变地址栏
  • 监听popstate 事件
  • 根据当前路由地址找到对应组件重新渲染

服务端配置history

express配置

const path = require('path')
const history = require('connect-history-api-fallback')
const express = require('express')

const app = express()
// 注册处理history 模式的中间件
app.use(history())
// 处理金泰资源的中间件,网站根目录 ../web
app.use(express.static(path.join(__dirname, '../web')))

app.listen(3000, ()=>{
 console.log('服务器开启,端口:3000')
})

nginx 配置

server{
 ...
 location / {
 	 root html;
   index index.html index.html;
   try_files $uri $uri/ index.html;
 }
 ...
}

history 实现

简易版说明

  • 只支持routes 参数
  • 只支持router-link 和router-view 组件
  • 不支持push replace 等功能

实现

  • 写一个VueRouter class类
  • 提供静态 install 方法
    • 接受一个Vue参数
    • 判断当前 router是否已经被安装
    • 把Vue的构造函数记录在全局
    • 把创建Vue的实例传入的router对象 注入到Vue实例中
      • 使用mixin的方式注入
      • 在beforeCreate 钩子中注入
  • 提供构造函数constructor 处理参数和初始化
    • 初始化参数options
    • 将routes存放在routeMap中
    • 记录当前的current, 并设置为响应式
      • 通过Vue.observable来实现
    • 初始化组件信息
  • 处理组件 router-link 和router-view 注册为全局组件
    • router-link
      • 处理router-link 组件 接受一个参数to
      • router-link即为a标签,to即为href的参数
      • 拦截a标签的onClick事件,将history中pushState 记录跳转记录
      • 设置当前的current为to的值
    • router-view
      • 处理router-view 组件
      • router-view组件,用于展示当前路由的对应的component内容
      • 获取当前的current,通过routerMap获取对应的component
      • render 函数中return component vnode
      • 由于current 是响应式的,router-view中的render 会实时 获取最新的component来渲染
  • 处理监听事件
    • 由于router-link中 点击的时候,在history中添加了state,浏览器会根据hsitory的state自动处理前进和后退箭头
    • 箭头浏览器的前进后退事件及popstate,重新设置对应的current
    • 触发了router-view中component的渲染
let _Vue = null;
export default class VueRouter {
  static install(Vue) {
    //1 判断当前插件是否被安装
    if (VueRouter.install.installed) {
      return
    }

    VueRouter.install.installed = true
    //2 把Vue的构造函数记录在全局
    _Vue = Vue
    //3 把创建Vue的实例传入的router对象注入到Vue实例
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
        }
      },
    })

  }
  constructor(options) {
    // 初始化参数
    this.options = options;
    // 将routes 存放在routeMap中
    this.routeMap = {}
    // 记录当前的current,并设置为响应式
    this.data = _Vue.observable({
      current: '/'
    })
    this.init()
  }
  init() {
    this.createRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }
  // 创建routeMap的数据
  createRouteMap() {
    this.options.routes.forEach(item => {
      this.routeMap[item.path] = item.component
    })
  }
  // 处理组件
  initComponent(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        console.log('this.$slots.default', this.$slots.default)
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander(e) {
          e.preventDefault();
          history.pushState({}, '', this.to)
          this.$router.data.current = this.to
        }
      }
    })


    Vue.component("router-view", {
      render: (h) => {
        const cm = this.routeMap[this.data.current]
        return h(cm)
      }
    })
  }
  // 监听事件 替换的current
  initEvent() {
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
  }
}

hash实现

简易版说明

  • 只支持routes参数
  • 只支持router-link和router-view组件
  • 不支持push replace等功能

实现

  • 和history实现整理类似, 可以继续使用history的模式
  • 或者通过hashchange监听路由变化,设置current的值
 window.addEventListener('hashchange', () => {
   this.data.current = window.location.hash
 })
let _Vue = null;
export default class VueRouter {
  static install(Vue) {
    //1 判断当前插件是否被安装
    if (VueRouter.install.installed) {
      return
    }

    VueRouter.install.installed = true
    //2 把Vue的构造函数记录在全局
    _Vue = Vue
    //3 把创建Vue的实例传入的router对象注入到Vue实例
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
        }
      },
    })

  }
  constructor(options) {
    // 初始化参数
    this.options = options;
    // 将routes 存放在routeMap中
    this.routeMap = {}
    // 记录当前的current,并设置为响应式
    this.data = _Vue.observable({
      current: '#/'
    })
    this.init()
  }
  init() {
    this.createRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }
  // 创建routeMap的数据
  createRouteMap() {
    this.options.routes.forEach(item => {
      this.routeMap[item.path] = item.component
    })
  }
  // 处理组件
  initComponent(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander() {
          this.$router.data.current = this.to
        }
      }
    })


    Vue.component("router-view", {
      render: (h) => {
        const cm = this.routeMap[this.data.current]
        return h(cm)
      }
    })
  }
  // 监听事件 替换的current
  initEvent() {
    // window.addEventListener('popstate', () => {
    //   this.data.current = window.location.hash
    // })

    window.addEventListener('hashchange', () => {
      console.log(window.location)
      this.data.current = window.location.hash
    })

  }
}