网站建设每年有维护费吗,企业网站建设的必要性及维护,郴州网站建设推广服务,餐饮设计公司1.Hash模式
hash就是url中#后面的部分hash改变时#xff0c;页面不会从新加载#xff0c;会触发hashchange事件#xff0c;去监听hash改变#xff0c;而且也会被记录到浏览器历史记录中vue-router的hash模式#xff0c;主要是通过hashchange事件#xff0c;根据hash值找…1.Hash模式
hash就是url中#后面的部分hash改变时页面不会从新加载会触发hashchange事件去监听hash改变而且也会被记录到浏览器历史记录中vue-router的hash模式主要是通过hashchange事件根据hash值找到对应的组件去进行渲染源码里会先判断浏览器支不支持popstate事件如果支持则是通过监听popstate事件如果不支持则监听hashchange事件
hash模式页面跳转不刷新 根据http协议所示url中hash改变请求是不会发送到服务端的不管怎么location跳转或者url上直接加上hash值回车他都一样请求是不会发送到服务端。 但是我们的系统里又引入了vue-router其中hashchange这个事件监听到了hash的变化从而触发了组件的更新也就绘制出了相应的页面 2.History模式
通过history.pushstate去修改页面的地址当history改变时会触发popstate事件所以可以通过监听popstate事件获取路由地址根据当前路由地址找到对应组件渲染
history模式切换路由时页面刷新 看一下正确的history模式下首页刷新到显示的整体流程 1.将这个完整的url发到服务器nginx2.ngix需要配置用这个uri在指给前端index.html因为根本没有任何一个服务器提供了这个url路由如果直接访问的话就是404所以就要指回给前端让前端自己去根据path来显示
location / {root /usr/share/nginx/html/store;//项目存放的地址index index.html index.htm;try_files $uri $uri/ /index.html;//history模式下需要配置它
}所以try_files $uri $uri/的意思就是比如http://test.com/example先去查找单个文件example如果example不存在则去查找同名的文件目录/example/如果再不存在将进行重定向index.html只有最后一个参数可以引起一个内部重定向凡是404的路由都会被重定向到index.html这样就显示正确了3.此时nginx将这个请求指回了前端的index.html,index.html中开始加载js,js中已有vue-router的代码vue-router自动触发了popstate这个事件在这个事件回调中绘制了这个path下对应的页面组件3.实现vue-router
VueRouter需要做以下这些事情
实现VueRouter根据不同模式进行不同处理根据传入的路由配置生成对应的路由映射init函数监听hashchange或popState事件浏览器记录改变时重新渲染router-view组件实现install静态方法给Vue实例挂载router实例注册全局组件和, router-view组件通过当前url找到对应组件进行渲染并且url改变时重新渲染组件router-link则渲染为a标签使用Object.defineProperty在Vue的原型上定义$router和$route属性
代码实现 首先在创建文件 router/index.jsrouter/my-router.js 在index中我就不做多讲解了和平常vue-router一样的配置只是不需要vue-router我们自己实现 一下都会有详细的注释每一项的作用 import Vue from vue
import VueRouter from ./my-router; //实现router文件
import HomeView from ../views/HomeView.vue //home文件
import about from ../views/AboutView.vue //about文件Vue.use(VueRouter) //注意 这是我们自己实现的文件只是名字叫vuerouterconst routes [ //这是我们的路由表{path: /home,name: home,component: HomeView},{path: /about,name: about,// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: about}
]const router new VueRouter({ //创建实例mode: history, //模式 hash historyroutes //路由表给实例传过去
})export default router //最后到处router接下来就是正式实现router 首先在my-router最顶部声明一个变量Vue并将其初始化为null //my-router.js
let Vue null; //保存Vue的构造函数在插件中要使用,保留在将来为Vue分配一个值,减少全局命名空间的污染定义一个HistoryRoute的类并在其构造函数中将this.current也初始化为null 用途 状态管理this.current用于存储当前路由的状态或信息比如当前激活的路由路径、参数等。初始化通过将其初始化为null你可以在类的其他方法中根据需要更新this.current的值而不会受到未初始化属性的影响。灵活性将this.current初始化为null提供了灵活性允许你在类的生命周期中的任何时刻为其分配一个具体的值。 //my-router.js
let Vue null; //保存Vue的构造函数在插件中要使用,保留在将来为Vue分配一个值,减少全局命名空间的污染
class HistoryRoute {constructor() {this.current null;}
}定义一个HistoryRoute的类 构造函数 constructor(options)接收一个options对象该对象包含两个属性mode和routes。mode指定路由模式hash或historyroutes是一个路由配置数组每个路由配置对象包含path和component属性。this.changeMap将routes数组转换为一个对象Map以path为键component为值方便后续根据路径快速查找对应的组件。Vue.util.defineReactive(this, history, new HistoryRoute()); 和 this.history new HistoryRoute();这里设置了history属性后者覆盖了前者。HistoryRoute类用于管理当前路由状态。 class VueRouter {// 可以看到暂时传入了两个一个是mode还有一个是routes数组。因此我们可以这样实现构造器constructor(options) {this.mode options.mode || hash; //默认是hashthis.routes options.routes || []; //默认为空// 由于直接处理数组比较不方便所以我们做一次转换采用path为keycomponent为value的方式this.routesMap this.changeMap(this.routes);// 我们还需要在vue-router的实例中保存当前路径在包含一些例如params信息其实就是$route所以我们为了方便管理使用一个对象来表示Vue.util.defineReactive(this, history, new HistoryRoute());this.history new HistoryRoute();}changeMap(routes) {// 使用render函数我们可以用js语言来构建DOMreturn routes.reduce((pre, next) {console.log(pre);pre[next.path] next.component;console.log(pre);return pre;}, {});}
}添加init 方法 根据mode的不同为window添加相应的事件监听器以监听路由变化hashchange或popstate事件并更新history.current属性。在页面加载时load事件也根据当前URL设置history.current。 class VueRouter {// 可以看到暂时传入了两个一个是mode还有一个是routes数组。因此我们可以这样实现构造器constructor(options) {this.mode options.mode || hash;this.routes options.routes || [];// 由于直接处理数组比较不方便所以我们做一次转换采用path为keycomponent为value的方式this.routesMap this.changeMap(this.routes);// 我们还需要在vue-router的实例中保存当前路径在包含一些例如params信息其实就是$route所以我们为了方便管理使用一个对象来表示Vue.util.defineReactive(this, history, new HistoryRoute());this.history new HistoryRoute();this.init();}init() {// 如果是hash模式if (this.mode hash) {location.hash ? void 0 : (location.hash /);window.addEventListener(load, () {this.history.current location.hash.slice(1);});window.addEventListener(hashchange, () {console.log(location.hash.slice(1))this.history.current location.hash.slice(1);});}// 如果是history模式if (this.mode history) {location.pathname ? void 0 : (location.pathname /);window.addEventListener(load, () {console.log(location.pathname)this.history.current location.pathname;});window.addEventListener(popstate, () {console.log(location.pathname)this.history.current location.pathname;});}}changeMap(routes) {// 使用render函数我们可以用js语言来构建DOMreturn routes.reduce((pre, next) {console.log(pre);pre[next.path] next.component;console.log(pre);return pre;}, {});}Vue Router作为一个Vue插件需要创建instll方法 设置Vue实例 Vue v;将传入的Vue实例赋值给全局变量Vue以便后续使用。 全局混入 使用Vue.mixin在Vue的生命周期钩子beforeCreate中注入代码用于处理路由相关的初始化。在根组件中保存_router和_root属性分别指向VueRouter实例和根组件自身。对于非根组件通过$parent找到根组件从而访问到_router和_root。 VueRouter.install (v) {Vue v;// vue-router还自带了两个组件分别是router-link和router-view 在Vue.use(VueRouter)的时候加载的 所以我们要写在install里面// 新增代码Vue.mixin({beforeCreate() {// 如果是根组件if (this.$options this.$options.router) {console.log(this.$options)// 将根组件挂载到_root上this._root this;this._router this.$options.router;// 拦截router-linkthis._router.mode history document.addEventListener(click, (e) {if (e.target.className router-link-to) {// 阻止默认跳转事件e.preventDefault();// 手动改变url路径console.log(e.target.getAttribute(href))history.pushState(null, , e.target.getAttribute(href));// 为current赋值url路径this._router.history.current location.pathname;}});} else {// 如果是子组件// 将根组件挂载到子组件的_root上this._root this.$parent this.$parent._root;console.log(this._root);}},});
};使用Object.defineProperty在Vue的原型上定义$router和$route属性以便在任何Vue组件中通过this.$router和this.$route访问到VueRouter实例和当前路由信息。在install方法里面写就行 // 定义$routerObject.defineProperty(Vue.prototype, $router, {get() {console.log(this);return this._root._router;},});// 定义$routeObject.defineProperty(Vue.prototype, $route, {get() {return this._root._router.history.current;},});定义全局组件install方法里面添加 router-link一个用于导航的a标签组件根据路由模式hash或history自动添加#或正常路径。点击时如果是history模式会阻止默认跳转行为改为手动更新URL和路由状态。router-view一个用于渲染当前路由对应组件的占位符组件。它根据history.current和routesMap找到对应的组件并使用Vue的render函数渲染。 Vue.component(router-link, {props: {to: String,},render(h) {const mode this._root._router.mode;let to mode hash ? # this.to : this.to;return h(a,{attrs: {href: to,},// 新增代码class: router-link-to,},this.$slots.default);},});Vue.component(router-view, {render(h) {const current this._root._router.history.current;const routesMap this._root._router.routesMap;return h(routesMap[current]);},});完整代码 /** Author: hukai huzhengengmail.com* Date: 2023-06-08 17:49:08* LastEditors: hukai huzhengengmail.com* LastEditTime: 2024-10-24 11:08:00* FilePath: \vue源码\vue-router-yuanma\src\router\my-router.js* Description: 这是默认设置,请设置customMade, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE*/
let Vue null;
class HistoryRoute {constructor() {this.current null;}
}
// 因为router时new出来的 并且穿了一个对象 配置的路由由此可知router是一个class类
class VueRouter {// 可以看到暂时传入了两个一个是mode还有一个是routes数组。因此我们可以这样实现构造器constructor(options) {this.mode options.mode || hash;this.routes options.routes || [];// 由于直接处理数组比较不方便所以我们做一次转换采用path为keycomponent为value的方式this.routesMap this.changeMap(this.routes);// 我们还需要在vue-router的实例中保存当前路径在包含一些例如params信息其实就是$route所以我们为了方便管理使用一个对象来表示Vue.util.defineReactive(this, history, new HistoryRoute());this.history new HistoryRoute();this.init();}init() {// 如果是hash模式if (this.mode hash) {location.hash ? void 0 : (location.hash /);window.addEventListener(load, () {this.history.current location.hash.slice(1);});window.addEventListener(hashchange, () {console.log(location.hash.slice(1))this.history.current location.hash.slice(1);});}// 如果是history模式if (this.mode history) {location.pathname ? void 0 : (location.pathname /);window.addEventListener(load, () {console.log(location.pathname)this.history.current location.pathname;});window.addEventListener(popstate, () {console.log(location.pathname)this.history.current location.pathname;});}}changeMap(routes) {// 使用render函数我们可以用js语言来构建DOMreturn routes.reduce((pre, next) {console.log(pre);pre[next.path] next.component;console.log(pre);return pre;}, {});}
}// 通过Vue.use 知道里面有一个install方法 并且第一个参数是Vue实例
VueRouter.install (v) {Vue v;// vue-router还自带了两个组件分别是router-link和router-view 在Vue.use(VueRouter)的时候加载的 所以我们要写在install里面// 新增代码Vue.mixin({beforeCreate() {// 如果是根组件if (this.$options this.$options.router) {console.log(this.$options)// 将根组件挂载到_root上this._root this;this._router this.$options.router;// 拦截router-linkthis._router.mode history document.addEventListener(click, (e) {if (e.target.className router-link-to) {// 阻止默认跳转事件e.preventDefault();// 手动改变url路径console.log(e.target.getAttribute(href))history.pushState(null, , e.target.getAttribute(href));// 为current赋值url路径this._router.history.current location.pathname;}});} else {// 如果是子组件// 将根组件挂载到子组件的_root上this._root this.$parent this.$parent._root;console.log(this._root);}},});// 定义$routerObject.defineProperty(Vue.prototype, $router, {get() {console.log(this);return this._root._router;},});// 定义$routeObject.defineProperty(Vue.prototype, $route, {get() {return this._root._router.history.current;},});Vue.component(router-link, {props: {to: String,},render(h) {const mode this._root._router.mode;let to mode hash ? # this.to : this.to;return h(a,{attrs: {href: to,},// 新增代码class: router-link-to,},this.$slots.default);},});Vue.component(router-view, {render(h) {const current this._root._router.history.current;const routesMap this._root._router.routesMap;return h(routesMap[current]);},});
};
export default VueRouter;最后在main.js中注册一下就行
import Vue from vue
import App from ./App.vue
import router from ./router
import store from ./storeVue.config.productionTip false
new Vue({router,store,render: h h(App)
}).$mount(#app)
APP.vue中
templatediv idappnavrouter-link to/homeHome/router-link |router-link to/aboutAbout/router-link/navrouter-view//div
/template
script
export default {name:Router,mounted(){console.log(this.$router)}
}
/script
style
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}nav {padding: 30px;
}nav a {font-weight: bold;color: #2c3e50;
}nav a.router-link-exact-active {color: #42b983;
}
/style总结 这段代码通过定义VueRouter类和install方法实现了一个简化版的Vue Router。它允许开发者定义路由规则并在Vue应用中通过和组件实现页面导航和组件渲染。尽管这个实现相对简单但它展示了Vue Router的核心概念和工作原理。