本篇文章將介紹如何在元件庫中開發一個元件,其中包括
- 如何本地實時除錯元件
- 如何讓元件庫支援全域性引入
- 如何在 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前端進階 檢視完整教程