随着前端项目越来越复杂,如何开发一个可以随处使用的组件库变得尤为重要。本文将带你从0开始,实现一个完全独立的Vue组件库,包含样式隔离、主题定制等核心功能。
在日常开发中,我们经常需要在不同项目间复用组件,但直接复制代码显然不是一个好办法。如何开发一个可以即插即用的组件库呢?本文将从实战角度出发,手把手教你实现。
首先创建项目并安装依赖:
# 创建项目目录
mkdir micro-ct && cd micro-ct
# 初始化package.json
npm init -y
# 安装核心依赖
npm install [email protected] [email protected] [email protected] [email protected] --save
# 安装开发依赖
npm install rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-babel @rollup/plugin-replace rollup-plugin-vue rollup-plugin-postcss postcss-prefix-selector --save-dev
创建 rollup.config.js
:
import commonjs from '@rollup/plugin-commonjs'
import vue from 'rollup-plugin-vue'
import babel from '@rollup/plugin-babel'
import { terser } from 'rollup-plugin-terser'
import postcss from 'rollup-plugin-postcss'
export default {
input: 'src/main.js',
output: {
file: 'dist/micro-ct.js',
format: 'iife',
name: 'MicroCT',
globals: {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
'ant-design-vue': 'antd'
}
},
external: ['vue', 'vue-router', 'vuex', 'ant-design-vue'],
plugins: [
postcss({
plugins: [
require('postcss-prefix-selector')({
prefix: '.micro-ct-root',
exclude: ['.micro-ct-root']
})
],
extract: 'micro-ct.css'
}),
vue({
css: false
}),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**'
}),
terser()
]
}
这里有几个关键点:
format: 'iife'
- 打包成立即执行函数,避免污染全局external
- 外部依赖不打包,减小体积postcss-prefix-selector
- 添加样式前缀,实现样式隔离创建 src/main.js
:
import Vue from 'vue'
import App from './App.vue'
import store from './store'
// 事件总线,用于页面切换
export const EventBus = new Vue()
const MicroCT = {
init(options = {}) {
const { container, width, height } = options
const app = new Vue({
store,
render: h => h(App, {
props: { width, height }
})
})
app.$mount(container || '#micro-ct-container')
return app
},
// 页面跳转API
goTo(pageName) {
EventBus.$emit('change-page', pageName)
},
// 获取当前页面
getCurrentPage() {
return localStorage.getItem('MicroCtCurrentPage') || 'home'
}
}
export default MicroCT
创建 src/components/PageManager.vue
:
创建 src/styles/variables.css
:
:root {
--mc-primary-color: #f56c6c;
--mc-text-color: #303133;
--mc-border-radius: 8px;
--mc-background-color: #fff;
--mc-font-size: 16px;
--mc-padding: 30px;
--mc-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
在组件中使用:
DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/[email protected]/dist/vue.js">script>
<script src="https://unpkg.com/[email protected]/dist/vuex.js">script>
<script src="dist/micro-ct.js">script>
<link rel="stylesheet" href="dist/micro-ct.css">
head>
<body>
<div id="micro-ct-container">div>
<script>
// 初始化
MicroCT.init({
container: '#micro-ct-container',
width: '100%',
height: '500px'
})
// 页面跳转
MicroCT.goTo('about')
script>
body>
html>
#micro-ct-container {
/* 修改主题色 */
--mc-primary-color: #409eff;
--mc-border-radius: 4px;
--mc-font-size: 14px;
}
.block__element--modifier {
/* 样式 */
}
/* 错误 ❌ */
.button { }
/* 正确 ✅ */
.my-component__button { }
/* 错误 ❌ */
.text {
color: #409eff;
}
/* 正确 ✅ */
.text {
color: var(--mc-primary-color);
}
export default {
components: {
HelloWorld: () => import('./components/HelloWorld.vue')
}
}
export default {
props: {
width: {
type: [String, Number],
default: '100%'
},
height: {
type: [String, Number],
required: true
}
}
}
问题:组件样式影响到宿主项目
解决:
问题:打包文件过大
解决:
问题:CSS变量兼容性
解决:
.button {
color: #409eff; /* fallback */
color: var(--mc-primary-color);
}
通过本文,我们学习了:
如果觉得本文对你有帮助,欢迎点赞、收藏、关注!