手把手教你写一个Vue3组件库但是乞丐版

news2025/1/20 5:46:08

好久没写文章了,最近在研究一些组件库的实现方法,分享一下。在这我这篇文章之前其实已经有一篇文章讲了Vue如何打包组件库了(最底部),但是这篇文章一是没有源码二是Vue3和Vue2的组件库写法有点不一样,关于这个我研究了ElementPlus源码一下午,终于找到了正确的使用方法,所以就有了这篇文章。在翻看Element-plus源码的时候发现Element-plus的组件库基本架构与我们本质是一样的,所以本文可以放心食用。

关于使用组件库方式

随便打开一个Vue3的UI组件库,我们可以看到通常有两种引入方法。

  • 第一种:通过script的方式引入
  • 第二种:install后通过import的方法引入

无论第一种还是第二种,引入之后我们通常会这样

const app = createApp(App)
app.use(MyComponents)
app.mount('#app') 

对于第一种script标签引入方式,Vue2和Vue3有着不同的引入方法,下面会详细讲到。 之后我们便可以使用MyComponents里面的所有组件了。在这个app.use里面到底发生了什么,为什么会这样?让我们深入兔子洞一探究竟。(源码在文章最下方)

随便写两个组件

先搭建一个Vue项目,搭建方式可以用cli也可以用vite,我自己简单的通过webpack搭建了一个,这里不再赘述搭建过程。

下面给出两个Vue组件,之后我们将会做出一个包含这两个组件的丐版组件库

封装、构建

文章开头有讲到,组件的使用方式为app.use(我们的组件)所以我们打开官方文档看一下app.use的定义。cn.vuejs.org/api/applica…

下面给出代码实现

// src/index.js
import Hello from './component/Hello/Hello.vue';
import Hi from './component/Hi/Hi.vue';

const components = [Hello,Hi,
];
const componentName = ['Hello','Hi',
];
const install = function (Vue) {components.forEach((component, index) => {Vue.component(componentName[index], component);});
};

export default {install,
};

if (typeof window !== 'undefined' && window.Vue) {install(window.Vue);} 

