好的,今天我们来 卸下巨人的肩膀来给自己站站 通过源码做到 ElementUI真正的按需加载。
前言
好吧,其实就是因为业务有普通轮播图和卡片轮播图的功能。作为一个蔡蔡的练习生,又不会自己手撸一个出来,vue-awesome-swiper又太大了(打包后 600kb),找到的轮播图组件虽然小但又不好用。
盯着原型图看啊看,诶?这些功能 ElementUI不全都有吗,而且还支持按需加载,这样打包后应该也不会特别大吧?搞起来搞起来!
Element UI
啥也别说了,先直接引入康康效果先
// main.js
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
<template>
<div id="app">
<el-carousel :interval="5000" arrow="always">
<el-carousel-item v-for="item in 4" :key="item">
<h3>{{ item }}</h3>
</el-carousel-item>
</el-carousel>
<el-carousel :interval="4000" type="card" height="200px">
<el-carousel-item v-for="item in 6" :key="item">
<h3 class="medium">{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
嗯!就你了!!让我康康打包后的大小 npm run build -- --report
啊这,有点大!加上按需加载呢?我只是想要一个轮播图而已啊 0.0
根据 ElementUI官网—按需加载 配置一波。
// main.js
import Vue from 'vue'
import App from './App.vue'
import {
Carousel,
CarouselItem,
} from 'element-ui';
Vue.use(Carousel)
Vue.use(CarouselItem)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
// babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
npm run serve 嗯,还正常。
让我再康康打包后的大小! npm run build -- --report
确实小了不少!但不论如何,这也都还是引入了一个ElementUI,寄人篱下的感觉总是有点微妙,还可能用上了不少浪费的代码。
那我们就从ElementUI源码中把轮播图的代码拆下来当成自己的吧 git clone https://github.com/ElemeFE/element.git
冷静分析一波目录解构
element-dev
├──.github // github文件
├── build // webpack配置文件
├── examples // API文档?组件demo
├── node_modules // 模块依赖目录
├── packages // 组件的源码目录
├── 所有组件
├── src // 源码目录
├── directive // 自定义指令
├── locale
├── mixins // Vue混合器
├── transition // 样式过渡效果
├── utils // 工具类包
├── index.js // 入口文件
├── test // 测试目录
├── types // typescript文件包
├── .babelrc // babel配置文件
├── .eslintignore // eslint配置忽略文件
├── .eslintrc // eslint配置
├── .gitignore // git忽略文件
├── package.json // npm包核心文件
├── components.json // 组件列表json
├── yarm.lock // yram版本控制文件
├── package-lock.json // npm包版本控制文件
├── ......
翻出轮播图组件源码
Carousel 走马灯 结合使用
el-carousel和el-carousel-item标签就得到了一个走马灯。
根据官网的指路,那应该就是这两个了
element-dev/packages/carousel
element-dev/packages/carousel-item
看看都有哪些依赖项
先看一下 element-dev/packages/carousel/src/main.vue
import throttle from 'throttle-debounce/throttle'
import {
addResizeListener,
removeResizeListener
} from 'element-ui/src/utils/resize-event'
throttle-debounce/throttle是个 npm包,先不管它。
再看看element-ui/src/utils/resize-event
import ResizeObserver from 'resize-observer-polyfill';
好的,也是个包。main的依赖就这些了。
再看看element-dev/packages/carousel-item/src/item.vue`
import { autoprefixer } from 'element-ui/src/utils/util';
element-ui/src/utils/util中
import Vue from 'vue';
import { isString, isObject } from 'element-ui/src/utils/types';
那么所有的引入依赖项就是
// main.vue
import throttle from 'throttle-debounce/throttle'
// resize-event依赖
import ResizeObserver from 'resize-observer-polyfill';
import {
addResizeListener,
removeResizeListener
} from 'element-ui/src/utils/resize-event'
// item.vue
import { autoprefixer } from 'element-ui/src/utils/util';
你的码就是我的码 那我们开始吧
开始偷窃一个轮播图
创建目录
先创建一个carousel目录存放轮播图组件,以及存工具类函数的目录utils。接着就把文件都丢进去好了。
├─components
│ ├─caursel
│ │ item.vue
│ │ main.vue
│ │
└─utils
resize-event.js
util.js
安装包以及删除无用代码
- 先安装包
// ElementUI源码中包的版本
"resize-observer-polyfill": "^1.5.0",
"throttle-debounce": "^1.0.1"
直接按照两个包的官网的最新版来安装了,出了事再看🙄
resize-observer-polyfill cnpm install resize-observer-polyfill --save-dev 1.5.1
throttle-debounce cnpm install throttle-debounce --save ^2.2.1
官网中
throttle-debounce的引入为import { throttle } from 'throttle-debounce';与源码中不同当然你也可以指定版本安装
cnpm install resize-observer-polyfill@1.5.0 --save-dev
cnpm install throttle-debounce@1.0.1 --save
- 删除无用代码
由于目录已经都不一样了,所以源码中
element-ui/src/utils/resize-event要更换为新目录的路径
import {
addResizeListener,
removeResizeListener
} from '@/utils/resize-event'
// item.vue
import { autoprefixer } from '@/utils/util';
打开文件可以看到,其实引入的并不是全部函数。那我们就直接删除无用的吧。
// resize-event.js 三个函数均有使用
/**
* util.js
* import { autoprefixer } from 'element-ui/src/utils/util';
* 函数非常的多,而我们只需要 autoprefixer的函数。
* 引入的 types文件轮播图中也没有用到。
* 因此我们只需要保留一个函数即可。
*/
export const autoprefixer = function (style) {
if (typeof style !== 'object') return style;
const rules = ['transform', 'transition', 'animation'];
const prefixes = ['ms-', 'webkit-'];
rules.forEach(rule => {
const value = style[rule];
if (rule && value) {
prefixes.forEach(prefix => {
style[prefix + rule] = value;
});
}
});
return style;
};
使用组件
引入并注册组件后直接按照官网Carousel 走马灯使用组件
<template>
<div id="app">
<el-carousel :interval="5000" arrow="always">
<el-carousel-item v-for="item in 4" :key="item">
<h3>{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
import ElCarousel from '@/components/caursel/main'
import ElCarouselItem from '@/components/caursel/item'
export default {
name: 'App',
components: {
ElCarousel,
ElCarouselItem
}
}
</script>
<style lang="scss">
.el-carousel__item h3 {
color: #475669;
font-size: 18px;
opacity: 0.75;
line-height: 300px;
margin: 0;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
控制台没有报错,但样式、字体图标很明显的...忘记加载了
引入样式以及字体图标
- 找到字体图标的
css文件element-dev/packages/theme-chalk/src/icon.css
@font-face {
font-family: 'element-icons';
src: url("fonts/element-icons.woff") format("woff"), url("fonts/element-icons.ttf") format("truetype");
/* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
font-weight: normal;
font-display: "auto";
font-style: normal;
}
可以看出,一共引入了两个字体图标文件fonts/element-icons.woff fonts/element-icons.ttf
三个文件 icon.css fonts/element-icons.woff fonts/element-icons.ttf一起复制到styles/fonts目录下并引入
icon.css中的路径记得要更改
- 找到组件样式的
css文件element-dev/packages/theme-chalk/src下的carousel.csscarousel-item.css
分别引入
// main.vue中
<style lang="scss" scoped>
@import './carousel.css';
</style>
// item.vue中
<style lang="scss" scoped>
@import './carousel-item.css';
</style>
那么,所有都准备好了。我们可以对着Carousel 走马灯直接使用了
效果
新加一个 卡片式的轮播
这里字体图标其实只用到了一个箭头的 icon,但两个字体文件就有 82.1kb了。完全可以自己在iconfont中定制。
打包
npm run build -- --report
然而,打包出来却比按需加载还大了了 49.59kb !
core.js
对比了一下两个打包文件的分析,发现是core.js的大小不同。相差了48.25kb。再细看,原来多出来的部分,是多了一些为兼容ES6+的代码。
查了半天资料没搞懂。VueCLI-浏览器兼容里明明是默认useBuiltIns: 'usage'检测代码中ES6/7/8等的使用情况,仅仅加载代码中用到的polyfills,为什么还会啥也丢了上去。即使把包换成和ElementUI一样的版本也一样。有知道的带哥指导指导😥
总结
也就是说,如果你想要弄一套自己能随便修改,只要其中的功能的 UI库,那你大可可以按照上面的说法去做!
先找到组件所有的依赖项 --> 引入依赖 --> 引入样式文件 --> 引入字体图标
此次 轮播图 carousel用到的文件如下
// 源码组件 .vue文件
element-dev/packages/carousel
element-dev/packages/carousel-item
// 源码组件 样式、字体文件
element-dev/packages/theme-chalk/src/icon.css
element-dev/packages/theme-chalk/src/fonts/element-icons.woff
element-dev/packages/theme-chalk/src/fonts/element-icons.ttf
// 源码组件 util工具函数文件
element-ui/src/utils/resize-event
element-ui/src/utils/util
// npm包
throttle-debounce/throttle
resize-observer-polyfill
全局注册 Global Registration
import Vue from 'vue'
import App from './App.vue'
import ElCarousel from '@/components/caursel/main'
import ElCarouselItem from '@/components/caursel/item'
Vue.component('el-carousel', ElCarousel)
Vue.component('el-carousel-item', ElCarouselItem)
局部注册 Local Registration
<template>
<div id="app">
<el-carousel :interval="5000" arrow="always">
<el-carousel-item v-for="item in 4" :key="item">
<h3>{{ item }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
import ElCarousel from '@/components/caursel/main'
import ElCarouselItem from '@/components/caursel/item'
export default {
name: 'App',
components: {
ElCarousel,
ElCarouselItem
}
}
</script>