Vue生态及实践 - Vue Router(1)

news2024/12/28 14:02:05

目录

路由

Vue-Router

Mode

Hash Mode

HTML5 Mode

代码实操

目标是替换掉原版的vue-router


路由

路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。

                                                                                                                        ——wikipedia

Vue-Router

传统web开发路由是后端控制的

随着ajax技术的普及页面无刷新,有了更好的用户体验

在单页面应用中路由开始由后端走向前端,前端需要自己管理路由了

Mode

监听浏览器History变化

window中有2个监听事件:

  • onhashchange:监听url中的hash变化
  • onpopstate: 监听history栈的改变

Hash Mode

指url中#开始到后面的部分

如:http://www.baidu.com#/hash【#/hash】

当url中的hash改变时页面不会刷新,但是会触发onhashchange事件

// 监听
window.onhashchange = function() {
    console.log(location.hash);
}
// 修改
location.hash = '/anotherhashtag'
// /anotherhashtag

HTML5 Mode

// 监听
window.addEventListener("popstate", () => {
    console.log(window.location.pathname);
}
// 触发时机:
// 点击浏览器前进、后退按钮
history.back() // 后退
history.forward() // 前进
history.go() // 前往历史栈索引
// 下面个方法不会触发popstate事件
history.pushState({},"title","anotherpage.html"); // 添加
history.replaceState({},"title","anotherpage.htm"); // 更新最后一条记录

代码实操

// cmd 中安装一个vue-router
npm add vue-router
// pages/Foo.vue
<template>
  <div>Foo</div>
</template>
<script>
export default {
  beforeRouteEnter(to, from, next) {
    console.log("foo::beforeRouteEnter");
    next();
  },
  beforeRouteUpdate(to, from, next) {
    console.log("foo::beforeRouteUpdate");
    next();
  },
  beforeRouteLeave(to, from, next) {
    console.log("foo::beforeRouteLeave");
    next();
  }
};
</script>
// pages/Bar.vue
<template>
  <div>Bar</div>
</template>
<script>
export default {
  beforeRouteEnter(to, from, next) {
    console.log("Bar::beforeRouteEnter");
    next();
  },
  beforeRouteUpdate(to, from, next) {
    console.log("Bar::beforeRouteUpdate");
    next();
  },
  beforeRouteLeave(to, from, next) {
    console.log("Bar::beforeRouteLeave");
    next();
  }
};
</script>
// router.js
import Vue from "vue";
// import Router from "vue-router";
import Router from "./router/routers";
import Foo from "./pages/Foo";
import Bar from "./pages/Bar";
Vue.use(Router);
//暴露一下Router实例
export default new Router({
    routes: [
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar }    
    ]
})
// main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router"; // 目标是替换掉vue-router
Vue.config.productionTip = false;
new Vue({
  router, // 在Vue的单页应用中加上router
  render: h => h(App)
}).$mount("#app");
// App.vue
<template>
  <div id="app">
    <img
      alt="Vue logo"
      width="500px"
      src="http://edu-image.nosdn.127.net/e4ebc486f7454d22870e0b79b824fdf1.png?imageView&quality=100
"
    >
    <router-link to="/foo">foo</router-link>
    <router-link to="/bar">bar</router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

目标是替换掉原版的vue-router

设计图

