• 第二章 开发一个Vue组件


    第二章 开发一个Vue组件

    1、基础组件

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

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

    import { defineComponent, h } from "vue";
    
    export default defineComponent({
    
      name: "SButton",
    
      // template:''
    
      render() {
    
        return h("button", null, "MyButton");
    
      },
    
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

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

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

    • src/index.ts 中启动 Vue 实例
    import { createApp } from "vue";
    
    import SButton from "./button";
    
    createApp(SButton).mount("#app");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 启动项目
    pnpm dev
    
    • 1
    • 浏览器访问项目地址
      VITE v3.0.7  ready in 165 ms
    
      ➜  Local:   http://localhost:5173/
      ➜  Network: use --host to expose
    
    • 1
    • 2
    • 3
    • 4
    • 页面并没有显示button组件,且控制台报错
    Uncaught SyntaxError: Cannot use import statement outside a module (at index.ts:1:1)
    
    • 1

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

    • 修改index.html文件,再次查看
    <script src="./src/index.ts" type="module">script>
    
    • 1
    • 再次查看浏览器,可以看见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.
    
    • 1
    • 2
    • 3

    查阅资料——解决方案

    • 安装插件@vitejs/plugin-vue
    pnpm i @vitejs/plugin-vue -D
    
    • 1
    • 创建vite.config.ts 配置插件
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    export default defineConfig({
    plugins: [
      vue(), // VUE插件
    ],
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 再次启动项目
    pnpm dev
    
    • 1
    • 再次查看浏览器控制台

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


    2、单文件组件

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

    Vite默认只能支持TS代码,而Vue的模板需要在编译阶段转换为TypeScript代码(渲染函数)才可以运行。Vue 插件不但提供了模板的编译,同时还支持 Vue 单文件 (SFC) 组件的编译。

    • 安装插件
    pnpm i @vitejs/plugin-vue -D
    
    • 1
    • 创建vite.config.ts 配置插件
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    export default defineConfig({
      plugins: [
        vue(), // VUE插件
      ],
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 引入到index.ts中测试
    import { createApp } from "vue";
    import SFCButton from "./SFCButton.vue";
    
    createApp(SFCButton)
    .mount("#app");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时报错

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

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

    • 创建src/shims-vue.d.ts类型声明文件
    declare module "*.vue" {
      import { DefineComponent } from "vue";
      const component: DefineComponent<{}, {}, any>;
      export default component;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 运行项目
    pnpm dev
    
    • 1
    • 浏览器访问地址
      VITE v3.0.7  ready in 297 ms
    
      ➜  Local:   http://localhost:5173/
      ➜  Network: use --host to expose
    
    • 1
    • 2
    • 3
    • 4

    此时可以看到按钮组件。


    3、JSX 组件

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

    • 在这里我们通过插件实现扩展
    pnpm i @vitejs/plugin-vue-jsx@"2.0.0" -D
    
    • 1
    • 修改 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 插件
      ],
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 创建src/JSXButton.tsx 文件
    import { defineComponent, h } from "vue";
    
    export default defineComponent({
    
      name: "JSXButton",
      render() {
        return <button>JSX Button</button>;
      },
    
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这个时候TS会报错

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

    这个提示的意思是不支持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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 将组件引入index.ts中测试
    import { createApp } from "vue";
    import JSXButton from "./JSXButton";
    
    createApp(JSXButton)
    .mount("#app");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 运行项目
    pnpm dev
    
    • 1
    • 浏览器查看地址
     VITE v3.0.7  ready in 466 ms
    
      ➜  Local:   http://localhost:5173/
      ➜  Network: use --host to expose
    
    • 1
    • 2
    • 3
    • 4

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


    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    可以满足以下的要求:

    • 默认导出为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);
      },
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    默认 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"],
        },
      },
    });
    
    • 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

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

     "scripts": {
        "build": "vite build"
      },
    
    • 1
    • 2
    • 3

    执行命令

    pnpm build
    
    • 1

    控制台打印

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    生成新的文件目录

    dist
    |----smart-ui.iife.js
    |----smart-ui.mjs
    |----smart-ui.umd.js
    
    • 1
    • 2
    • 3
    • 4

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

    验证的过程还是基于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: `
          
          
          
        `}).use(SmartyUI).mount('#app')
    
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    创建目录文件: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: `
    
    
    
    `,
      })
        .component(SFCButton.name, SFCButton)
        .component(JSXButton.name, JSXButton)
        .component(MyButton.name, MyButton)
        .mount("#app");
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    执行命令启动项目

    pnpm dev
    
    • 1

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

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

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

  • 相关阅读:
    『抽丝剥茧』手把手快速上带你开启文心大模型的奇妙冒险
    驱动 点灯
    如何写公众号推文?公众号文章写作步骤分享
    【C++学习笔记】1.2 C++输入与输出
    笔记本上使用usb蓝牙适配器
    XenServer 存储、vApp、高可用
    Objective-C依然占C位,Swift和SwiftUI在iOS 15中的使用情况
    mapstruct实现各个实体间的类型转换(DTO转BO、BO转Entity)的实践
    宠物疾病 与 光线疗法
    器学习算法(六)基于天气数据集的XGBoost分类预测
  • 原文地址:https://blog.csdn.net/qq_36362721/article/details/127827700