前言
几个月前写了一个数据大屏的项目,基于vue2、echarts5的数据大屏。有小伙伴在后台留言说适配方案很实用。最近不太忙,就打算单独把大屏适配组件封装一下,传到npm。
虽然只有一个组件,也算是一次完整的,从零到一发布按需加载的vue组件库的经历。看完后相信你也能打包并发布属于自己的vue组件库。
打包工具的选择
当前要打包的组件库,虽然只有一个组件,但是我们希望,后面可以进行扩展,并且,当组件增多时,我们希望可以对组件按需加载。
之前写过两篇文章:
分别探讨了使用webpack和rollup打包按需加载组件库的原理和方法。
相比较而言,rollup的配置比较简单。而且,通过webpack打包出来的组件库,按需加载需要借助插件,比如element-ui使用的是babel-plugin-component。
所以,我们这里将选用rollup。
项目搭建
mkdir bs-display
cd bs-display
npm init -y
新建各种配置文件、组件代码文件夹、测试文件夹,项目结构如下:(dist目录由打包生成)
rollup的配置在前面的文章中有非常详细的讲解,这里我们直接上配置文件的代码:
//rollup.prod.js
import babel from 'rollup-plugin-babel'
import commonjs from 'rollup-plugin-commonjs'
import vue from 'rollup-plugin-vue'
import autoprefixer from 'autoprefixer'
import { terser } from 'rollup-plugin-terser'
export default {
input: "./src/index.js",
//输出umd、es、cjs三种模块规范的打包文件
output: [
{
file: './dist/bs-display-umd.js',
format: 'umd',
name: 'bsDisplay'
},
{
file: './dist/bs-display-es.js',
format: 'es'
},
{
file: './dist/bs-display-cjs.js',
format: 'cjs'
}
],
plugins:[
babel({
exclude: 'node_modules/**' //转换es6语法
}),
vue({ //编译vue代码,并为vue组件的样式加前缀
style: {
postcssPlugins: [
autoprefixer()
]
}
}),
commonjs(), //支持commonjs模块规范
terser() //代码压缩
],
external:[
'vue'
]
}
rollup支持的打包文件的格式有amd, cjs, es\esm, iife, umd。
- amd为AMD标准
- cjs为CommonJS标准
- esm\es为ES模块标准
- iife为立即调用函数
- umd同时支持amd、cjs和iife
上述的打包配置,会以"./src/index.js"作为入口文件,打包后,在dist文件夹下生成以下3个文件:
在这三个文件中,都包含全部业务逻辑,只是导出方式不同。在下面的调试方法中,我们再展开来讲。
组件开发
适配的原理
大屏成像原理几乎都是投屏,也就是把电脑屏幕通过有线信号投放到大屏上,电脑上呈现什么内容,大屏上就会呈现什么内容,所以浏览器的横向和纵向上都不能出现滚条。
这里我们用CSS3的scale,将容器设置为设计稿宽高(如3840 * 2160),再动态根据浏览器视口的宽高进行缩放,从而实现容器始终铺满浏览器视口,而不出现滚动条。组件的内容如下:
// Frame.vue
//容器组件的结构
<template>
<div class="bsd-frame" :style="{'background': bgColor}" ref="bsdFrame">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'bsd-frame',
props: {
width: {
type: Number,
default: 3840
},
height: {
type: Number,
default: 2160
},
bgColor: {
default: 'rgb(2, 2, 37)'
}
},
data(){
return {
frameWidth: 0,
frameHeight: 0
}
},
methods: {
setSize(){
//获取父组件传入的容器宽高,通常是设计稿宽高,或者电脑屏幕的宽高
this.frameWidth = this.width || screen.width
this.frameHeight = this.height || screen.height
//将传入的宽高设为大屏边框容器的宽高
let frame = this.$refs.bsdFrame
frame.style.width = this.frameWidth + 'px'
frame.style.height = this.frameHeight + 'px'
},
setScale(){
//获取页面的宽高,使用时需要设置html,body{ height:100% },否则获取到的页面高度为0
let bodyWidth = document.body.clientWidth,
bodyHeight = document.body.clientHeight
//根据浏览器视口的的宽高 和 大屏边框容器的宽高 计算缩放值
let scaleX = bodyWidth / this.frameWidth,
scaleY = bodyHeight / this.frameHeight
//为大屏边框容器设置缩放值
this.$refs.bsdFrame.style.transform = `scale(${scaleX},${scaleY})`
},
debounce (fn, t) {
const delay = t || 300
let timer
return () => {
const args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
timer = null
fn.apply(this, args)
}, delay)
}
}
},
mounted() {
this.setSize()
this.setScale()
this.debouncedSetScale = this.debounce(this.setScale, 500)
//触发resize事件时,重新计算 大屏边框容器 的缩放值
window.addEventListener('resize', this.debouncedSetScale)
},
destroyed(){
window.removeEventListener('resize', this.debouncedSetScale)
}
}
</script>
<style lang="scss">
.bsd-frame{
position: fixed;
transform-origin: left top; //将transform-origin设为左上角
}
</style>
使用方式:
<bsd-frame> //宽高和背景色如果不传则使用默认值
<div>大屏内容</div>
</bsd-frame>
组件库的相关文件
我们的打包配置,会以"./src/index.js"作为入口文件,那么"./src/index.js"的内容是什么呢?src文件夹的目录结构是什么呢?
组件都放在src下的components文件夹中,每一个组件对应一个文件夹,每个文件夹包含一个.vue文件和index.js文件,这是为了按需加载做准备。
Frame/index.js会导出一个函数,当外部导入这个函数并执行时,就会实现Frame组件的全局注册。(test/index.js同理)
export default function(Vue){
Vue.component(Frame.name, Frame)
}
"./src/index.js"的内容如下:
// ./src/index.js的内容
import Frame from "./components/Frame" //导入Frame/index.js的函数
import test from "./components/test" //导入test/index.js的函数
// Vue.use的用法,执行该函数会全局注册所有组件
function install(Vue){
Vue.use(Frame)
Vue.use(test)
}
//通过`script`标签引入组件库的情况,注册所有组件
if(window && window.Vue) {
Vue.use(install)
}
/***
在es模块中, 能被按需引入的变量需要用这些方式导出:
export const a = 1
export function a(){}
export { a, b }
而不能使用export default
***/
//这里导出各组件的全局组件函数
//当以 import { Frame } from 'xxx'的方式导入时,就只会导入Frame的相关代码,而不会导入test相关代码
export {
Frame,
test
}
export default install
写好了组件代码和打包配置文件,打包后,我们还需要修改package.json:
"main": "./dist/bs-display-umd.js",
"module": "./dist/bs-display-es.js",
接下来就是本地调试了。
本地调试
通过script标签引入
新建一个html文档(我们这里是在example文件夹下新建一个index.html),引入打包好的组件库引入。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,body,#app {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="app">
<bsd-frame><div>大屏内容</div></bsd-frame>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="../dist/bs-display-umd.js"></script>
<script>
new Vue({
el: '#app'
})
</script>
</html>
文字是黑色的,而且被缩小后文字太小了,所以截图中基本上看不到。如果设置:
color: #fff;
font-size: 100px;
则能看到有拉伸效果的文字。
import引入
搭建一个用于测试的vue项目LibTest,或者,更方便快捷一点的,在已有的vue的项目中加一个测试组件,并添加到routes中。
在myLib组件库项目根目录下执行 npm link
cd bs-display
npm link
在测试项目根目录下执行npm link bs-display
cd LibTest
npm link bs-display //这个bs-display是在bs-display项目的package.json中定义的"name": "bs-display"
然后,就可以和普通npm安装的组件库一样使用了
在测试项目LibTest的入口js中,引入bs-display,执行Vue.use()注册组件
import { Frame } from 'bs-display' //按需引入
Vue.use(Frame)
在LibTest的App.vue中使用组件:
<template>
<div>
<bsd-frame><div>大屏内容</div></bsd-frame>
</div>
</template>
npm发布
注册npm账号
在npm官网按照提示注册账号。npm官网
登录npm账号
在命令行登录npm账号。
在命令行输入:
npm login
就会出现下面的登录界面
如果你的npm源是淘宝镜像,那么需要更换回默认的npm源:
npm config set registry https://registry.npmjs.org/
npm publish
在发布之前,如果你的包引用了第三方包,则需要确保在package.json中的dependencies字段,写入了依赖的包及版本。
修改package.json中的files字段,指定需要上传到npm的文件。
"files": [
"dist" //上传dist文件夹中的所有文件
],
此外,包的名字对应的是package.json中的"name"字段,这里我们将包名改成big-screen-display。
然后,在命令行输入:npm publish。等待发布完成即可。
这是在测试项目中通过npm i big-screen-display --S安装到node_modules中的big-screen-display包的内容。
npm更新
当包的内容进行了更新,需要再次发布时:
首先,运行npm version patch更新版本,它会修改package.json文件中的version值。
然后,再次运行npm publish,就会上传最新版本的包。
npm删除
- npm unpublish big-screen-display@1.0.0 删除指定版本
- npm unpublish big-screen-display --force 删除整个包
结语
以上就是写一个按需加载的vue组件库的全部流程,看完后相信你也能发布属于自己的vue组件库啦,一起加油吧。
如果有需要大屏适配组件的朋友,也欢迎安装big-screen-display。