// router/router.js
// 路由表参数构建
import Vue from 'vue'
import RouterView from './components/RouterView'
import RouterLink from './components/RouterLink'
//注册RouterView组件
Vue.component("RouterView", RouterView)
Vue.component("RouterLink", RouterLink)
class RouterTable {
    constructor( routes ) {
      this._pathMap = new Map()  
      this.init(routes)
    }
    // 初始化函数
    init(routes) {
        const addRoute = (route) => {
            this._pathMap.set(route.path,route)
            if(route.children) {
                // 遍历
                route.children.forEach(cRoute => addRoute(cRoute) );          
            }        
        }
        routes.forEach(route => addRoute(route) );   
    }
    // 找一下path是否存在
    match(path) {
        let find;
        // 获取所有的路径this._pathMap.keys()
        for(const key of this._pathMap.keys()) {
            if(path === key) {
                find = key;
                break;            
            }        
        }
        return this._pathMap.get(find)
    }
}
import Html5Mode from './history/html5';
// 创建一个构造路由的类
export default class Router {
    constructor({ routes = [] }) {
      this.routerTable = new RouterTable(routes);   // 路由表
      this.history = new Html5Mode(this);   
    }
    init(app) { // vue单页应用
        const {history} = this;// 解构出history
        history.listen(route => {
            //_route是响应式的
             app._route = route;       
        })
        // 第一次渲染
        history.transitionTo(history.getCurrentLocation());           
    }
    push(to) {
        this.history.push();    
    }
}

Router.install = function() {
    Vue.mixin({
        beforeCreate() {
            if(this.$options.router !== undefined) {// 存在router
               this._routerRoot = this;// this指Vue实例
               this._router = this.$options.router;
               this._router.init(this);
               // this._route的路由信息,响应式的,初始值
               Vue.util.defineReactive(this, "_route", this._route.history.current);                                             
            }        
        }    
    })
}
// /router/history/base.js
// 监听器【两种Mode都包含的监听器】
export default class BaseHistory {
    constructor({routeTable}) {// 依赖反转把routeTable注入进来
        this.routeTable = routeTable;    
    }
    // 注册监听cb函数
    listen(cb) {
         this.cb = cb;   
    }
    // 跳转函数
    transitionTo(target) {
        const route = this.routerTable.match(target);
        // 如果我们的路由配置上找到了这个地址
        this.current = route;
        // 钩子函数cb
        this.cb(this.current)
    }
}
// /router/history/hash.js
// 监听器【hash Mode的监听器】
import BaseHistory from './base'
export default class HashHistory extends BaseHistory {
    constructor(options) {
        super(options)    
        
        
        push(to) {
        	location.hash = to            
        }
    }
    
}
// /router/history/html5.js
// 监听器【html5 Mode的监听器】
import BaseHistory from './base'
// 子分类Html5History-继承->父分类 BaseHistory
export default class Html5History extends BaseHistory {
    constructor(options) {// 构造函数 options透传
    // super()调用父类方法,并重写>>>>>>减少代码量(Square类实现) 
    // 它允许您在子类中调用超类的方法。 这种情况的主要用例是扩展继承方法的功能。 (cube类实现)
       super(options)     
       // 初始化事件监听
       this.initListener();
       initListener() {
           window.addEventListener("popstate", () => {
               // transitionTo跳转函数->继承自BaseHistory
               this.transitionTo(this.getCurrentLocation());           
           })       
       }
       // 获取当前地址,H5 Mode和hash Mode,当前地址是不同的
       getCurrentLocation() {
           // 解码URI
           let path = decodeURI(window.location.pathname) || '/';
           return path + window.location.search + window.location.hash;      
       }
       // 路由跳转实现push方法
       push(target) {
        	this.transitionTo(target);
         	window.history.pushState({key: +new Date()}, "", target)// 第二个参数页面title
       }
    }
}
// router/components/RouterView.vue
// RouterView组件-渲染页面组件
<script> 
export default {
    name: 'RouterView',
    render() {
        const route = this._routerRoot._route;
        if(!route) {
          return 404;          
        }
        const {component} = route;
        return <component />;
    }
}
</script>
// router/components/RouterLink.vue
// RouterLink组件 跳转页面组件
<template>
    <a @click="jump">
    <!-- 渲染内容 -->
    	<slot> </slot>
    </a>
</template>
<script>
    export default {
        props: {
            to:{
                type: String,
                required: true  
            }        
        },
        methods: {
            jump() {
               const router = this._routerRoot._router;   
               router.push(this.to)           
            }                             
        } 
    }
</script>

