大前端Vue插件开发
BreezliPlugins 开发
插件 | Vue.js
前言
Vue3中,一个插件通常是一个对象
通常我们开发的插件通过全局导出
从而在项目的入口文件中使用
基础开发
plugins/
1 2 3
| <template> <button>我的按钮</button> </template>
|
index.ts
1 2 3 4 5 6
| import MyButton from './MyButton.vue' export default{ install:(app,options)=>{ app.component('myButton', MyButton) } }
|
main.js
1 2 3
| import MyButton from './plugins/MyButton.ts'
create(App).use(MyButton).mount('#app')
|
Views/
Helloworld.vue
1 2 3 4 5
| <template> <div class="home"> <myButton></myButton> </div> </template>
|
多插件开发
components/
1 2 3
| <template> <button>我的按钮</button> </template>
|
1 2 3 4 5
| <template> <div class="er-button-group"> <slot></slot> </div> </template>
|
index.ts
导出 MyButton
和 MyButtonGroup
组件
使用 withInstall
函数为它们添加安装方法
1 2 3 4 5 6 7 8
| import Button from "./MyButton.vue"; import ButtonGroup from "./MyButtonGroup.vue"; import { withInstall } from "@tyche/utils";
export const ErButton = withInstall(Button); export const ErButtonGroup = withInstall(ButtonGroup);
export * from "./types";
|
utils/
install.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import type { App, Plugin, Directive } from "vue";
import { noop } from "lodash-es";
type SFCWithInstall<T> = T & Plugin;
export const withInstall = <T>(component: T) => { (component as SFCWithInstall<T>).install = (app: App) => { const name = (component as any)?.name || "UnnamedComponent"; app.component(name, component as SFCWithInstall<T>); }; return component as SFCWithInstall<T>; };
|
style.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { isNumber, isString } from "lodash-es"; import { debugWarn } from "./error";
const SCOPE = "utils/style" as const;
const isStringNumber = (val: string): boolean => { if (!isString(val)) { return false; } return !Number.isNaN(Number(val)); }; export function addUnit(value?: string | number, defaultUnit = "px") { if (!value) return ""; if (isNumber(value) || isStringNumber(value)) { return `${value}${defaultUnit}`; } if (isString(value)) { return value; } debugWarn(SCOPE, "binding value must be a string or number"); }
|
error.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { isString } from "lodash-es";
class ErUIError extends Error { constructor(message: string) { super(message); this.name = "ErUIError"; } }
export function throwError(scope: string, msg: string) { throw new ErUIError(`[${scope}] ${msg}`); }
export function debugWarn(error: Error): void; export function debugWarn(scope: string, msg: string): void; export function debugWarn(scope: string | Error, msg?: string) { if (process.env.NODE_ENV !== "production") { const err = isString(scope) ? new ErUIError(`[${scope}] ${msg}`) : scope; console.warn(err); } }
|
index.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| export * from './install' import { defineComponent } from "vue"; import { isFunction } from "lodash-es";
export const RenderVnode = defineComponent({ props: { vNode: { type: [String, Object, Function], required: true, }, }, setup(props) { return () => (isFunction(props.vNode) ? props.vNode() : props.vNode); }, });
export const typeIconMap = new Map([ ["info", "circle-info"], ["success", "check-circle"], ["warning", "circle-exclamation"], ["danger", "circle-xmark"], ["error", "circle-xmark"], ]);
export * from "./install"; export * from "./error"; export * from "./style";
|
core/
componens.ts
集合所有需要全局注册的组件,并将其作为一个插件数组导出
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { ErButton, ErButtonGroup, ... } from "@tyche/components";
import type { Plugin } from 'vue'
export default [ ErButton, ErButtonGroup, ... ] as Plugin[]
|
makeInstaller.ts
创建一个通用的安装器,用于批量安装组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import type { App, Plugin } from "vue"; import { INSTALLED_KEY } from "@tyche/constants"; import { each, get, set } from "lodash-es";
export default function makeInstaller(components: Plugin[]) { const install = (app: App) => { if (get(app, INSTALLED_KEY)) return; set(app, INSTALLED_KEY, true);
each(components, (c) => { app.use(c); }); };
return install; }
|
注:以下是constants/index.ts
1
| export const INSTALLED_KEY = Symbol("INSTALLED_KEY");
|
index.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { library } from "@fortawesome/fontawesome-svg-core"; import { fas } from "@fortawesome/free-solid-svg-icons"; import makeInstaller from './makeInstaller' import components from './components' import printLogo from "./pringLogo"; import '@tyche/theme/index.css'
printLogo();
library.add(fas); const installer = makeInstaller(components);
export * from '@tyche/components' export default installer
|
docs/
components
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| --- title: Button description: Button 组件文档
next: link: /components/collapse text: Collapse 折叠面板
prev: link: /get-started text: 快速开始 ---
# Button 按钮
常用的操作按钮。
## 基础用法
使用 `type`、`plain`、 `round`和 `circle`来定义按钮的样式。
::: preview demo-preview=../demo/button/Basic.vue :::
|
demo
Basic.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <template> <p> <er-button>Default</er-button> <er-button type="primary">Primary</er-button> <er-button type="success">Success</er-button> <er-button type="info">Info</er-button> <er-button type="warning">Warning</er-button> <er-button type="danger">Danger</er-button> </p>
<p> <er-button plain>Plain</er-button> <er-button type="primary" plain>Primary</er-button> <er-button type="success" plain>Success</er-button> <er-button type="info" plain>Info</er-button> <er-button type="warning" plain>Warning</er-button> <er-button type="danger" plain>Danger</er-button> </p>
<p> <er-button round>Round</er-button> <er-button type="primary" round>Primary</er-button> <er-button type="success" round>Success</er-button> <er-button type="info" round>Info</er-button> <er-button type="warning" round>Warning</er-button> <er-button type="danger" round>Danger</er-button> </p>
<p> <er-button icon="search" circle /> <er-button type="primary" icon="edit" circle /> <er-button type="success" icon="check" circle /> <er-button type="info" icon="message" circle /> <er-button type="warning" icon="star" circle /> <er-button type="danger" icon="trash" circle /> </p> </template>
|