代码层面的功夫我们就做好了,现在我们需要修改一下webpack配置

 output: {path: path.join(__dirname, '/lib'),filename: () => '[name].js',libraryTarget: 'umd', // 用到的模块定义规范},externals: {vue: {root: 'Vue', // 通过 script 标签引入,此时全局变量中可以访问的是 Vuecommonjs: 'vue', // 可以将vue作为一个 CommonJS 模块访问commonjs2: 'vue', // 和上面的类似,但导出的是 module.exports.defaultamd: 'vue', // 类似于 commonjs,但使用 AMD 模块系统},}, 

文章最底下的链接中文章有说明libraryTargetexternals的作用,这里不再赘述。 之后将构建工具的入口设置为index.js构建。构建完成后我们将package.json的入口设置为我们的构建结果的入口文件,例如我的构建结果为lib/main.js。这样,一个超低配的组件库就封装好了,接下来我们测试一下。

本地测试

首先我们通过script脚本插入这一最简单的测试方法来进行测试

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue3组件库</title>
</head>
<body><div id="app">script引入!<Hello></Hello><Hi></Hi></div>
</body>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="./lib/index.js"></script>
<script> const App = {data() {},};const app = Vue.createApp(App);app.use(VueComponents);app.mount("#app"); </script>
</html> 

渲染结果:

下面通过npm link和import的方式来测试组件库

npm link

首先在我们的组件库根目录运行

npm link 

之后,我们随便通过任意脚手架搭建一个vue项目,在它的根目录运行

npm link test_library 

这样我们就可以像使用普通组件库一样使用它了。

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import Hello from 'test_library'
const app = createApp(App)
app.use(Hello)
app.mount('#app')
// app.vue
<template><div>这是我们的测试代码哦<Hello></Hello><Hi></Hi></div>
</template> 

细心的同学会发现,我们明明没有引入Hi组件,但却能使用这是为什么呢。其实import Hello from 'test_library'这个语句就相当于将lib/index.jsexport出来的对象进行了引入拿到的就是带有install的对象,这个install会在app.use()被调用,也就将两个组件都注册了。那么当我们不想要引入全部组件的时候该怎么做呢?答案是按需引入。

按需引入

所谓按需引入,就是要多少引入多少,例如这样import { Hi } from 'test_library'但是在没处理之前这样引用明显是不行的,毕竟我们的test_library本质上引入的是带有install的对象,所以根本没法拆分,对吧?

那该怎么办呢,答案是将入口变为多个,然后每个组件打包出自己专属的入口文件和css文件,这就开始做!

首先我们还是需要通过App.use()的方法来使用组件,这一点永远不会变,所以在每一个组件的组件文件夹下面写出他们自己的入口文件。

// src/component/Hello/index.js
import Hello from './Hello.vue';
Hello.install = function (Vue) {Vue.component('Hello', Hello);
};
export default Hello;

// src/component/Hi/index.js
import Hi from './Hi.vue';
Hi.install = function (Vue) {Vue.component('Hi', Hi);
};
export default Hi; 

最后通过webpack的多入口打包功能,就可以做到分开打包了。

entry: {hello: './src/component/Hello/index.js',hi: './src/component/Hi/index.js',index: './src/index.js',},output: {path: path.join(__dirname, '/lib'),filename: () => '[name].js',libraryTarget: 'umd', // 用到的模块定义规范}, 

webpack的配置到这里还没算完,既然我们的vue组件进行了拆分,那每一个组件的css代码也要进行拆分才行,所以我们需要用到mini-css-extract-plugin这个插件。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');plugins: [new VueLoaderPlugin(),new CleanWebpackPlugin(),new MiniCssExtractPlugin({filename: 'lib-style/[name].css',}),], 

最后的产物目录如下

接下来我们测试一下

import { createApp } from 'vue'
import App from './App.vue'
import Hi from 'test_library/lib/hi'
import 'test_library/lib/lib-style/hi.css'
const app = createApp(App)
app.use(Hi)
app.mount('#app') 

效果:

通过babel插件优化按需引入

上面的代码我们都实现的很好了,但是似乎有些不对劲,我们平时使用组件库的时候好像是这样的import { 组件a } from '组件库'。 但是也许有同学忘了,在你按需引入组件库的时候你通常还需要装一个babel插件,例如Element-plus里面会让你这样(element-plus.gitee.io/en-US/guide… ),这个插件做的事情就是将 import { 组件a } from '组件库转变成我们上面的引入方式。

现在让我们来使用一下,在我们用来测试组件库组件的项目中的babel.config.js文件加入这些代码

module.exports = {
···"plugins": [["component",{"libraryName": "test_library","styleLibrary": {"name": "lib-style", // same with styleLibraryName"base": false// if theme package has a base.css}}]]
···
} 

更改引用方式

import { createApp } from 'vue'
import App from './App.vue'
import { Hi } from 'test_library'
const app = createApp(App)
app.use(Hi)
app.mount('#app') 

查看最终效果

Vue2与Vue3到底有什么不同

我们都知道,在Vue2中我们创建vue实例的方法是new Vue(),而注册全局组件的方法是Vue.component(),所以由于这个特性我们只需要去简单的注册组件,那无论new多少个vue实例也是会有我们的注册组件的。所以在vue2组件库中如果我们想要在script中注册组件我们只需要,Vue.use(install)(这个install方法就是上面的install方法)。

但是在Vue3中,上面的办法行不通了,因为在Vue3中Vue.component()这个方法被移除了,取而代之的是createApp().component()这就导致了我们无法真正的全局注册并且更坏的情况是我们似乎没办法拿到这个create出来的vue实例。所以我们只能另辟蹊径通过文章中的方式来进行注册。具体Element-plus到底有没有写的和我一样,这个我无从得知代码阅读能力有限。但是可以肯定的是,当通过script引用他们的组件库时,window上却确实有ElementPlus这个对象。

// Vue2
import Hello from './component/Hello/Hello.vue';
import Hi from './component/Hi/Hi.vue';

const components = [Hello,Hi,
];
const componentName = ['Hello','Hi',
];
const install = function (Vue) {components.forEach((component, index) => {Vue.component(componentName[index], component);});
};

const VueComponents = { install }
if (typeof window !== 'undefined' && window.Vue) {Vue.use(install)
}
export default VueComponents
// Vue2在script中的使用,可以不用use,直接使用(因为已经注册)

// Vue3
import Hello from './component/Hello/Hello.vue';
import Hi from './component/Hi/Hi.vue';

const components = [Hello,Hi,
];
const componentName = ['Hello','Hi',
];
const install = function (Vue) {components.forEach((component, index) => {Vue.component(componentName[index], component);});
};

const VueComponents = { install }

if (typeof window !== 'undefined') {window.VueComponents = VueComponents
}
export default VueComponents
// Vue3在script中的使用,需要use
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="./lib/index.js"></script>
<script> const App = {data() {},};const app = Vue.createApp(App);app.use(VueComponents);app.mount("#app"); </script> 

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/48654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据挖掘-理论与算法 公开课笔记

1.1.1.1 整装待发 近年来数据存储和数据处理的能力都产生了飞跃&#xff0c;为数据挖掘奠定了基础。虽然数据量大&#xff0c;但是真正有用的信息少 2.1.2.1 学而不思则罔 是多学科&#xff08;机器学习、人工智能、模式识别、统计学&#xff09;的交叉领域如何学习数据挖掘&…

【分布式能源的选址与定容】基于非支配排序多目标粒子群优化算法求解分布式能源的选址与定容附Matlab代码

​✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法…

【HDU No. 1166】 敌兵布阵

【HDU No. 1166】 敌兵布阵 杭电 OJ 题目地址 【题意】 A国在海岸线沿直线布置了N 个工兵营地。C国通过先进的监测手段对A国每个工兵营地的人数都掌握得一清二楚。每个工兵营地的人数都可能发生变动&#xff0c;可能增加或减少若干人手。 【输入输出】 输入&#xff1a; 第…

知识整理:1802907-99-8,Desthiobiotin-PEG4-Alkyne生物素类似物

&#xff08;本品应密封避光&#xff0c;储存于阴凉&#xff0c;干燥&#xff0c;通风处&#xff0c;取用一定要干燥&#xff0c;避免频繁的溶解和冻干&#xff09; ●中文名&#xff1a;脱硫生物素-四聚乙二醇-炔基 ●英文&#xff1a;Desthiobiotin-PEG4-Alkyne ●外观以及性…

浮点数渐进下溢

文章目录浮点数渐进下溢浮点数渐进下溢 当IEEE754浮点数的运算结果或转化结果中&#xff0c;存在阶码全0的情况时&#xff0c;在IEEE754标准的描述中说&#xff0c;若此时尾数不全为0&#xff0c;则表示次正规数&#xff0c;即次数浮点数的真值其实应该成为&#xff1a; (−1)…

YUV数据格式

1. YUV的原理 YUV 的原理是把亮度&#xff08;Luma&#xff09;与色度&#xff08;Chroma&#xff09;分离。 “Y”表示亮度&#xff0c;也就是灰度值。 “U”表示蓝色通道与亮度的差值。 “V”表示红色通道与亮度的差值。 其中 Y 信号分量除了表示亮度信号外&#xff0c;还含…

Redis学习笔记(一)

NoSQL 泛指非关系型数据库&#xff0c;作为关系型数据库的补充作用&#xff1a;应对海量用户和海量数据前提下的数据处理问题特征 可扩容、可伸缩大数据量下高性能灵活的数据模型高可用 常见的NoSQL数据库 RedismemcacheHBaseMongoDB Redis 一种高性能键值对数据库特征 数据间…

[附源码]计算机毕业设计springboot酒店在线预约咨询小程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

STL 迭代器萃取

导言 什么是迭代器 迭代器是一种抽象的设计概念&#xff0c;《Design Patterns》一书中对于 iterator 模式的定义如下&#xff1a;提供一种方法&#xff0c;使之能够依序巡访某个聚合物&#xff08;容器&#xff09;所含的各个元素&#xff0c;而又无需暴露该聚合物的内部表述…

wcdma基站的重选和切换

首先移动组网的特点&#xff0c;单个基站覆盖一定区域范围&#xff0c;我们称之为小区&#xff0c;为了组成一个连续服务不断的网&#xff0c;需要在空间上部署多个基站&#xff0c;应对用户的移动。 为了实现业务的连续性&#xff0c;必须给每个小区设置相邻的小区&#xff0c…

C/C++-指针

C/C-指针参考1. 指针指针与内存/地址指针使用2.数组指针数组/指针/sizeof一维数组与指针多维数组指针3.字符/字符串指针4. 其他指针二级指针 -- 还没看空指针void指针野指针5.指针与函数函数指针引用传递指针函数6.结构体指针结构体数组指针???c 对象指针参考 https://www.…

Kotlin 开发Android app(十四):startActivity跳转Activity活动

从一个Activity跳到另一个Activity 在编写安卓代码是最常见的事情了。我们不可能在一个页面中&#xff0c;把所有的事情都做完。 在kotlin中跳转的程序也比较简单&#xff0c;跟java差不多。如果熟悉java代码的话&#xff0c;只需要把代码改变过来而已。 带参数的调整 从一个…

极空间Docker安装Alist套件整合阿里云盘、百度云盘等网盘资源并挂载到本地供极影视刮削播放完整教程

文章目录0、前言1、在docker中安装alist套件1.1、拉取并下载alist镜像1.2.安装alist镜像2、访问并设置alist2.1、访问alist2.2、配置alist2.2.1、在alist中添加阿里云盘2.2.2、在alist中添加其它网盘3、在极空间中将前述网盘挂载到本地4、在极影视中扫描刮削挂载到本地的云盘中…

如何制作一个微信小程序【微信小程序是怎么做的】

为什么现在这么多人使用微信小程序呢&#xff1f;因为微信小程序除了便捷易开发&#xff0c;公司企业可以用来做小程序展示官网&#xff0c;商家也可以做小程序商城&#xff0c;甚至个人也可以拥有自己的小程序。那么如何制作一个微信小程序&#xff1f;微信小程序是怎么做的呢…

第二证券|房地产股债嗨了,百余只个股谁受热捧?谁还受益?

29日&#xff0c;AH股房地产板块狂飙&#xff0c;地产债反常火热。 A股地产股开盘即掀涨停潮&#xff0c;中国武夷、中交地产、空港股份、光大嘉宝、中华企业等超10股竞价涨停。港股内房股大幅高开&#xff0c;碧桂园、富力地产、新城开展等多股涨超10%&#xff0c;盘中三巽集…

Crack:Stimulsoft BI Server 2022.4.5

Stimulsoft BI Server 是一个客户端-服务器系统&#xff0c;可让您高效且有效地实施使用报告和仪表板的完整周期&#xff0c;从执行信息处理任务的设计和自动化开始&#xff0c;到为方便地向用户展示结果做准备结束。报告模块的功能和功能是使用 Stimulsoft 的快速现代技术实现…

一、Vue3基础[组件(props、事件、插槽)]

一、组件化 解释:正如上图所示,一个页面可以分为多块部分,但是如果把所有代码都写在一个vue文件当中,维护性和可读性都会很差,所以需要用到组件化思维->创建多个vue文件每个里面写一部分代码,然后集中在一个主的vue文件调用 二、组件的注册 1.全局 解释:顾名思义,…

【Java盲点攻克】「时间与时区系列」让我们一起完全吃透对于时区和日期相关的功能开发原理

技术简介 java中的日期处理一直是个问题&#xff0c;没有很好的方式去处理&#xff0c;所以才有第三方框架的位置比如joda。文章主要对java日期处理的详解&#xff0c;用1.8可以不用joda。 时间概念 首先我们对一些基本的概念做一些介绍&#xff0c;其中可以将GMT和UTC表示时…

自然算法 - AI面试基础补全

手撕BP神经网络手写Bert和Transformer&#xff08;BERT很细节的地方&#xff0c;比如文字标签CLS&#xff0c;par&#xff09;学习pytorch&#xff0c;tensorflow AI算法岗位 可看网站 牛客网站 面经回复 github 项目连接 算法工程师岗位必备知识 问答 ELMO、GPT、…

Linux系统下KVM虚拟机的基本管理和操作

Linux系统下KVM虚拟机的基本管理和操作一、检查本地环境1.检查系统版本2.检查防火墙状态3.检查selinux3.检查libvirtd服务状态4.检查kvm安装结果5.检查kvm虚拟机状态6.检查virsh版本二、virsh常用命令1.列出虚拟机2.虚拟机开关机操作3.删除虚拟机4.设置虚拟机在宿主机开机时自启…