搭建Vue3组件库:第二章 开发一个Vue组件

简介: 使用Vite+Vue开 发一个简单的组件:基础组件===>单文件组件===>JSX组件

1、基础组件

  • 首先安装 Vue3.0 包依赖。
pnpm i vue@"3.2.37"
  • 接着尝试编写一个简单的 Button 组件

创建src/button/index.ts目录文件

import { defineComponent, h } from "vue";

export default defineComponent({

  name: "SButton",

  // template:'<button>MyButton</button>'

  render() {

    return h("button", null, "MyButton");

  },

});
写到这里大家可能有点疑问: 为什么是使用 render 函数,而不是熟悉的 template 语法编写呢?

这是因为 Vue3.0 默认的包是不支持模板编译功能的。也就是说, template 语法现在还不能用。在 Vue3.0 中编译功能推荐在构建阶段完成,而不是放到浏览器中运行。如果希望在浏览器中的话,可以选择 ./node_modules/vue/dist/vue.global.js 这个包。

  • index.html 中添加一个容器 , 用来展示组件
<div id="app"></div>

给容器添加id属性,用于后面Vue实例挂载。

  • src/index.ts 中启动 Vue 实例
import { createApp } from "vue";

import SButton from "./button";

createApp(SButton).mount("#app");
  • 启动项目
pnpm dev
  • 浏览器访问项目地址
  VITE v3.0.7  ready in 165 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  • 页面并没有显示button组件,且控制台报错
Uncaught SyntaxError: Cannot use import statement outside a module (at index.ts:1:1)

这里报错的原因是用了es6的语法, 浏览器默认将它作为js解析会出现问题,需要将它作为模块导入,script标签默认type="text/javascript",需要改为type="module",更改后的index.html

  • 修改index.html文件,再次查看
<script src="./src/index.ts" type="module"></script>
  • 再次查看浏览器,可以看见button组件,但是控制台有以下警告
runtime-core.esm-bundler.js:4952 Feature flags __VUE_OPTIONS_API__, __VUE_PROD_DEVTOOLS__ are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.

For more details, see https://link.vuejs.org/feature-flags.

查阅资料——解决方案

  • 安装插件@vitejs/plugin-vue
pnpm i @vitejs/plugin-vue -D
  • 创建vite.config.ts 配置插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [
  vue(), // VUE插件
],
})
  • 再次启动项目
pnpm dev
  • 再次查看浏览器控制台

组件正常显示,且控制台此时无警告报错。


2、单文件组件

由于Vue3.0 默认的包是不支持模板编译功能, 这里需要安装viteVue插件,也就是上面的解决方案步骤。

Vite默认只能支持TS代码,而 Vue的模板需要在编译阶段转换为 TypeScript代码(渲染函数)才可以运行。 Vue 插件不但提供了模板的编译,同时还支持 Vue 单文件 ( SFC) 组件的编译。
  • 安装插件
pnpm i @vitejs/plugin-vue -D
  • 创建vite.config.ts 配置插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue(), // VUE插件
  ],
})
  • 引入到index.ts中测试
import { createApp } from "vue";
import SFCButton from "./SFCButton.vue";

createApp(SFCButton)
.mount("#app");

此时报错

找不到模块“./SFCButton.vue”或其相应的类型声明。ts(2307)

这是因为Typescript 默认是不支持 .vue 类型的模块的。可以通过添加一个模块的类型定义来解决这个问题。

  • 创建src/shims-vue.d.ts类型声明文件
declare module "*.vue" {
  import { DefineComponent } from "vue";
  const component: DefineComponent<{}, {}, any>;
  export default component;
}
  • 运行项目
pnpm dev
  • 浏览器访问地址
  VITE v3.0.7  ready in 297 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

此时可以看到按钮组件。


3、JSX 组件

JSX 是一种 Javascript 的语法扩展,最早运用于 React 架构中。JSX 也可以当作一种模板语言使用。虽然有人会质疑利用JSX语法编写 Vue3 代码是否合理, 比如怀疑 JSX 语法是否兼容 Vue3 的静态提升特性。但是现在很多基于 Vue 的组件库都大量使用 JSX 语法,对于工程化搭建,还是以开发者的使用习惯优先,我们支持了再说。

  • 在这里我们通过插件实现扩展
pnpm i @vitejs/plugin-vue-jsx@"2.0.0" -D
  • 修改 vite.config.ts 文件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [
    vue(), // VUE插件
    vueJsx({}), // JSX 插件
  ],
})
  • 创建src/JSXButton.tsx 文件
import { defineComponent, h } from "vue";

export default defineComponent({

  name: "JSXButton",
  render() {
    return <button>JSX Button</button>;
  },

});

这个时候TS会报错

(property) button: ElementAttrs<ButtonHTMLAttributes>
找不到名称“React”。ts(2304)

这个提示的意思是不支持 JSX 语法造成的。而不是需要安装 React。只需要在 tsconfig 中配置一下 jsx 语法支持就行了。

  • 在根目录下创建tsconfig.json文件
{
  "compilerOptions": {
      "declaration": true, /* 生成相关的 '.d.ts' 文件。 */
      "declarationDir": "./dist/types", /* '.d.ts' 文件输出目录 */
      "jsx": "preserve",
  },
  "include": [
      "./**/*.*",
      "./src/shims-vue.d.ts"
  ],
  "exclude": [
      "node_modules"
  ],
  "esModuleInterop": true,
  "allowSyntheticDefaultImports": "true"
}
  • 将组件引入index.ts中测试
import { createApp } from "vue";
import JSXButton from "./JSXButton";