小结

  1. 路由表
  2. HashMode 【兼容性更好,但是hash带’#‘多了个字符,可读性没有那么美观】
  3. HTML5Mode【兼容性没有hashMode那么好,html5Mode需要后端对我们的路由一一映射,以保证用户在第一次访问页面时,能正确的进入到我们的页面】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/717641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【代理服务器】Squid 反向代理与Nginx缓存代理

目录 一、Squid 反向代理1.1工作机制1.2反向代理实验1.3清空iptables规则&#xff0c;关闭防火墙1.4验证 二、使用Nginx做反向代理缓存服务器三CDN简介3.1什么是CDN3.1CDN工作原理 一、Squid 反向代理 如果 Squid 反向代理服务器中缓存了该请求的资源&#xff0c;则将该请求的…

基于Surprise协同过滤实现短视频推荐

前言 前面一文介绍了通过基础的web项目结构实现简单的内容推荐&#xff0c;与其说那个是推荐不如说是一个排序算法。因为热度计算方式虽然解决了内容的时效质量动态化。但是相对用户而言&#xff0c;大家看到的都是几乎一致的内容&#xff08;不一样也可能只是某时间里某视频的…

准确率 99.9% 的离线IP地址定位库

Ip2region 是一个离线 IP 地址定位库&#xff0c;准确率高达 99.9%&#xff0c;搜索性能为 0.0x 毫秒。DB 文件只有几兆字节&#xff0c;其中存储了所有 IP 地址。 支持 Java、PHP、C、Python、Nodejs、Golang、C#、lua 等查询绑定。查询算法使用二叉树、B树和内存搜索算法。 …

基于Java乡镇篮球队管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

探索小程序的世界(专栏导读、基础理论)

文章导读 一、为什么要学习小程序开发1.1 低门槛1.2 市场需求1.3 创业机会1.4 技术发展趋势 二、专栏导读2.1 实战系列2.2 工具系列2.3 游戏系列2.4 插件系列 三、基础理论3.1 微信小程序简易教程框架组件API工具 开发者工具项目结构 3.2 app.json配置pageswindowtabbar 3.3 Ap…

Android Studio实现内容丰富的安卓自行车租赁平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号105 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查…

Linux centos7.6下查看下线指定用户(实操)

Linux系统是一个多用户多任务的分时操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员申请一个账号&#xff0c;然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪&#xff0c;并控制他们对系统…

【源码】为什么UWB定位技术可用于室内定位?

UWB室内人员定位原理 UWB室内人员定位技术只是属于无线定位技术的一种。流行的无线定位技术包括GPS定位、北斗定位、蓝牙定位、WIFI定位、RFID定位等&#xff0c;其中GPS、北斗主要用在室外定位&#xff0c;蓝牙定位、WIFI定位、RFID定位、UWB定位主要用于室内定位。UWB定位和…

《软件测试开发》概念篇

目录 一.什么是测试 二.测试与开发之间的区别1.工作内容上的区别 2.技能要求上的区别 3.发展前景 测试与调试之间的区别 三.优秀的测试人员所应具备的素质 四.需求 需求的概念 需求的产生&#xff0c;需求是怎么来的&#xff1f; 测试人员眼中的需求 需求的重要性 测…

论文阅读 (94):Substructure Aware Graph Neural Networks (SAGNN, AAAI2023)

文章目录 1 要点1.1 概述1.2 一些概念1.3 代码1.4 引用 2 基础知识2.1 符号2.2 信息传递神经网络 (MPNN) 3 方法3.1 子图提取3.1.1 基于节点的策略3.1.2 基于图的策略 3.2 随机游走返回概率编码3.3 子图信息注入的信息传递 1 要点 1.1 概述 题目&#xff1a;子结构感知图神经…

《YOLOv5/YOLOv7魔术师》专栏介绍 CSDN独家改进创新实战专栏目录

