import Header from './components/Header'
需要现在文件夹里创建个index.js导出所有组件:
export { default as Layout } from './Layout/Index.vue'
// ...
然后才能引入
import { Layer } from '@components' // 意思为src/components/Layer/index.vue
import {
Login,
Home,
ErrorPage
} from '@components'
使用场景:当一个页面加载的时候,时间过久(特别是首屏)。一般是两个原因,资源太大,接口拉取时间过久;页面中有较为复杂的组件,导致渲染过久。
当我们一个页面中引入的子组件很多时,打包的时候这个组件生成的文件也会很大
对于link标签的引入:
<link rel="preload" href="xxxx/sdk.js" />
<link rel="prefetch" href="xxxx/sdk.js" />
按需引入默认效果是prefetch方式,我称为预加载。先看看写法:
components: {
fromPage: (resolve) => {
require(['@/views/fromPage/index.vue'], resolve)
}
}
// 或者
components: {
'from-page' : () => import (/*webpackChunkName: "fromPage" */ './components/fromPage') // 注释的地方是说明打包后生成的文件叫什么
}
// 在路由表中
{
component: function() {
return import(/* webpackChunkName: "fromPage" */' ../xxx/fromPage.vue'
}
为什么是这种写法,好像是jsonp的原理,以后有空细看下。
使用按需引入的方式后,该组件代码会单独打包,那默认的prefetch方式是什么行为呢?
例如当一个首屏页面,其中有a组件做了按需引入,我们可以通过浏览器的Network记录查看,他拉取首页的资源的同时,也开始要拉取a组件单独打包的资源(是一个预备的状态),但是要等首页拉取完毕后,空闲了才去真正拉取a组件。
如果是路由组件做了按需引入怎么理解,其实很好理解,我们最外层不是有个App.vue,这个就相当于路由组件的父组件,所以逻辑和上面说的一样。
原理:在运行的index.html文件中引入的link标签中打上标识rel="prefetch"
,其他正常引入的是preload
。
<link href="/js/fromPage.js" rel="prefetch" 〉
<link href="/js/xxx.js" rel="preload" 〉
...
这是第二种方式,需要在vue.config.js中禁用默认的方式:
chainWebpack: config => config.plugins·delete('prefetch')
当然某个组件还想使用默认方式可以通过webpage注释:
{
component: function() {
return import(/* webpackChunkName: "fromPage" */ /*webpackPrefetch:true*/ '../xxx/fromPage.vue'
}
其中webpackPrefetch:true
可以使用数字表示优先级。
使用这种script方式的效果是:当你用v-if渲染子组件或者浏览器浏览到的时候,才会去单独拉取该子组件的打包代码文件,可以通过浏览器的Network记录证实。
原理大概是需要加载资源的时候,创建一个script标签去拉取,其实就是下面说的JS触发按需引入。
两种方式都有优缺点
预加载:
script:
main.js中
import components from '@/utils/components.js'
Vue.use(components)
在放组件的文件夹中,新建个js文件把所有组件都导出:
// 这里统一把组件都导出,在main.js中引入
import Vue from 'vue'
import pgFrom from './pg-form'
import pgTable from './pg-table'
// 注意每个组件内部一定要有name属性,要不拿下面不到对象的
Vue.component(pgFrom.name, pgFrom)
Vue.component(pgTable.name, pgTable)
export { pgFrom, pgTable }
main.js中
import * as pgComponent from './components/business-components' // 导入全局组件(对象类型),这样写默认导入index.js
Object.values(pgComponent).forEach(i => { // 循环注册组件
Vue.component(i.name, i)
})
更好的方法是直接用正则去匹配文件:
// 这里统一把组件都导出,在main.js中引入
import Vue from 'vue'
const components = require.context('./', true, /.vue$/)
components.keys().forEach(fileName => {
const component = components(fileName)
Vue.component(component.default.name, component.default)
})
main.js中
/* 引入公共组件 */
import '@/components/index.js'
例如有个场景,通过数组的数据去渲染对应的组件:
<template>
<div>
<div v-for="(item, index) in list" :key="index">
<a v-if="item.type === 'a'"></a>
<b v-else-if="item.type === 'b'"></b>
<c v-else-if="item.type === 'c'"></c>
....
<div>
</div>
</template>
代码太冗长了,借助动态组件可以解决:
<template>
<div>
<div v-for="(item, index) in list" :key="index">
<component :is="item.type"></component>
<div>
</div>
</template>
第三方库一般新版本都支持了按需引入,例如:
import { a, b } from '某某库'
如果是很老的库就实在无法这样写了,例如jQuery
如果是自己封的工具,可以参考【es6入门】模块化的写法export与import 。注意不要把整个对象引入再以obj.a
的方式调用,这样打包会把整个obj都囊括了。
例如某个库只有在触发某个函数的时候才使用
那老旧的库要怎么写呢?例如jQuery这种,默认导出整个对象的,可以这样写:
clickFn() {
import('jquery').then(res=>{
let $ = res.default
})
}
新库可以这样写:
clickFn() {
import('xlsx').then(res=>{
let read = res.read
})
}
这样子做虽然能让接口拉取组件资源的时候比较快(因为容量小了),但是每次触发的时候才会去拉取库中引入的需要的资源,会有个卡顿的过程。
所以最好在mounted这个钩子函数触发后去按需引入,可以定义全局的变量赋值上去。这样当组件挂载完后就去拉取库资源,体验会好很多。
mounted(){
import(/*webpackPrefetch:2*/'jquery').then(res=>{ // 加载优先级为2,数字越大越优先
$ = res.default
})
import(/*webpackPrefetch:1*/'xlsx').then(res=>{ // 加载优先级为1
read = res.read
})
}