createApp(JSXButton)
.mount("#app");
  • 运行项目
pnpm dev
  • 浏览器查看地址
 VITE v3.0.7  ready in 466 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

查看浏览器显示的按钮组件是否正常。


4、库文件封装

参考一下 Element 的使用指南。可以看到组件库有两种引入形态:

  • 完整引入 :一次性引入全部组件,使用 Vue.use Vue 插件的形式引入
  • 按需引入 :按需引入,导出单个组件,使用 Vue.component 注册
import Vue from 'vue'
import Element from 'element-ui'

// 完整引入
Vue.use(Element)

// or
import {
  Select,
  Button
  // ...

} from 'element-ui'

// 按需引入
Vue.component(Select.name, Select)
Vue.component(Button.name, Button)

综上所述,组件库的形态应该是这样的结构:

可以满足以下的要求:

  • 默认导出为Vue插件
  • 每个组件可以单独导出

首先设计一个入口,包含两个功能:

  • 导出全部组件
  • 实现一个 Vue 插件,插件中编写 install 方法,将所有组件安装到 vue 实例中.

新建目录文件:src/entry.ts

import { App } from "vue";
import MyButton from "./button";
import SFCButton from "./SFCButton.vue";
import JSXButton from "./JSXButton";

// 导出单独组件
export { MyButton, SFCButton, JSXButton };

// 编写一个插件,实现一个install方法

export default {
  install(app: App): void {
    app.component(MyButton.name, MyButton);
    app.component(SFCButton.name, SFCButton);
    app.component(JSXButton.name, JSXButton);
  },

};

默认 Vite 就是可以支持构建,使用 Vite 的 build 命令就可以打包输出。如果导出的是一个库文件的话,还需要配置【导出模块类型】并确定导出的文件名。配置如下:

修改文件 vite.config.ts

const rollupOptions = {

  external: ["vue", "vue-router"],
  output: {
    globals: {
      vue: "Vue",
    },
  },
};

export default defineConfig({

  .....  

  // 添加库模式配置

  build: {
    rollupOptions,
    minify:false,
    lib: {
      entry: "./src/entry.ts",
      name: "SmartyUI",
      fileName: "smarty-ui",
      // 导出模块格式
      formats: ["es", "umd","iife"],
    },
  },
});

修改包配置(package.json)添加打包命令

 "scripts": {
    "build": "vite build"
  },

执行命令

pnpm build

控制台打印

vite v3.0.7 building for production...
✓ 6 modules transformed.
dist/smarty-ui.mjs   1.02 KiB / gzip: 0.45 KiB
Entry module "src/entry.ts" is using named and default exports together. Consumers of your bundle will have to use `SmartyUI["default"]` to access the default export, which may not be what you want. Use `output.exports: "named"` to disable this warning
dist/smarty-ui.umd.js   1.56 KiB / gzip: 0.67 KiB
Entry module "src/entry.ts" is using named and default exports together. Consumers of your bundle will have to use `SmartyUI["default"]` to access the default export, which may not be what you want. Use `output.exports: "named"` to disable this warning
dist/smarty-ui.iife.js   1.26 KiB / gzip: 0.54 KiB

生成新的文件目录

dist
|----smart-ui.iife.js
|----smart-ui.mjs
|----smart-ui.umd.js

看到提示说明正常导出了。最后编写一个验证页面,测试一下打包结果是否正确。

验证的过程还是基于Vite。首先测试加载全部组件,引用构建完的 smarty-ui.mjs 文件。

创建目录文件:demo/esm/index.html 测试全量导入

<h1>全量加载组件</h1>
<div id="app"></div>
<script type="module">
  import { createApp } from "vue/dist/vue.esm-bundler.js";
  import SmartyUI from "../../dist/smarty-ui.mjs";

  createApp({
    template: `
      <SButton/>
      <JSXButton/>
      <SFCButton/>
    `}).use(SmartyUI).mount('#app')

</script>

创建目录文件:demo/esm/button.html 测试按需导入

<h1>按需加载组件</h1>
<div id="app"></div>
<script type="module">
  import { createApp } from "vue/dist/vue.esm-bundler.js";
  import {
    SFCButton,
    JSXButton,
    MyButton,
  } from "../../dist/smarty-ui.mjs";

  createApp({
    template: `
<SButton/>
<JSXButton/>
<SFCButton/>
`,
  })
    .component(SFCButton.name, SFCButton)
    .component(JSXButton.name, JSXButton)
    .component(MyButton.name, MyButton)
    .mount("#app");
</script>

执行命令启动项目

pnpm dev

访问全量加载URL: http://localhost:5173/demo/esm/index.html

访问按需加载URL: http://localhost:5173/demo/esm/button.html

查看3种按钮组件是否都加载出来了,最后验证结果。

相关文章
|
30天前
|
存储 设计模式 JavaScript
Vue 组件化开发:构建高质量应用的核心
本文深入探讨了 Vue.js 组件化开发的核心概念与最佳实践。
77 1
|
3月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
74 8
|
3月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
181 64
|
3月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
存储 前端开发 JavaScript
为什么我不再用Vue,改用React?
当我走进现代前端开发行业的时候,我做了一个每位开发人员都要做的决策:选择一个合适的框架。当时正逢 jQuery 被淘汰,前端开发者们不再用它编写难看的、非结构化的老式 JavaScript 程序了。
|
8天前
|
JavaScript 前端开发 开发者
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
|
8天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
8天前
|
JavaScript 前端开发 数据安全/隐私保护
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
|
12天前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
66 12
|
29天前
|
JavaScript 安全 API
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
61 8

热门文章

最新文章