组件库
基于element UI创建组件库
优化组件库
创建vue3组件库
vue3组件库添加脚本
本文档使用 MrDoc 发布
-
+
首页
创建vue3组件库
# 创建vue3组件库 ### 搜索并参考资料 1. [Vue Amazing UI | Amazing UI Components Library (themusecatcher.github.io)](https://themusecatcher.github.io/vue-amazing-ui/) 好看 搜索不能使用 2. [pnpm monorepo+vue3+vite组件库搭建_pnpm 私有组件库-CSDN博客](https://blog.csdn.net/weixin_43719925/article/details/136911757) 基本 3. [Vue3+Vite+Element-plus搭建组件库并使用Vitepress编辑组件库文档且发布到 npm并且部署 github pages(vitepress文档渲染.vue组件-推荐使用第二种)_element-plus目录结构-CSDN博客](https://blog.csdn.net/cwin8951/article/details/128903971) vue2组件库作者 4. [如何写一个属于自己的vue3组件库 - 掘金 (juejin.cn)](https://juejin.cn/post/7211521650252398649) 搜索 5. [手把手从零搭建一个 vue3 组件库 (二):为组件编写文档_组件库文档-CSDN博客](https://blog.csdn.net/weixin_43960320/article/details/126474289) 文档可以 搜索不行 存在bug 6. [从零搭建VUE3组件库 - 掘金 (juejin.cn)](https://juejin.cn/post/7213285816491900986#heading-0) 有点复杂 7. [vue3+vite+ts搭建组件库 - 掘金 (juejin.cn)](https://juejin.cn/post/7138811174497288205) 搜索可以 8. [记Vue+vite+pnpm UI组件库搭建过程 - 掘金 (juejin.cn)](https://juejin.cn/post/7114567578193772551#heading-47) > 最终选择 5 3 1 > > 搜索 4 7 > > 经过验证第5个代码存在问题 > > 因此使用第三个 其他资料: [https://juejin.cn/post/7246638858912989241](https://juejin.cn/post/7246638858912989241) ### 创建vue3项目 执行命令`npm init vue@latest` ```bash PS E:\nasGit\demo> npm init vue@latest Vue.js - The Progressive JavaScript Framework √ 请输入项目名称: ... v3-elp-ui √ 是否使用 TypeScript 语法? ... 否 / 是 √ 是否启用 JSX 支持? ... 否 / 是 √ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是 √ 是否引入 Pinia 用于状态管理? ... 否 / 是 √ 是否引入 Vitest 用于单元测试? ... 否 / 是 √ 是否要引入一款端到端(End to End)测试工具? » 不需要 √ 是否引入 ESLint 用于代码质量检测? ... 否 / 是 √ 是否引入 Prettier 用于代码格式化? ... 否 / 是 √ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是 正在初始化项目 E:\nasGit\demo\v3-elp-ui... 项目初始化完成,可执行以下命令: cd v3-elp-ui npm install npm run format npm run dev ``` 将项目中无用的代码删掉,只保留基本的文件 配置`prettier`和`eslint` `.prettierrc.cjs` ```cjs //配置参照 https://prettier.io/docs/en/options.html module.exports = { tabWidth: 2, // tab 使用两个空格 endOfLine: "auto", // 保持现有的行尾 useTabs: false, // 不使用制表符缩进,使用空格缩进 semi: true, // 代码需要分号结尾 quotes: false, // 使用单引号而不是双引号,默认false singleQuote: false, bracketSpacing: true, // 对象左右两侧需要空格 jsxBracketSameLine: false, // html 关闭标签换行 jsxSingleQuote: false, //在JSX中使用单引号 arrowParens: "avoid", // 单参数的箭头函数参数不需要括号 proseWrap: "never", // markdown文档不换行 trailingComma: "all", // 结尾处不加逗号 quoteProps: "as-needed", //自定义引号配置 $schema: "https://json.schemastore.org/prettierrc", printWidth: 100, }; ``` `.eslintrc.cjs` ```cjs /* eslint-env node */ require("@rushstack/eslint-patch/modern-module-resolution"); module.exports = { root: true, extends: [ "plugin:vue/vue3-essential", "eslint:recommended", "@vue/eslint-config-typescript", "@vue/eslint-config-prettier/skip-formatting", ], parserOptions: { ecmaVersion: "latest", }, rules: { // 'no-console': import.meta.env.NODE_ENV === 'production' ? 'warn' : 'off', // 'no-debugger': import.meta.env.NODE_ENV === 'production' ? 'warn' : 'off', // 强制使用一致的缩进 indent: ["error", 2], // 强制使用一致的换行风格 // LF // "linebreak-style": ["error", "unix"], // CRLF "linebreak-style": [0, "error", "windows"], // 强制使用一致的反勾号、双引号或单引号 quotes: [ "error", "double", // backtick、double、single ], // 要求或禁止使用分号代替 ASI semi: ["error", "always"], // 禁止空格和 tab 的混合缩进 "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], // 强制在 function的左括号之前使用一致的空格 // 'space-before-function-paren': [2, 'always'], // 禁止或强制在单行代码块中使用空格(禁用) "block-spacing": [1, "never"], "no-cond-assign": 2, // 禁止 function 定义中出现重名参数 "no-dupe-args": 2, // 禁止对象字面量中出现重复的 key "no-dupe-keys": 2, // 禁止重复的 case 标签 "no-duplicate-case": 2, // 禁止空语句块 "no-empty": 2, // 禁止对 catch 子句的参数重新赋值 "no-ex-assign": 2, // 禁止不必要的布尔转换 "no-extra-boolean-cast": 2, // 禁止不必要的括号 //(a * b) + c;//报错 "no-extra-parens": 0, // 强制所有控制语句使用一致的括号风格 curly: [2, "all"], // 禁止 catch 子句的参数与外层作用域中的变量同名 "no-catch-shadow": 0, // 不允许标签与变量同名 "no-label-var": 2, // 禁用特定的全局变量 "no-restricted-globals": 2, // 禁止 var 声明 与外层作用域的变量同名 "no-shadow": 0, // 禁止覆盖受限制的标识符 "no-shadow-restricted-names": 2, // 禁止将变量初始化为 undefined "no-undef-init": 2, // 禁止将 undefined 作为标识符 "no-undefined": 0, // 不允许在变量定义之前使用它们 "no-use-before-define": 0, // //////////// // 风格指南 // // //////////// // 指定数组的元素之间要以空格隔开(, 后面), never参数:[ 之前和 ] 之后不能带空格,always参数:[ 之前和 ] 之后必须带空格 "array-bracket-spacing": [2, "never"], // 强制使用一致的缩进 第二个参数为 "tab" 时,会使用tab, // if while function 后面的{必须与if在同一行,java风格。 "brace-style": [ 2, "1tbs", { allowSingleLine: true, }, ], // 控制逗号前后的空格 "comma-spacing": [ 2, { before: false, after: true, }, ], // 控制逗号在行尾出现还是在行首出现 (默认行尾) // http://eslint.org/docs/rules/comma-style "comma-style": [2, "last"], // "SwitchCase" (默认:0) 强制 switch 语句中的 case 子句的缩进水平 // 以方括号取对象属性时,[ 后面和 ] 前面是否需要空格, 可选参数 never, always "computed-property-spacing": [2, "never"], // 用于指统一在回调函数中指向this的变量名,箭头函数中的this已经可以指向外层调用者,应该没卵用了 // e.g [0,"self"] 指定只能 var that = this. self不能指向其他任何值,this也不能赋值给self以外的其他值 "consistent-this": [2, "self", "that", "_self", "_that", "me", "_this"], // 强制使用命名的 function 表达式 "func-names": 0, // 文件末尾强制换行 "eol-last": 0, // 要求或禁止在函数标识符和其调用之间有空格 "func-call-spacing": 2, // 强制在对象字面量的属性中键和值之间使用一致的间距 "key-spacing": [ 2, { beforeColon: false, afterColon: true, }, ], // 要求在注释周围有空行 ( 要求在块级注释之前有一空行) "lines-around-comment": [ 0, { beforeBlockComment: true, }, ], "func-style": 0, // 强制回调函数最大嵌套深度 5层 "max-nested-callbacks": [2, 5], // 禁止使用指定的标识符 "id-blacklist": 0, // 强制标识符的最新和最大长度 "id-length": 0, // 要求标识符匹配一个指定的正则表达式 "id-match": 0, // 强制在 JSX 属性中一致地使用双引号或单引号 "jsx-quotes": 0, // 强制在关键字前后使用一致的空格 (前后腰需要) "keyword-spacing": 2, // 强制最大行数 "max-lines": 0, // 强制 function 定义中最多允许的参数数量 "max-params": [1, 5], // 强制 function 块最多允许的的语句数量 "max-statements": [1, 200], // 强制每一行中所允许的最大语句数量 "max-statements-per-line": 0, // 要求构造函数首字母大写 (要求调用 new 操作符时有首字母大小的函数,允许调用首字母大写的函数时没有 new 操作符。) "new-cap": [ 2, { newIsCap: true, capIsNew: false, }, ], // 要求调用无参构造函数时有圆括号 "new-parens": 2, // 要求或禁止 var 声明语句后有一行空行 "newline-after-var": 0, // 禁止使用 Array 构造函数 "no-array-constructor": 2, // 禁用按位运算符 "no-bitwise": 0, // 要求 return 语句之前有一空行 "newline-before-return": 0, // 要求方法链中每个调用都有一个换行符 "newline-per-chained-call": 1, // 禁用 continue 语句 "no-continue": 0, // 禁止在代码行后使用内联注释 "no-inline-comments": 0, // 禁止 if 作为唯一的语句出现在 else 语句中 "no-lonely-if": 0, // 禁止混合使用不同的操作符 "no-mixed-operators": 0, // 不允许多个空行 "no-multiple-empty-lines": [ 2, { max: 2, }, ], // 不允许否定的表达式 "no-negated-condition": 0, // 不允许使用嵌套的三元表达式 "no-nested-ternary": 0, // 禁止使用 Object 的构造函数 "no-new-object": 2, // 禁止使用一元操作符 ++ 和 -- "no-plusplus": 0, // 禁止使用特定的语法 "no-restricted-syntax": 0, // 禁止 function 标识符和括号之间出现空格 "no-spaced-func": 2, // 不允许使用三元操作符 "no-ternary": 0, // 禁用行尾空格 "no-trailing-spaces": 2, // 禁止标识符中有悬空下划线_bar "no-underscore-dangle": 0, // 禁止可以在有更简单的可替代的表达式时使用三元操作符 "no-unneeded-ternary": 2, // 禁止属性前有空白 "no-whitespace-before-property": 2, // 要求或禁止在 var 声明周围换行 "one-var-declaration-per-line": 0, // 要求或禁止在可能的情况下要求使用简化的赋值操作符 "operator-assignment": 0, // 强制操作符使用一致的换行符 "operator-linebreak": [ 2, "after", { overrides: { "?": "before", ":": "before", }, }, ], // 要求或禁止块内填充 "padded-blocks": 0, // 要求对象字面量属性名称用引号括起来 "quote-props": 0, // 要求使用 JSDoc 注释 "require-jsdoc": 0, // 要求或禁止使用分号而不是 ASI(这个才是控制行尾部分号的,) // "semi": [2, "always"], // 强制分号之前和之后使用一致的空格 "semi-spacing": 2, // 要求同一个声明块中的变量按顺序排列 "sort-vars": 0, // 强制在块之前使用一致的空格 "space-before-blocks": [2, "always"], // 强制在圆括号内使用一致的空格 "space-in-parens": [2, "never"], // 要求操作符周围有空格 "space-infix-ops": 2, // 强制在一元操作符前后使用一致的空格 "space-unary-ops": [ 2, { words: true, nonwords: false, }, ], // 强制在注释中 // 或 /* 使用一致的空格 "spaced-comment": [ 2, "always", { markers: ["global", "globals", "eslint", "eslint-disable", "*package", "!"], }, ], // 要求或禁止 Unicode BOM "unicode-bom": 2, // 要求正则表达式被括号括起来 "wrap-regex": 0, // 禁止词法声明 (let、const、function 和 class) 出现在 case或default 子句中 "no-case-declarations": ["warn"], // //////////// // ES6.相关 // // //////////// // 每个模块只能使用一个import "no-duplicate-imports": 2, // 要求箭头函数体使用大括号 "arrow-body-style": 2, // 要求箭头函数的参数使用圆括号 "arrow-parens": 0, "arrow-spacing": [ 2, { before: true, after: true, }, ], // 强制 generator 函数中 * 号周围使用一致的空格 "generator-star-spacing": [ 2, { before: true, after: true, }, ], // 禁止修改类声明的变量 "no-class-assign": 2, // 不允许箭头功能,在那里他们可以混淆的比较 "no-confusing-arrow": 0, // 禁止修改 const 声明的变量 "no-const-assign": 2, // 禁止类成员中出现重复的名称 "no-dupe-class-members": 2, // 禁止 Symbolnew 操作符和 new 一起使用 "no-new-symbol": 2, // 允许指定模块加载时的进口 "no-restricted-imports": 0, // 禁止在构造函数中,在调用 super() 之前使用 this 或 super "no-this-before-super": 2, // 禁止不必要的计算性能键对象的文字 "no-useless-computed-key": 0, // 要求使用 let 或 const 而不是 var "no-var": 1, // 要求或禁止对象字面量中方法和属性使用简写语法 "object-shorthand": 0, // 要求使用箭头函数作为回调 "prefer-arrow-callback": 0, // 要求使用 const 声明那些声明后不再被修改的变量 "prefer-const": 0, // 要求在合适的地方使用 Reflect 方法 "prefer-reflect": 0, // 要求使用扩展运算符而非 .apply() "prefer-spread": 0, // 要求使用模板字面量而非字符串连接 "prefer-template": 0, // Suggest using the rest parameters instead of arguments "prefer-rest-params": 0, // 要求generator 函数内有 yield "require-yield": 2, // 要求或禁止模板字符串中的嵌入表达式周围空格的使用 "template-curly-spacing": 1, // 强制在 yield* 表达式中 * 周围使用空格 "yield-star-spacing": 2, // 要求或禁止使用拖尾逗号 "comma-dangle": 0, // 禁止在条件中使用常量表达式 "no-constant-condition": 0, // 强制一行的最大长度 "max-len": [ 0, 200, { ignoreUrls: true, }, ], // 禁止出现未使用过的变量 "no-unused-vars": [ 0, { vars: "all", // all 检测所有变量,包括全局环境中的变量。这是默认值。 args: "none", // none - 不检查参数。 }, ], // 去除插槽报错 "vue/no-deprecated-slot-attribute": "off", // 关掉命名规范 "vue/multi-word-component-names": "off", }, }; ``` ### 创建组件 在项目根目录下面创建`packages`用来存放组件,在`packages`下面创建每个组件的文件夹 组件目录下面创建`index.ts`、`src文件夹`,在`src`文件夹下面创建`index.vue` * `src`用来存放组件 * `index.vue`是组件内容 * `index.ts`用来导出组件 在`packages`下面创建`index.ts`用来导出全部组件或按需引入,创建`withInstall.ts`用来注册组件,创建`components.d.ts`支持`Volar` `withInstall.ts` ```ts import { App, Plugin } from 'vue' type SFCWithInstall<T> = T & Plugin export const withInstall = <T, E extends Record<string, any>>( main: T, extra?: E ) => { ;(main as SFCWithInstall<T>).install = (app: App) => { for (const comp of [main, ...Object.values(extra ?? {})]) { app.component(comp.name, comp) } } if (extra) { for (const [compName, comp] of Object.entries(extra)) { ;(main as Record<string, any>)[compName] = comp } } // 将 T 断言为具体的类型 T & plugin & Record<string, any> return main as SFCWithInstall<T> & E } ``` `index.ts` ```ts // 公共方法 /* import { debounce, throttle, formatNumber } from './utils' */ import type { Component, App } from "vue"; import Btn from "./button"; import labelInput from "./labelInput"; // 存储组件列表 const components: { [propName: string]: Component; } = { Btn, labelInput, }; // 插件声明:声明所有插件 // 插件注册:在 Vue 项目的入口文件中,通过 ( app.use(插件) ) 进行注册 const installComponents: any = (app: App) => { // components.forEach((comp: any) => { // app.component(comp.name as string, comp) // }) // app.use(ElementPlus, { // locale // 语言设置 // // size: Cookies.get('size') || 'medium' // 设置默认尺寸 // }) for (const key in components) { app.component(key, components[key]); } }; // vue插件 // - install:每个插件都有一个 install 方法 // - 参数:是通过 Vue.createApp() 创建的 app 实例 const install: any = (app: any, router?: any) => { // !router && installRouter(app); installComponents(app); }; // 按需引入 export { Btn, labelInput }; /** * @description 公共方法 */ /* export { throttle, debounce, formatNumber } */ export default { // 导出的对象必须具有 install,才能被 Vue.use() 方法安装 install, }; ``` 安装`npm i vite-plugin-dts -D`,作用是`为打包的库里加入声明文件(即生成:.d.ts文件)` 修改文件如下 `tsconfig.json` ```json { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "noImplicitAny": false, // 隐式具有“any”类型 "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "types": ["vite/client"], // 如果编译器无法根据变量的使用来判断类型时,将用 any 类型代替 // "suppressImplicitAnyIndexErrors": true, // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。 "allowSyntheticDefaultImports": true, "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], // 解析非相对模块名的基准目录 "baseUrl": "./", // 模块名到基于 baseUrl的路径映射的列表。 "paths": { "@": ["packages"], "@vue/shared": ["./node_modules/@vue/shared"], "@/*": ["packages/*"] }, "skipLibCheck": true }, "include": ["packages/**/*.ts", "packages/**/*.d.ts", "packages/**/*.tsx", "packages/**/*.vue"], "exclude": ["node_modules"], "references": [ { "path": "./tsconfig.node.json" } ] } ``` `tsconfig.node.json` ```json { "extends": "@tsconfig/node20/tsconfig.json", "include": [ "vite.config.*", "vitest.config.*", "cypress.config.*", "nightwatch.conf.*", "playwright.config.*" ], "compilerOptions": { "composite": true, "noEmit": true, "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "module": "ESNext", "moduleResolution": "Bundler", "types": ["node"] } } ``` `vite.config.ts` ```ts import { fileURLToPath, URL } from "node:url"; import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import vueJsx from "@vitejs/plugin-vue-jsx"; import dts from "vite-plugin-dts"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue(), dts(), vueJsx()], resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, build: { outDir: "lib", rollupOptions: { // 请确保外部化那些你的库中不需要的依赖 external: ["vue"], output: { // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 globals: { vue: "Vue", }, }, }, lib: { entry: "./packages/index.ts", name: "v3-elp-ui", }, }, }); ``` `package.json` ```json { "name": "v3-elp-ui", "version": "0.0.5", "type": "module", "private": false, "description": "描述", "author": "作者", "main": "lib/v3-elp-ui.umd.cjs", "module": "lib/v3-elp-ui.umd.cjs", "types": "lib/index.d.ts", "files": [ "package.json", "README.md", "lib" ], "scripts": { "dev": "vite", "lib": " vite build", "build": "run-p type-check \"build-only {@}\" --", "preview": "vite preview", "build-only": "vite build", "type-check": "vue-tsc --build --force", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", "format": "prettier --write src/" }, "dependencies": { "element-plus": "^2.7.5", "less": "^4.2.0", "vue": "^3.4.21" }, "devDependencies": { "@rushstack/eslint-patch": "^1.8.0", "@tsconfig/node20": "^20.1.4", "@types/node": "^20.12.5", "@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue-jsx": "^3.1.0", "@vue/eslint-config-prettier": "^9.0.0", "@vue/eslint-config-typescript": "^13.0.0", "@vue/tsconfig": "^0.5.1", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.23.0", "npm-run-all2": "^6.1.2", "prettier": "^3.2.5", "typescript": "~5.4.0", "vite": "^5.2.8", "vite-plugin-dts": "^3.9.1", "vue-tsc": "^2.0.11" } } ``` > 经过以上操作能够正常打包,命令`npm run lib`,在项目中验证正常,但是需要项目全局安装`element plus` > > 支持全量引入和按需引入 > > 需要再`main.ts`中引入`css`文件 > > `import 'v3-elp-ui/lib/style.css'` ### 组件设置name属性 在编写组件的时候需要将`name`单独添加到一个`script`中,使用不方便,安装`vite-plugin-vue-setup-extend`可以直接在`script`上添加`name` `npm i vite-plugin-vue-setup-extend -D` 在`vite.config.ts`中引入 ```ts import vueSetupExtend from 'vite-plugin-vue-setup-extend' // 设置neme属性 plugins: [vue(), dts(), vueJsx(), vueSetupExtend()], ``` ### 集成vitepress及完善其配置 > 参考资料: > > [https://blog.csdn.net/cwin8951/article/details/128903971](https://blog.csdn.net/cwin8951/article/details/128903971) > > [https://juejin.cn/post/7246638858912989241](https://juejin.cn/post/7246638858912989241) 1. 安装vitepress(也看用yarn、npm) ```bash pnpm add vitepress -D ``` 2. 在根目录创建文件夹`docs` 3. 创建文件夹及文件,结构如下 ```bash docs ├── .vitepress │ ├── config │ │ ├── global.ts │ │ └── plugins.ts │ ├── config.ts │ ├── theme │ │ ├── index.ts │ │ └── useComponents.js │ ├── utils │ │ └── highlight.ts │ └── vitepress │ ├── components │ │ └── vp-demo │ ├── index.ts │ └── style │ ├── code.css │ ├── css-vars.scss │ ├── index.scss │ ├── mixins.scss │ └── vars.scss ├── components │ ├── button │ │ └── base.md │ └── index.md ├── demos │ └── button │ └── index.vue ├── index.md └── public ├── css │ └── index.css ├── favicon.ico └── img └── vue.jpg ``` 4. 添加 scripts ```json "scripts": { "docs:dev": "vitepress dev docs", "docs:build": "vitepress build docs" }, ``` 5. 首页配置(即:docs/index.md文件)如下修改: ```md --- layout: home title: vue3 + element plus 组件库 # titleTemplate: 选项卡描述 editLink: true lastUpdated: true hero: name: v3-elp-ui text: vue3基础组件 tagline: Vue3 中基于Element-plus二次封装基础组件文档 image: src: /img/vue.jpg alt: v3-elp-ui actions: - theme: brand text: 安装指南 link: /components/ - theme: brand text: 组件预览 link: /components/button/base.md features: - icon: 🔨 title: 实际项目 details: 实际项目中碰到的疑点、难点,致力于更优的自我。。 - icon: 🧩 title: 基础组件 details: 基于Element-plus二次封装;使用组件 Demo 快速体验交互细节。。 - icon: ✈️ title: Vue驱动。 details: 享受 Vue3 + vite3 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。 --- <p style="display: flex; justify-content: center; align-items: center; margin-top: 10px;"> <a href="https://github.com/vuejs/vue" target="_blank"> <img src="https://img.shields.io/badge/vue-3.2.36-brightgreen.svg" alt="vue3"> </a> </p> ``` 6. 配置组件 在`demos`目录下创建组件文件夹`button`,里面在创建对应的`vue`文件 ```vue <template> <!-- 组件库中的包 --> <Btn /> </template> ``` 在`components`文件夹中创建组件说明文档文件夹`button`,里面在创建`base.md` ```md # 按钮组件 :::demo button/index ::: ``` 在`components`目录下创建`index.md` ```md # 安装&使用 ::: tip 提示 v3ElpUi 是基于 vue3 + Element-plus 二次封装的基础组件 ::: ## 安装 ```js npm install v3-elp-ui & yarn add v3-elp-ui -S ``` ## 使用 ```js // main.js import v3ElpUi from "v3-elp-ui"; Vue.use(v3ElpUi); ``` ## 说明 需要项目全局安装`elemen-plus` ``` 7. 接下来开始配置`vitepress`,主要设置`docs\.vitepress`目录下的文件,代码较多就不写了 ```bash .vitepress ├── config │ ├── global.ts # 设置文档库路径 │ └── plugins.ts # 用于扩展Markdown解析器markdown-it的功能,以便在Markdown文档中支持一种特殊的自定义容器(以demo标记),该容器可以用来展示代码示例及其描述。 ├── config.ts # vitepress配置文件 设置导航和侧边栏 ├── theme │ ├── index.ts # 安装注册组件 注册了element-plus he ziji de zuianku │ └── useComponents.js # 注册自定义组件 ├── utils │ └── highlight.ts # 实现代码高亮 └── vitepress ├── components │ └── vp-demo # 自定义组件 用来展示demo │ ├── index.vue │ ├── vp-example.vue # 注意 25行 的 demo表示组件demo文件夹 │ └── vp-source-code.vue ├── index.ts # 导出组件 └── style #代码样式 ├── code.css ├── css-vars.scss ├── index.scss ├── mixins.scss └── vars.scss ``` * `docs\.vitepress\config\plugins.ts` > 1. **导入依赖**: > > * 引入了Node.js的`path`和`fs`模块来处理文件路径和读取文件内容。 > * 引入了TypeScript类型忽略注释`@ts-ignore`来规避Markdown解析器和容器插件的类型检查问题,因为这些包可能缺少直接的TypeScript声明文件。 > * 导入了`markdown-it`库来解析Markdown文本,并且使用了`markdown-it-container`插件以支持自定义的容器块。 > * 从本地`highlight`函数和`docRoot`变量导入,用于代码高亮和获取文档根目录路径。 > 2. **定义类型**: > > * `ContainerOpts`接口定义了传递给`mdContainer`插件的选项结构,包括验证函数、渲染函数和可选的标记。 > 3. **创建Markdown解析实例**: > > * 创建了一个`MarkdownIt`的实例`localMd`,用于渲染描述文本。 > 4. **定义mdPlugin函数**: > > * 此函数接收一个`MarkdownIt`实例作为参数,用于扩展Markdown解析功能。 > * 使用`mdContainer`插件定义名为"demo"的容器,该容器包含两部分逻辑: > > * `validate`函数检查代码块是否以"demo"开头,并可选地捕获后续描述文本。 > * `render`函数定义了如何渲染这种特殊类型的代码块。它读取指定的Vue组件文件,对组件源码进行高亮处理,然后构造一个`<Demo>`标签来包裹这些信息,包括组件源代码、文件路径、未经处理的源码以及可选的描述。 > 5. **用途示例**: > > * 在Markdown文档中,用户可以通过以下方式插入组件示例: > > ``` > ::: demo 示例名称 > src/components/Button.vue > ::: > ``` > > * 解析器会将上述Markdown转换成HTML,其中包含一个`<Demo>`元素,属性包括组件的源代码(经过高亮处理)、原始文件路径、未编码的源代码以及描述(如果有的话)。 > > 此代码片段极大地增强了Markdown文档的交互性和开发者的文档编写体验,特别是在需要频繁展示和文档化代码组件的项目中。 > >> 注意`第34行`的`demos`代表组件`demo`文件夹 >> > * `docs\.vitepress\utils\highlight.ts` > 主要实现了代码高亮功能,使用了`prismjs`库来对特定语言的代码进行语法高亮处理。以下是代码的关键部分和功能解释: > > 1. **导入依赖**: > > * `chalk`:用于在控制台输出带有颜色的文本。 > * `escapeHtml`:用于转义HTML特殊字符,防止XSS攻击。 > * `prism`:代码高亮库,支持多种编程语言的语法高亮。 > * `consola`:一个美观的日志记录库,常用于Node.js应用中。 > * `loadLanguages`:动态加载`prismjs`的语言包,确保需要的语言支持已加载。 > 2. **加载语言包**: > > * 使用`loadLanguages(["markup", "css", "javascript"])`预先加载了一些常用的语言包,确保基本的代码高亮功能可用。 > 3. **`wrap`****函数**: > > * 接受一段代码和语言类型,如果语言类型是"text",则转义HTML特殊字符后包裹在`<pre><code>...</code></pre>`标签内返回。否则,直接返回原始代码包裹在相同的标签内。 > 4. **`highlight`****函数**: > > * 是主要的代码高亮处理函数,接受要高亮的字符串和语言类型作为参数。 > * 首先,如果没有指定语言类型,则默认按照纯文本处理。 > * 然后,根据语言类型调整为`prismjs`支持的标准语言标识符(如将`vue`调整为`markup`)。 > * 接着,尝试加载对应语言的高亮规则,如果规则不存在,则尝试动态加载,并在加载失败时通过[`consola.warn`]()输出警告信息。 > * 最后,如果成功加载了语言规则,使用[`prism.highlight`]()方法对代码进行高亮处理,并返回包裹好的HTML代码;否则,按纯文本处理返回。 > > 综上所述,这段代码提供了一个灵活且健壮的代码高亮工具,能够适应多种编程语言,并且在遇到不支持的语言时提供了友好的警告提示。 > 8. 最后安装依赖 ```bash # highlight.ts npm i chalk escape-html prismjs consola -D # plugins.ts npm i markdown-it markdown-it-container -D # demo文件 npm i @vueuse/core ``` ### 说明文档添加搜索 查看代码没有找到`4、7`参考链接的搜索设置 经过上网搜索发现VitePress支持使用浏览器内置索引进行模糊全文搜索,查看`4、7`参考链接的确具有相同的设置 在`.vitepress/config.ts`文件中将`themeConfig.search.provider`选项设置为`local`即可 ### 结束 最后就是对组件库进行打包上传并部署组件库文档了 > 仓库地址:[http://banmag.cn:6080/npmbag/v3-elp-ui-tem.git](http://banmag.cn:6080/npmbag/v3-elp-ui-tem.git)
admin
2024年7月2日 11:54
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码