路由懒加载及实现方式(vue-router)
Posted 禾木白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了路由懒加载及实现方式(vue-router)相关的知识,希望对你有一定的参考价值。
vue-router路由懒加载及实现方式。
文章目录
3.webpack提供的require.ensure()实现懒加载
前言
什么是路由懒加载?--延迟加载,在需要的时候才会进行加载。
一、路由懒加载
我们在路由中通常会定义很多不同的页面。如果不应用懒加载的话,很多页面都会打包到同一个js文件中,文件将会异常的大。造成进入首页时,需要加载的内容过多,时间过长,在浏览器中可能会出现短暂的空白页,从而降低用户体验,而运用路由懒加载是将各个模块分开打包,用户查看的时候再加载对应的模块,减少加载用时。
也就是说:一开始进入页面时不需要一次性把资源都加载完,需要时在加载对应的资源。
二、实现路由懒加载
路由懒加载的主要作用是将 路由对应的组件打包成一个个的js代码块。只有在这个路由被访问到的时候,才会加载对应组件的代码块。
//非路由懒加载
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Login from '@/components/Login'
import New from '@/components/New'
import List from '@/components/List'
......
routes:[
path:'/Login',name:'Login',component:Login,
path:'/',name:'Home',component:Home,
...
]
vue实现路由懒加载的三种方式:
- Vue异步组件
- ES6的import()
- webpack的require.ensure()
1.Vue异步组件(异步加载)
vue-router 配置路由,使用vue的异步组件技术,可以实现懒加载,但是这种情况是一个组件会生成一个js文件。
component:resolve => require(['需要加载的组件地址'],resolve)
path:'/login',name:'Login',
component:resolve => require(['@/components/Login'],resolve),
path:'/home',name:'Home',
component:resolve => require(['@/components/Home'],resolve),
children:[
path:'/new',name:'New',
component:resolve =>require(['@/components/New'],resolve),
path:'/list',name:'List',
component:resolve => require(['@/components/List'],resolve)
]
2.推荐方式-ES6的import()
const 组件名 = () => import('组件路径')
//下面没有指定webpackChunkName,每个组件打包成一个js文件
const Foo = () => import('../components/Foo')
const Aoo = () => import('../components/Aoo')
指定相同的webpackChunkName,会合并打包成一个js文件
const Foo = () => import(/*webpackChunkName:'ImportFuncDemo'*/,'../components/Foo');
const Aoo - () => import(/*webpackChunkName:'ImportFuncDemo'*/,'../components/Aoo')
...
path:'/Foo',name:'Foo',component:Foo,
path:'/Aoo',name:'Aoo',component:Aoo,
path:'/Login',name:'Login',
component: ()=>import(/*webpackChunkName:"ImportFuncDemo"*/,'../compontents/Login')
上面代码中,webpackChunkName值相同的会打包成一个js文件
3.webpack提供的require.ensure()实现懒加载
vue-router 配置路由,使用webpack的require.ensure技术,可以实现懒加载,这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
require.ensure可实现按需加载资源,包括js,css等,会给里面require的文件单独打包,不会合主文件打包在一起。
path:'/home',name:'home',component:r=>
require.ensure([],()=>r(require('@/components/home')),'funcDemo'),
path:'/new',name:'new',component:r=>
require.ensure([],()=>r(require('@/components/new')),'funcDemo'),
path:'/list',name:'list',component:r=>
require.ensure([],()=>r(require('@/components/list')),'listDemo'),
注:r就是resolve
const list = r => require.ensure([],()=>r(require('组件地址')),'list')
第一个参数是数组,表明第二个参数里需要依赖的模块,这些会提前加载。
第二个是回调函数,在这个回调函数里面require的文件会被单独打包成一个chunk,不会和主文件打包在一起,这样就生成了两个chunk,第一次加载时只加载主文件。
第三个参数是错误回调。
第四个参数是单独打包的chunk的文件名
const Coo = resolve=>
require.ensure([],()=>resolve(require('@/components/List')))
...
path:'/list',name:'List',component:Coo
vue-router路由懒加载
路由懒加载指的是打包部署时将资源按照对应的页面进行划分,需要的时候加载对应的页面资源,而不是把所有的页面资源打包部署到一块。避免不必要资源加载。(参考vue项目实现路由按需加载(路由懒加载)的3种方式_小胖梅的博客-CSDN博客_vue懒加载 )
// 非懒加载
import Home from '@/components/Home'
const routes = [
path: '/home',
name: 'home',
component: Home
]
这里有三种方式可以实现vue项目路由跳转时资源的按需加载。
1. vue异步组件
vue-router配置路由,使用vue的异步组件技术,可以实现按需加载。
但是,这种情况下每一个组件就会生成一个js文件,不能分类指定chunkName
// vue异步组件
path: '/home',
name: 'home',
component: resolve => require(['@/components/home'], resolve)
2. 使用import
// const 组件名 = () => import('组件路径');
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
const Home = () => import('@/componnets/home');
const Index = () => import('@/components/index');
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件
// 把组件按组分块
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home');
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
path: '/home',
name: 'home',
component: Home
,
path: '/index',
name: 'index',
component: Index
3. webpack提供的require.ensure()
该方法也可指定相同的chunkName,合并打包成一个js文件。
path: '/home',
name: 'home',
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
,
path: '/index',
name: 'index',
component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
,
path: '/about',
name: 'about',
// 传入空字符串 则每个component会单独生成一个js文件
component: r => require.ensure([], () => r(require('@/components/index')), '')
公司后台项目路由懒加载模式修改(新后台vue2.0)
项目背景:老后台(angular1.x版本)正在迁移新后台(vue2.0)
未修改之前:
打完包之后有156个js文件,这是按照每个路由对应的component生成一个js文件,这就意味着到时候老后台全部迁移到新后台之后,目前大概有800个路由,那就会生成800多个js文件,这种模式的路由懒加载对于后台管理系统其实是没有必要的,所以考虑通过webpackChunkName将各个模块分类,一个一级分类指定一个chunkName。
修改之后:
打完包只有25个js文件,看起来就舒服多了。
各个大模块路由懒加载修改的格式如下:
在一个大的路由模块下,指定相同的webpackChunkName。
修改之后打包生成的文件名格式如下:
hash值之前为自己设置的webpackChunkName名称。
这里当时遇到的一个问题如下图所示:
如左边红框所示,生成的文件里面多了一个用 '~' 拼接起来的js文件。
这个后来翻到了webpack的splitChunks.automaticNameDelimiter。因为项目中在这三个模块下,都引入了同一个文件(UEditor),并且项目中也并没有指定对应的webpackChunkName,所以webpack内部自动处理,将这个文件单独提取出来,并自动命名,命名规则见webpack官方文档,连接符 '~' 是可配置的。
出现 '~' 连接符的组件引入方式如下:
修改之后的引入方式如下:
指定了webpackChunkName,以后其他模块引入富文本UEditor时也请按照此方式引入,命名保持相同。
以下是webpack官方文档对automaticNameDelimiter配置的解释。
vue-router核心原理解析:(参考【第2194期】SPA 路由三部曲之核心原理 )
路由描述了URL和UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需刷新页面)。前端路由最主要的展示方式有2种:
- 带有hash的前端路由:地址栏URL中有 #,即hash值,不好看,但兼容性高。
- 不带hash的前端路由:地址栏URL中没有 #,好看,但部分浏览器不支持,还需要后端服务器支持。
在vue-router中,这两种展示形式,被定义成两种模式,即Hash模式与History模式。前端路由实现原理很简单,本质上就是检测URL的变化,截获URL地址,通过解析、匹配路由规则实现UI更新。
① Hash模式
一个完整的URL包括:协议、域名、端口、虚拟目录、文件名、参数、锚。
Hash值指的是URL地址中的锚部分,也就是# 后面的部分。hash也称作锚点,是用来做页面定位的,与hash值对应的DOM id显示在可视区域内。在HTML5的history新特性出现前,基本都是使用监听hash值来实现前端路由的。hash值更新有一下几个特点:
- hash值是网页的标志位,HTTP请求不包含锚部分,对后端无影响
- 因为HTTP请求不包含锚部分,所以hash值改变时,不触发网页重载
- 改变hash值会改变浏览器的历史纪录
- 改变hash值会触发window.onhashchange()事件
而改变hash值的方式有3种:
- a标签使锚点值变化,例:<a href="#/home"></a>
- 通过设置window.location.hash的值
- 浏览器前进键(history.forword())、后退键(history.back())
综上所述,这3种改变hash值的方式,并不会导致浏览器向服务器发送请求,浏览器不发出请求,也就不会刷新页面。hash值改变,触发全局的window对象上的hashchange事件。所以hash模式路由就是利用hashchange事件监听URL的变化,从而进行DOM操作来模拟页面跳转。
② History模式
主要应用了History API新增的两个方法:pushState()、replaceState(),均具有操纵浏览器历史记录的能力。
history.pushState(state, title, URL),该方法共接收3个参数:
- state:用于存储该URL对应的状态对象,可以通过history.state获取
- title:标题,目前浏览器并不支持
- URL:定义新的历史URL记录,需要注意,新的URL必须与当前URL同源,不能跨域
pushState函数会向浏览器的历史记录中国添加一条,history.length的值会+1,当前浏览器的URL变成了新的URL。需要注意的是:仅仅将浏览器的URL变成了新的URL,页面不会加载、刷新。
history.replaceState(state, title, URL)
replaceState的使用与pushState非常相似,都是改变当前的URL,页面不刷新。区别在于replaceState是修改了当前的历史记录项而不是新建一个,history.length的值保持不变。
window.onpopstate()
为了配合history.pushState()或者history.replaceState(),HTML5还新增了一个事件,用于监听URL历史记录改变:window.onpopstate。
官方对于window.onpopstate()事件的描述是这样的:
每当处于激活状态的历史记录条目发生变化时,popstate事件就会在对应的window对象上触发。如果当前处于激活状态的历史记录条目是由history.pushState()方法创建,或者由history.replaceState()方法修改过的,则popstate事件对象的state属性包含了这个历史记录条目的state对象的一个拷贝。调用history.pushState()或者history.replaceState()不会触发popstate事件。popstate事件只会在浏览器某些行为下触发,比如点击后退、前进按钮(或者在Javascript中调用 history.back()、history.foward()、history.go()方法),此外,a标签的锚点也会触发该事件。
结合上述,在浏览器支持 pushState 的情况下,hash 模式路由也可以使用 pushState 、replaceState 和 popstate 实现。pushstate 改变 hash 值,进行跳转,popstate 监听 hash 值的变化。小小的剧透,vue-router 中不管是 hash 模式,还是 history 模式,只要浏览器支持 history 的新特性,使用的都是 history 的新特性进行跳转。
以上是关于路由懒加载及实现方式(vue-router)的主要内容,如果未能解决你的问题,请参考以下文章