Build Vue3 component library from 0 (4): How to develop a component

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 packagescomponents are stored, and the utils package stores some public methods and the like. Execute @easyest/components @easyest/utils under two files respectivelycomponentsutilscomponentspnpm 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"
}

componentsCreate a new directory under the directory to srcstore all components. The final directory structure is
insert image description here
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.vueWrite 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.tsexport 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.vuequote 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 updateinsert image description here

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.vuea name:ea-buttongood 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.tsmount 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-buttoncomponents 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>

insert image description here
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 {
    
    };

insert image description here
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 scriptlabel 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-optionsto 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-ignoreignore

pnpm add unplugin-vue-define-options  -D -w

Then play/vite.config.tsimport 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 defineOptionsthe 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、roundattributes such as etc. Here we only accept one attribute typeto 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.lessas 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>

insert image description here
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!

Guess you like

Origin blog.csdn.net/weixin_45821809/article/details/130273856