大家好,今天给大家分享的是如何在Vue中开发一个组件库。我们在开发中经常会用到一些ui 组件库,比如element plus , vant ui 等。 这些ui组件库封装了非常丰富的组件,我们使用起来非常方便。安装,导入,就可以使用了。那么我们能不能开发一个自己的ui组件库呢!
今天,我将带领大家一起探讨如何在 Vue 中开发一个简单的组件库。我们的目标是创建一个包含两个组件的库:UiButton 和 UiDialog。这两个组件将分别支持内容自定义、样式变化、事件处理等功能,并能够通过 app.use 的形式进行全局注册。
需求分析
具体需求如下:
- 需要开发一个组件库
- 这个组件库包含两个组件, UiButton 组件和UiDialog 组件
- UiButton 组件要支持里面的内容自定义,比如自定义文案,甚至可能会加入图标等
- UiButton 组件还需要支持根据传入type 来决定显示对应颜色的按钮
- UiDialog 需要支持弹框标题的传入
- UiDialog 需要支持内容模板自定义
- UiDialog 底部也需要至支持模板自定义
- UiDialog 要有一个关闭按钮,点击可以关闭按钮向外界发送事件,外界进行关闭
- 这个组件库需要支持全部导入和按需导入
- 这个组件库需要使用app.use的形式使用
我们先来实现一个UiButton 组件。 即第三条和第四条需求开发
UiButton 组件实现
- 在components 下面新建一个文件夹UiPlus用来存放我们全部的ui组件
- 在UiPlus 下面新建UiButton 文件夹, 并在该文件夹下新建UiButton.vue
- 编写UiButton.vue 组件代码
<template>
<button class="ui-button" :class="'btn-' + type">
<slot></slot>
</button>
</template>
<script setup>
const props = defineProps({
type: {
type: String,
validator(value) {
return ['primary', 'success', 'info', 'warning', 'danger'].includes(value)
}
}
})
</script>
<style lang="scss" scoped>
.ui-button {
border: 1px solid #dcdfe6;
border-radius: 4px;
color: #606266;
padding: 8px 15px;
background: #fff;
cursor: pointer;
&.btn-primary {
background: #409eff;
border-color: #409eff;
color: #fff;
&:hover{
background: rgb(121.3, 187.1, 255);
border-color: rgb(121.3, 187.1, 255);
}
}
&.btn-success {
background: #67c23a;
border-color: #67c23a;
color: #fff;
&:hover{
background: rgb(148.6, 212.3, 117.1);
border-color: rgb(148.6, 212.3, 117.1);
}
}
&.btn-info {
background: #909399;
border-color: #909399;
color: #fff;
&:hover {
background: rgb(177.3, 179.4, 183.6);
border-color: rgb(177.3, 179.4, 183.6);
}
}
&.btn-warning {
background: #e6a23c;
border-color: #e6a23c;
color: #fff;
&:hover {
background: rgb(237.5, 189.9, 118.5);
border-color: rgb(237.5, 189.9, 118.5);
}
}
&.btn-danger {
background: #f56c6c;
border-color: #f56c6c;
color: #fff;
&:hover {
background: rgb(248, 152.1, 152.1);
border-color: rgb(248, 152.1, 152.1);
}
}
}
</style>
由上面的组件代码可以看出
- 我们定义了type 属性,需要外界传入,并且添加了验证,满足第四条需求。
- 添加了slot 占位符。用户可以自定义button 显示的内容,满足第四条需求
现在我们再来开发UiDialog
UiDialog 组件实现
- 在UiPlus下面新建UiDialog文件夹, 并在UiDialog 文件夹下面新建UiDialog.vue
- 编写UiDialog 组件代码
<template>
<div class="dialog-wrap" v-if="model">
<div class="dialog">
<div class="header">
<h3>{{ title }}</h3>
<span class="close" @click="close">X</span>
</div>
<div class="body">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
title: {
type: String,
default: 'dialog title'
}
})
const model = defineModel()
const emit = defineEmits(['close'])
const close = () => {
emit('close')
}
</script>
<style lang="scss" scoped>
h3{
margin: 0;
}
.dialog-wrap {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0,0,0,0.5);
.dialog {
position: fixed;
width: 600px;
height: 320px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: #fff;
border-radius: 4px;
box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, .04), 0px 8px 20px rgba(0, 0, 0, .08);
.header {
padding: 0 20px;
height: 40px;
line-height: 40px;
display: flex;
justify-content: space-between;
.close {
cursor: pointer;
}
}
.body{
padding: 0 20px;
height: 200px;
overflow: auto;
}
.footer {
display: flex;
justify-content: flex-end;
padding: 0 20px;
}
}
}
</style>
这个UiDialog 组件代码中:
- 我们定义了title 属性,由外界传入,符合第5条需求
- 我们定义了close方法, 点击的关闭按钮的时候触发,并向外界发送close 事件。其次我们使用了defineModel 返回的变量来决定UiDialog 的显示,这意味着,外界可以由v-model 绑定一个变量来决定弹框的显示。外界接收到close事件后将v-model绑定的变量值更改为false 即可。 满足第8条需求
- 我们分别使用了默认插槽和具名插槽来占位弹框的内容,和底部的内容,满足第6,7条需求
现在我们来使用下这两个组件:
<template>
<div>
<UiButton class="btn">default</UiButton>
<UiButton type="primary" class="btn">primary</UiButton>
<UiButton type="success" class="btn">success</UiButton>
<UiButton type="info" class="btn">info</UiButton>
<UiButton type="warning" class="btn">warining</UiButton>
<UiButton type="danger" class="btn">danger</UiButton>
<div style="margin-top:30px;">
<UiButton @click="openDialog">点击显示弹框</UiButton>
</div>
<UiDialog title="删除确认框标题" v-model="showDialog" @close="close">
<p>确定删除100条记录吗</p>
<template #footer>
<UiButton class="btn" @click="close">取消</UiButton>
<UiButton type="primary" @click="close">确认</UiButton>
</template>
</UiDialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
import UiButton from '@/components/UiPlus/UiButton/UiButton.vue'
import UiDialog from '@/components/UiPlus/UiDialog/UiDialog.vue'
const showDialog = ref(false)
const openDialog = () => {
showDialog.value = true
}
const close = () => {
showDialog.value = false
}
</script>
<style scoped>
.btn {
margin-right: 10px;
}
</style>
来看看运行效果:
点击 点击弹框按钮
点击关闭,可以看到弹框也能正常关闭。
现在可以看到大部分需求我们都已经满足了,但是还有最后两条不满足。最后这两条我们该怎么做呢?
按需导入,并能使用app.use 的形式使用组件
在UiButton文件夹下新增index.js 文件 编写index.js 代码如下:
import UiButton from "./UiButton.vue";
export default {
install(app) {
app.component("UiButton", UiButton);
},
};
在UiDialog 文件夹下也新增index.js,编写代码如下
import UiDialog from "./UiDialog.vue";
export default {
install(app) {
app.component("UiDialog", UiDialog);
},
};
修改main.js
import { createApp } from "vue";
import App from "./App.vue";
import UiButton from "./components/UiPlus/UiButton/index";
import UiDialog from "./components/UiPlus/UiDialog/index";
createApp(App).use(UiButton).use(UiDialog).mount("#app");
主要新增了
import UiButton from "./components/UiPlus/UiButton/index";
import UiDialog from "./components/UiPlus/UiDialog/index";
和
.use(UiButton).use(UiDialog)
修改App.vue, 将UiButton和UiDialog 的导入删除。这时候我们再来看看效果:
点击 点击显示弹框
可以看到依然好使。
现在我们完成了按需引入,并且使用use 的方式使用。还差全部导入,一次性use 的方式。
全局一次性导入
在UiPlus 文件夹下新建index.js, 编写代码如下:
import UiButton from "./UiButton/UiButton.vue";
import UiDialog from "./UiDialog/UiDialog.vue";
export default {
install(app) {
app.use("UiButton", UiButton);
app.use("UiDialog", UiDialog);
},
};
修改main.js
将之前的导入UiButton
下的index.js
和UiDialog
文件夹下的index.js
换成了导入UiPlus
下的index
导入,将use的内容 换成use 导入的UiPlus 下的index.js
import { createApp } from "vue";
import App from "./App.vue";
import UiPlus from "./components/UiPlus";
createApp(App).use(UiPlus).mount("#app");
查看运行效果:
点击 点击显示弹框
可以看到效果依然好使。
从最后这两个需求的实现我们可以发现使用install 方法,进行注册组件。在使用时, 就可以使用app.use 的形式进行使用。
通过这次的实践,我们不仅实现了一个简单的组件库,还掌握了如何在 Vue 中进行插件化开发。这为我们在实际项目中开发自定义组件库提供了很好的参考和借鉴。希望这篇文章能对你有所帮助!