乐趣区

关于前端:vue3typescript开发公共组件

记录一下 vue3+typescript 开发公共组件的注意事项

我的项目构造

|-- examples 搁置用于测试组件的代码
|   |-- App.vue
|   |-- main.ts
|-- packages 搁置组件的代码
|   |-- index.ts
|   |-- shims-vue.d.ts
|   |-- assets
|   |   |-- logo.png
|   |-- components
|       |-- helloWorld
|           |-- HelloWorld.tsx 组件的定义
|           |-- index.ts 组件裸露以及全局申明
|-- public
|   |-- favicon.ico
|   |-- index.html
|-- tests
|   |-- unit
|       |-- example.spec.ts
|-- .browserslistrc
|-- .eslintrc.js
|-- .gitignore
|-- babel.config.js
|-- jest.config.js
|-- package-lock.json
|-- package.json
|-- README.md
|-- tsconfig.json
|-- vue.config.js

组件编写

组件定义

// packages/components/helloWorld/HelloWorld.tsx
import {defineComponent, type ExtractPropTypes} from "vue";

const props = {
  /** 姓名 */
  name: String,
  /** 年龄 */
  age: Number,
};

// ExtractPropTypes:承受一个类型,返回 vue3 解决后的类型
export type HelloWorldProps = ExtractPropTypes<typeof props>;

export default defineComponent({
  name: "HelloWorld",
  props: props,
  emits: ["click"],
  setup(props, { emit}) {const onClick = (event: MouseEvent) => {emit("click", event);
    };

    return () => {
      return (
        <tag>
          <div onClick={onClick}>
            HelloWorld, {props.name}, {props.age}
          </div>
        </tag>
      );
    };
  },
});

组件申明,裸露

// packages/components/helloWorld/index.ts
import HelloWorld from "./HelloWorld";
export {type HelloWorldProps} from "./HelloWorld";
export default HelloWorld;

// 组件调用时,提供代码提醒
declare module "vue" {
  export interface GlobalComponents {HelloWorld: typeof HelloWorld;}
}

组件注册

// packages/index.ts
import type {App} from "vue";
import HelloWorld from "./components/helloWorld";

// 定义 install 办法,供内部调用
const install = (Vue: App) => {Vue.component("HelloWorld", HelloWorld);
};

export default {install};

编译插件

npm i -D vue-ts

配置文件

package.json

"scripts": {"lib": "vue-cli-service build --target lib --name xxx --dest lib packages/index.ts && vue-tsc --declaration --emitDeclarationOnly",}

tsconfig.json

{
  "compilerOptions": {
    "outDir": "lib/types", // 指定编译后的文件门路
    "target": "esnext",
    "module": "CommonJS",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env",
      "jest"
    ],
    "paths": {
      "@/*": ["packages/*"]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "packages/**/*.ts",
    "packages/**/*.tsx"
  ],
  "exclude": ["node_modules"]
}
退出移动版