This article will introduce how to develop a component in the component library, including
- How to debug components in real time locally
- How to make the component library support global import
- How to name components under the syntax sugar of setup
- How to develop a component
Directory Structure
Create a new and two packages under the directory, where our packages
components are stored, and the utils package stores some public methods and the like. Execute @easyest/components @easyest/utils under two files respectivelycomponents
utils
components
pnpm init,并将它们的包名改为
和
{
"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
Create a new directory under the directory to src
store all components. The final directory structure is
of course this is only the current structure, and it will be adjusted later, because there are also file directories such as styles and tests.
test component
button.vue
Write a simple button in the file
<template>
<button>测试按钮</button>
</template>
Then export it in button/index.ts
import Button from "./button.vue";
export {
Button };
export default Button;
Because we will have many components later, such as Icon, Upload, Select, etc., we need to export all components in the components/src/index.ts set
export * from "./button";
Finally, components/index.ts
export all components for external use
export * from "./src/index";
Next, we will conduct a test in the play project built in the previous article. First, install it locally in the paly project @easyest/components
(component library package name, you can modify the name yourself in subsequent releases)
pnpm add @easyest/components
and then app.vue
quote inButton
<template>
<div>
<Button />
</div>
</template>
<script lang="ts" setup>
import {
Button } from "@easyest/components";
</script>
You can see the Button component when you start the project, and modifying the Button component will also have the effect of hot update
app.use global mount component
Sometimes when we use components, we want to directly use app.use() to mount the entire component library. In fact, when using app.use(), it will call the install method of the incoming parameters, so first we give each component Add an install method, and then export the entire component library, we change button/index.ts to
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 is modified to
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]);
}
},
};
At this point we need to give button.vue
a name:ea-button
good name to use as a component name when mounting globally
<template>
<button>测试按钮</button>
</template>
<script lang="ts">
import {
defineComponent } from "vue";
export default defineComponent({
name: "ea-button",
setup() {
return {
};
},
});
</script>
At this time, play/main.ts
mount the component library globally in
import {
createApp } from "vue";
import App from "./app.vue";
import easyest from "@easyest/components";
const app = createApp(App);
app.use(easyest);
app.mount("#app");
Use ea-button
components in app.vue, and then you will find that the component library is mounted successfully
<template>
<div>
<ea-button />
</div>
</template>
<script lang="ts" setup></script>
But this global component does not have any property prompts, so we need to use volar in vscode to add prompt effects to global components
install first@vue/runtime-core
pnpm add @vue/runtime-core -D -w
Create a new one under srccomponents.d.ts
import * as components from "./index";
declare module "@vue/runtime-core" {
export interface GlobalComponents {
EaButton: typeof components.Button;
EaIcon: typeof components.Icon;
}
}
export {
};
At this time, the components introduced globally also have a prompt effect
Note: When the user uses the component library, the user needs to configure the types in tsconfig.json: ["easyest/lib/src/components"] before the prompt effect will appear
"compilerOptions": {
//...
"types": ["easyest/lib/src/components"]
},
Use the setup syntax
We all know that it is very convenient to use the setup syntax to develop Vue components, but there is a problem, that is, how to name the components when we use the setup syntax?
In fact, there are two solutions, one is to write another script
label name, such asinput.vue
<template>
<button>测试按钮</button>
</template>
<script lang="ts">
import {
defineComponent } from "vue";
export default defineComponent({
name: "ea-button"
});
</script>
<script lang="ts" setup></script>
This method is obviously strange.
The second way is to use a plug-in unplugin-vue-define-options
to solve it. In the test environment, we need to configure it in the play project.
First, install it globally unplugin-vue-define-options
, because this plug-in will also be used for packaging and configuration later. The latest version installation will Prompt error, see how the follow-up author solves it, temporarily // @ts-ignore
ignore
pnpm add unplugin-vue-define-options -D -w
Then play/vite.config.ts
import the plugin
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()],
});
At this point we can directly use defineOptions
the function to define the component name
<template>
<button>测试按钮</button>
</template>
<script lang="ts" setup>
defineOptions({
name: "ea-button" });
</script>
Component development
We all know that a component needs to accept some parameters to achieve different effects. For example, the Button component needs to receive type、size、round
attributes such as etc. Here we only accept one attribute type
to develop a simple Button component. We can give the Button component different class names
according to the incomingtype
// 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>
The style file is introduced here, and a new style folder is created in the button directory to store the style of the Button component
src/button/style/index.less
as follows
.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;
}
}
At this point, you can see the desired effect by introducing the Button component in app.vue
<template>
<div>
<Button type="primary">主要按钮</Button>
</div>
</template>
<script lang="ts" setup>
import {
Button } from "@easyest/components";
</script>
Since the development of components may involve a lot of content, I will not go into details here. Here I will only briefly introduce the general idea of component development. In the future, some common components will be developed. Welcome to like, collect and pay attention!