&#x1f4a1;&#x1f4a1;&#x1f4a1;YOLOv5/YOLOv7魔术师&#xff0c;独家首发创新&#xff08;原创&#xff09;&#xff0c;持续更新&#xff0c;最终完结篇数≥100&#xff0c;适用于Yolov5、Yolov7、Yolov8等各个Yolo系列&#xff0c;专栏文章提供每一步步骤和源码&am…

测试员眼中的____是____

- 1 - 测试员眼中的开发是淘气的孩子 只有靠哄、豁、骗 才能让其完成“作业” - 2 - 测试员眼中的产品经理是女票 不管大小事&#xff0c;只要意见有出入 都得与其商量&#xff0c;才能最终拍板 - 3 - 测试员眼中的UI是艺术家 每天都操着画板&#xff08;苹果显示器&#xff…

解除网页禁止复制,复制粘贴没烦恼。

参考 解除网页禁止复制&#xff0c;复制粘贴没烦恼。 https://zhuanlan.zhihu.com/p/344419634 安装SuperCopy插件

游戏出海长期向好趋势未改,茄子科技助力企业把握出海机遇

在中国游戏出海成为更多企业的必选题之时&#xff0c;如何把握出海机遇&#xff0c;在激烈竞争中实现增长&#xff0c;成为中国游戏厂商的着力点。秉承着红海将至的市场发展背景&#xff0c;出海全球化、本地化的战略已经成为企业大势所趋&#xff0c;越来越多的游戏厂商开始挑…

【3 栈和队列】共享栈

利用栈底位置相对不变的特性&#xff0c;可以让两个顺序栈共享一个一维数据空间&#xff0c;将两个栈的栈底分别设置在共享空间的两端&#xff0c;两个栈顶向共享空间中间延伸。 两个栈的栈顶指针都指向栈顶元素&#xff0c; top0-1时0号栈为空&#xff0c;top1MaxSize-1时1号…

智安网络|网络安全威胁多样化和复杂化,防护任务日益艰巨

随着数字化和网络化的加速发展&#xff0c;人们面临的网络安全问题日益增多。由于网络安全威胁的多样性和复杂性&#xff0c;网络安全防护变得越来越困难。 一. 网络安全威胁的复杂性 网络安全威胁种类繁多&#xff0c;主要包括病毒、木马、蠕虫、间谍软件、恶意软件、黑客攻击…

解决使用idea的maven打包springboot项目时,“不支持版本号17”的问题

问题描述 在idea里面使用maven的package功能&#xff0c;对一个springboot项目打包jar包时&#xff0c;出现了“不支持版本号17”的错误 经排查&#xff0c;本地确实装了jdk17的&#xff0c;而且运行mvn -version也提示有java 17 解决办法 最后发现&#xff0c;可能是idea…

2023年生猪行业研究报告

第一章 行业概况 生猪是指猪类动物中未经加工的、原始的、活体的猪&#xff0c;通常是指用于肉类生产的猪。生猪在全球范围内都是主要的肉类来源之一。它们的肉质丰富&#xff0c;营养价值高&#xff0c;同时还能用来制作各种加工肉类产品&#xff0c;如火腿、香肠等。 生猪养…

以太网 (数据链路层协议)

以太网 认识以太网以太网数据帧 认识以太网 “以太网” 不是一种具体的网络&#xff0c;而是一种技术标准&#xff1b;既包含了数据链路层的内容&#xff0c;也包含了一些物理层的内容。 例如&#xff1a;规定了网络拓扑结构&#xff0c;访问控制方式&#xff0c;传输速率等&a…

你值得拥有——流星雨下的告白(Python实现)

目录 1 前言 2 霍金说移民外太空 3 浪漫的流星雨展示 4 Python代码 1 前言 我们先给个小故事&#xff0c;提一下大家兴趣&#xff1b;然后我给出论据&#xff0c;得出结论。最后再浪漫的流星雨表白代码奉上&#xff0c;还有我自创的一首诗。开始啦&#xff1a; 2 霍金说移民外…