本篇文章將介紹如何在組件庫中開發一個組件,其中包括 如何本地實時調試組件 如何讓組件庫支持全局引入 如何在 setup 語法糖下給組件命名 如何開發一個組件 目錄結構 在packages目錄下新建components和utils兩個包,其中components就是我們組件存放的位置,而utils包則 ...
本篇文章將介紹如何在組件庫中開發一個組件,其中包括
- 如何本地實時調試組件
- 如何讓組件庫支持全局引入
- 如何在 setup 語法糖下給組件命名
- 如何開發一個組件
目錄結構
在packages
目錄下新建components
和utils
兩個包,其中components
就是我們組件存放的位置,而utils
包則是存放一些公共的方法之類的。分別在兩個文件下執行pnpm init
,並將它們的包名改為@easyest/components
和@easyest/utils
{
"name": "@easyest/components",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
在components
目錄下新建src
目錄用於存放所有組件,最終目錄結構為
當然這隻是目前的結構,後面會進行調整,因為還有樣式,測試等文件目錄
測試組件
在button.vue
文件中寫一個簡單的按鈕
<template>
<button>測試按鈕</button>
</template>
然後在button/index.ts
將其導出
import Button from "./button.vue";
export { Button };
export default Button;
因為我們後面會有很多組件的,比如 Icon,Upload,Select 等,所以我們需要在components/src/index.ts
集中導出所有組件
export * from "./button";
最後在components/index.ts
導出所有組件提供給外部使用
export * from "./src/index";
接下來我們在上篇文章中搭建的 play 項目中進行一個測試,首先在 paly 項目中本地安裝@easyest/components
(組件庫包名,後續發佈可以自己修改名字)
pnpm add @easyest/components
然後再app.vue
中引用Button
<template>
<div>
<Button />
</div>
</template>
<script lang="ts" setup>
import { Button } from "@easyest/components";
</script>
啟動項目便可以看到 Button 組件了,並且修改 Button 組件也會有熱更新的效果
app.use 全局掛載組件
有的時候我們使用組件的時候想要直直接使用 app.use()掛載整個組件庫,其實使用 app.use()的時候它會調用傳入參數的 install 方法,因此首先我們給每個組件添加一個 install 方法,然後再導出整個組件庫,我們將 button/index.ts 改為
import _Button from "./button.vue";
import type { App, Plugin } from "vue";
type SFCWithInstall<T> = T & Plugin;
const withInstall = <T>(comp: T) => {
(comp as SFCWithInstall<T>).install = (app: App) => {
const name = (comp as any).name;
//註冊組件
app.component(name, comp as SFCWithInstall<T>);
};
return comp as SFCWithInstall<T>;
};
export const Button = withInstall(_Button);
export default Button;
components/index.ts 修改為
import * as components from "./src/index";
export * from "./src/index";
import { App } from "vue";
export default {
install: (app: App) => {
for (let c in components) {
app.use(components[c]);
}
},
};
此時我們需要給button.vue
一個name:ea-button
好在全局掛載的時候作為組件名使用
<template>
<button>測試按鈕</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "ea-button",
setup() {
return {};
},
});
</script>
這時候在play/main.ts
中全局掛載組件庫
import { createApp } from "vue";
import App from "./app.vue";
import easyest from "@easyest/components";
const app = createApp(App);
app.use(easyest);
app.mount("#app");
app.vue 中使用ea-button
組件,然後就會發現組件庫掛載成功了
<template>
<div>
<ea-button />
</div>
</template>
<script lang="ts" setup></script>
但是這個全局組件並沒有任何屬性提示,所以我們要藉助vscode中的volar給全局組件加上提示效果
首先安裝@vue/runtime-core
pnpm add @vue/runtime-core -D -w
在src下新建components.d.ts
import * as components from "./index";
declare module "@vue/runtime-core" {
export interface GlobalComponents {
EaButton: typeof components.Button;
EaIcon: typeof components.Icon;
}
}
export {};
此時全局引入的組件也有了提示效果
註意:當用戶使用組件庫的時候需要讓用戶在tsconfig.json中配置types:["easyest/lib/src/components"]才會出現提示效果
"compilerOptions": {
//...
"types": ["easyest/lib/src/components"]
},
使用 setup 語法
我們都知道,使用 setup 語法進行 Vue 組件的開發是非常方便的,但是會有一個問題,就是當我們使用 setup 語法時該怎麼給組件命名呢?
其實有兩種解決方法,一個是再寫一個script
標簽命名,比如input.vue
<template>
<button>測試按鈕</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "ea-button"
});
</script>
<script lang="ts" setup></script>
這種方式顯然是比較奇怪的
第二種方式就是使用插件unplugin-vue-define-options
解決,在測試環境中,我們需要把它配置在 play 項目中
首先全局安裝unplugin-vue-define-options
,因為這個插件後面打包配置也需要用到,最新版本安裝會提示錯誤,看後續作者如何解決吧,暫時用// @ts-ignore
忽略
pnpm add unplugin-vue-define-options -D -w
然後在play/vite.config.ts
引入該插件
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// @ts-ignore
import DefineOptions from "unplugin-vue-define-options/vite";
export default defineConfig({
plugins: [vue(), DefineOptions()],
});
此時我們便可以直接使用defineOptions
函數定義組件名了
<template>
<button>測試按鈕</button>
</template>
<script lang="ts" setup>
defineOptions({ name: "ea-button" });
</script>
組件開發
我們都知道一個組件需要接受一些參數來實現不同效果,比如 Button 組件就需要接收type
、size
、round
等屬性,這裡我們暫且只接收一個屬性type
來開發一個簡單的 Button 組件。
我們可以根據傳入的不同type
來賦予 Button 組件不同類名
// button.vue
<template>
<button class="ea-button" :class="buttonStyle"><slot /></button>
</template>
<script lang="ts" setup>
import "./style/index.less";
import { computed } from "vue";
defineOptions({ name: "ea-button" });
type ButtonProps = {
type?: string;
};
const buttonProps = defineProps<ButtonProps>();
const buttonStyle = computed(() => {
return { [`ea-button--${buttonProps.type}`]: buttonProps.type };
});
</script>
這裡引入了樣式文件,在 button 目錄下新建 style 文件夾來存放 Button 組件的樣式
src/button/style/index.less
如下
.ea-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: 0.1s;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.ea-button.ea-button--primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
&:hover {
background: #66b1ff;
border-color: #66b1ff;
color: #fff;
}
}
此時在 app.vue 中引入 Button 組件就可以看到想要的效果了
<template>
<div>
<Button type="primary">主要按鈕</Button>
</div>
</template>
<script lang="ts" setup>
import { Button } from "@easyest/components";
</script>
由於組件的開發可能涉及的內容比較多,這裡就不詳細展開,這裡只簡單介紹一下組件開發的大致思路,後續會專門對一些常用組件進行開發,歡迎點贊收藏加關註!
本文對應代碼地址 如何開發一個組件,動動小手Star一下謝謝
關註公眾號web前端進階 查看完整教程