# VueClassApiTsx **Repository Path**: bmycode/vue-class-api-tsx ## Basic Information - **Project Name**: VueClassApiTsx - **Description**: 基于Vue Class Api 语法 和 TSX 开发的一套项目脚手架,同时使用babel AST语法树提取代码实现自动路由配置生成等 - **Primary Language**: TypeScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 6 - **Forks**: 0 - **Created**: 2020-08-30 - **Last Updated**: 2023-12-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 前言: 前端发展真的是一个轮回,越发展越偏向**原生**,`Vue3`开发阶段就参与并使用了,但是`Vue3`真的垃圾,十分的不喜欢这种垃圾的语法,钟爱`class`和`ts装饰器`,所以有了本项目!! 本项目作为`Vue`脚手架而存在,已在很多公司项目中落地并经过不断打磨,同时为了更优雅的代码开发,本人写了很多周边的辅助插件,装饰器,shell,为你提供类似`java`开发中`SpringBoot`那般优雅的爽快感! **围绕项目开发的插件有:** 1: [vue-cli-plugin-tsx-autorouter](https://www.npmjs.com/package/vue-cli-plugin-tsx-autorouter) tsx自动路由插件 受`Nuxt.js`的思想启发,针对本项目`tsx`开发,根据页面结构自动生成路由配置文件,借助`babel`的`ast`实现提取`tsx`中类的属性进而实现路由`meta`。 2:./bin/tinit 封装shell命令行工具,实现通过命令行直接创建众多代码文件 3:解耦前端 页面 & JSON数据,实现JSON映射存储到类属性: - 1: [json-mapper-class](https://www.npmjs.com/package/json-mapper-class) 核心插件 - 2: [json-class-interface](https://www.npmjs.com/package/json-class-interface) `TypeScript`项目中通用的JSON数据自动生成类型工具,支持生成 [json-mapper-class](https://www.npmjs.com/package/json-mapper-class) 标准代码。 - 3: [json-class-desktop](https://gitee.com/bmycode/json-class-desktop) 基于`tauri` `Svelte`写的[json-class-interface](https://www.npmjs.com/package/json-class-interface) 桌面端工具,支持`Mac`,`linux`,`windows`。 4:装饰器(将封装成通用TS项目插件): - 1: 让代码更加优雅简洁高效的请求中间层装饰器 @GET,@POST,@DELETE,@PUT ```typescript @GET() @Mapper(ResponseType) public async IndexTest (params: object): Promise { // 留空,不要写请求代码 即可发送请求,除非 useHandle: true,这时 方法入参 params 为 ajax 接口数据,直接处理 params // 即可,同时也不需要写请求代码!! } ``` - 2: 依赖注入装饰器:@Autowired - 3: 其他装饰器:@GlobalMethod,@Mapper,@RegVuePlugs,@RegServiceAndMethods,@Start 等等.. 5:AutoServiceCodeGeneration:实时监听`configure.config.ts`配置文件,然后根据`ApiList`中的对象`key`名称自动生成请求中间层的代码,降低手动复制的低效率! 介绍: 1: 文件监听:已通过Nodejs流操作实现文件监听,读取,提取,核心代码,并实现同一文件中不同编辑下的新旧数据`Diff`。 2:请求中间层代码自动生成:**思路已有,挑战性不足,所以还未进行代码实现** ## TsxVueClassApi 基于`Vue Class Api`,`TypeScript`,`JSX`,搭建的一套项目脚手架,实现了很多常用的注解,同时基于`babel`插件通过`Ast`语法树进行路由配置文件的自动生成等。 如果你喜欢`JSX`,那么这套脚手架你应该会十分喜欢,代码语法如下: ```tsx import "@pageLess/Home.less"; import { Component } from 'vue-property-decorator'; import HelloWorld from '@components/HelloWorld'; import { HomeLogic } from "@logic/page/Home.logic"; import { Getter } from "vuex-class"; import { IndexUtils } from "@utils/index.utils"; import { Autowired } from "@ann/Ioc.annotation"; import { VueCustomize, RouterMeta } from "@logic/Base.type"; @Component export default class Home extends VueCustomize { // RouterMeta 是 vue-router 路由meta配置信息,会被 我们的插件 // vue-cli-plugin-tsx-autorouter 进行 ast 提取注入到 自动生成的 路由配置文件中 public RouterMeta: RouterMeta = { title: '首页', showNav: true, isLogin: true } // 抽离组件所有逻辑到独立类,解耦 页面层 和 逻辑层 // 通过 Autowired 依赖注入装饰器 实现 注入 逻辑 -> 页面 // 同时 传入 vue 的 this,实现逻辑层可以调用vue方法 @Autowired(Home) private logic!: HomeLogic @Autowired() public readonly Utils!: IndexUtils; @Getter('GettersTabsContentArr') public readonly getterFoo!: Array; public async created() { await this.logic.StartUp(); } public ClickButton(): JSX.Element { return ( { console.log("按钮被点击22222"); }}> Primary ) } public back() { console.log("qqqq"); } protected render() { return (

111

{this.logic.title}

{this.ClickButton()}
    { this.logic.List.map(v => { return
  • {v.user_id} {v.user_name}
  • }) }
) } } ``` **这个脚手架我们正在项目中使用,同时也在不断的开发和完善!!!!** ## 1:安装 需要额外全局安装的插件有: ```bash npm i -g concurrently cross-env gulp ``` 然后下载项目,初始化并启动: ```bash git clone https://gitee.com/bmycode/vue-class-api-tsx.git npm i npm run start # 注意!!!:网站运行后使用电脑本机的局域网ip地址来访问,例如:http://192.168.1.101:8080/#/Home ``` **注意** `Vue`官方原生底层就支持`JSX`语法,但是官方没有关于`Vue`中使用`JSX`的文档,而且很多`Vue`ui框架和第三方插件都没有相关语法,但是这不影响我们在`Vue`中正常使用`JSX`。很多语法需要特殊注意和改造一下!! ## 2:使用 下面说下这个脚手架的使用和注意事项。 ### 2.1:项目结构 请仔细看文件后面的中文说明!!! ```txt ├── README.md ├── babel.config.js babel配置文件 ├── bin 终端NewFile工具 │   ├── config │   │   └── index.js │   └── tinit ├── dist 打包后的文件夹 ├── gulpfile.js gulp配置文件,实现监听page自动生成路由文件 ├── package.json 核心依赖配置文件 ├── public 公共的资源文件 ├── src 存放核心源码 │   ├── application 页面相关 │   │   ├── app.tsx 最外层顶级父组件 │   │   ├── assets 静态资源回合webpack打包进源码 │   │   ├── components 公共组件 │   │   ├── logic 【重要】TSX组件中的js逻辑抽象层 │   │   │   ├── base.logic.ts 【重要】所有TSX组件的js逻辑父类 │   │   │   ├── base.type.ts 组件中 通用类型的编写 │   │   │   └── page 【重要】对应页面的TSX组件逻辑抽象 │   │   └── page 【重要】存放TSX页面组件 │   └── core 核心JS层 │   ├── annotation 存放自己开发的装饰器    │   ├── JsonToClass json-mapper-class 的源代码 │   │   ├── http.annotation.ts 请求装饰器 │   │   ├── ioc.annotation.ts IOC依赖装饰器 │   │   └── register.annotation.ts 启动装饰器 │   ├── config 站点配置文件 │   │   ├── configure.config.ts 核心配置文件 │   │   └── route.config.ts 自动生成的路由配置文件 │   ├── dao axios的封装 │   ├── model TS存取器 │   ├── run 项目的启动类 │   │   ├── init.run.ts 初始化Vue各种配置 │   ├── service 请求的service层封装 │   │   └── impl 请求service的具体类 │   ├── store Vuex的配置 │   ├── types 自定义的声明文件 │   └── utils 工具函数 ├── tsconfig.json TS的配置文件 └── vue.config.js Vue-cli3 的配合文件 ``` ### 2.2:编码注意事项和规范,严格遵守!!! 1:`page/`文件夹中的所有`tsx`组件必须继承自`VueCustomize`,`VueCustomize`是所有页面的父类,可以在这里定义一些公共的类型! 2:`logic/`文件夹中的所有`logic.ts`必须继承`BaseLogic`并实现接口`Methods`,`BaseLogic`是所有页面逻辑层的公共封装,可以把使用率高的接口或者变量放在`BaseLogic` 中去定义和实现,这样页面的逻辑层子类可以实现直接使用! 3:`logic/`中页面的逻辑层可以使用装饰器`@Autowired()`去注入多个`service`的依赖,实现对`ajax`中间层方法的调用,以发送`ajax`请求!具体的看下面代码 ```typescript import { Autowired } from "@/core/annotation/Ioc.annotation"; import { UserServiceImpl, ResponseType} from "@/core/service/impl/User.service.impl"; import { BaseLogic } from "@logic/Base.logic"; import { Methods, VueCustomize } from "@logic/Base.type"; export class HomeLogic extends BaseLogic implements Methods { @Autowired() public readonly UserServiceImpl!: UserServiceImpl; public title: string = "12222"; public List: ResponseType[] = []; constructor(_: T) { super(); this._ = _ } /** * 在这里面调用需要打开页面就执行的ajax请求 * @constructor */ public async StartUp (): Promise { await this.getData(); } /** * 请求首页数据 */ public async getData (): Promise { this.List = await this.UserServiceImpl.IndexTest({ type: 1, page: 1 }); console.log("this.List: ", this.List); // let res = await this.UserServiceImpl.login({ type: 2, page: 2 }); // console.log("this.res: ", res); // this._.$setToken("") // await this._.$router.push('/About') } } ``` 4:`logic/`中必须实现构造函数`constructor`,在构造函数中保存`tsx`页面传入指向`vue`实例的`this`,这样才能在`logic`中正确使用`vue`的一些方法,具体看代码: ```typescript constructor(_: T) { super(); this._ = _ } /** * 请求首页数据 */ public async getData (): Promise { this.List = await this.UserServiceImpl.IndexTest({ type: 1, page: 1 }); console.log("this.List: ", this.List); } ``` 5:如何将自定义的方法通过 `Vue.prototype.xxx` 挂载到`Vue`上以方便全局使用? 答:在`utils/index.utils.ts`中定义方法的时候请使用装饰器`@GlobalMethod()`装饰方法,然后如果你在`tsx`页面组件中需要使用此方法,那么请在`base.type.ts`中定义变量并编写变量类型! 同时如果你需要在`logic`逻辑层使用此方法,那么需要在`base.logic.ts`的`VueType`接口中编写类型。具体请看代码: ```typescript // src/core/utils/index.utils.ts import { ConfigureConfig } from "@config/configure.config"; import { GlobalMethod } from "@ann/Register.annotation"; export class IndexUtils { /** * 方法上打上 @GlobalMethod() 注解,这个方法会自动成为vue的全局方法 * 组件中直接:this.$setToken() 即可 */ @GlobalMethod() public setToken (args: string): void { localStorage.setItem("token", args) } } // src/application/logic/base.logic.ts // 定义 $setToken 方法和入参类型,返回值等! export class VueCustomize extends Vue { $setToken!: (token: string) => void } ``` 如果你觉得上面方式使用全局方法太过于麻烦,那么你可以在你需要使用的`logic`类或`tsx`组件中使用装饰器`@Autowired()`来注入`index.utils.ts`到类属性中,代码示例: ```typescript import "@pageLess/Home.less"; import { Component } from 'vue-property-decorator'; import HelloWorld from '@components/HelloWorld'; import { HomeLogic } from "@logic/page/Home.logic"; import { Getter } from "vuex-class"; // 1:导入需要被注入的类 import { IndexUtils } from "@utils/index.utils"; // 2:导入装饰器 import { Autowired } from "@ann/Ioc.annotation"; import { VueCustomize, RouterMeta } from "@logic/Base.type"; import { toClass, toInterface, configFilePath } from "json-class-interface"; @Component export default class Home extends VueCustomize { // 抽离组件所有逻辑到独立类,解耦页面和数据 @Autowired(Home) private logic!: HomeLogic // RouterMeta 是 vue-router 路由meta配置信息,会被ast提取注入到自动生成的路由配置文件中 public RouterMeta: RouterMeta = { title: '首页', showNav: true, isLogin: true } // 3:将 IndexUtils 注入到属性 Utils 中 @Autowired() public readonly Utils!: IndexUtils; @Getter('GettersTabsContentArr') public readonly getterFoo!: Array; public async created () { // 4:使用 setToken 方法 this.Utils.setToken("1111") } public ClickButton(): JSX.Element { return ( { console.log("按钮被点击22222"); }}> Primary ) } public back() { console.log("qqqq"); } protected render() { return (

111

{this.logic.title}

{this.ClickButton()}
    { this.logic.List.map(v => { return
  • {v.user_id} {v.user_name}
  • }) }
) } } ``` ### 2.3:使用注意事项 **1:** 项目中的路由使用的是`vue-router`,同时我借鉴了`Nuxt.js`的思想,自己开发了路由配置文件自动生成的插件,这个插件是`Vue-cli 3`的插件,所以不能在`Vue cli 2`的项目中使用!! 插件源码已经提交`npm`包市场!请完整阅读下面的插件文档,路由的配置文件让插件帮我们自动生成就好了!!! [vue-cli-plugin-tsx-autorouter](https://www.npmjs.com/package/vue-cli-plugin-tsx-autorouter) **2:** 同时借鉴`PHP`开发框架`Laravel`开发终端命令行工具,通过命令帮我们创建带有模板代码能直接运行的文件!代码放在 `bin/` 文件夹中! 使用手册: ```bash ╭─bmy@MacBook-Pro /Applications/Source/TsxVueClassApi ‹master*› ╰─$ ./bin/tinit -h Usage: tinit [options] Options: -t, --file-type 文件类型: [page,logic,service,impl,less] -n, --file-name 被创建的文件名称 -i, --is-create 是否为 -t 参数自动创建相关文件类型 (default: false) -v, --version 显示当前的版本 -h, --help display help for command ``` 参数说明: - -t:需要被创建的文件类型,取值 page(TSX页面),logic(TSX页面的js抽象层),service(请求中间层的接口),impl(实现接口的类),less(css样式文件)。可以多传! - -n:需要被创建的文件名 - -i:如果数值为true,那么会自动创建 -t 参数所有的文件类型 使用案例: ```bash ╭─bmy@MacBook-Pro /Applications/Source/TsxVueClassApi ‹master*› ╰─$ ./bin/tinit -t page logic -n Test 成功创建文件... ``` 上面命令执行后会分别在`src/application/page`中创建创建文件`Text.tsx`页面组件,同时在`src/application/logic/page`中创建`Test.logic.ts`的逻辑层文件。 多试几次,请自行熟练掌握!! ## 3:开发中功能 - [x] 【重要】1:实现`ajax`请求到的数据和`model`层的映射绑定,这种数据绑定关系,可以完全解决后端改接口字段从而导致前端代码也需要同步大量修改的问题!! - 插件文档:[https://gitee.com/bmycode/json-to-class-or-interface](https://gitee.com/bmycode/json-to-class-or-interface) - [x] 【不太重要】1:实时监听`configure.config.ts`配置文件,然后根据`ApiList`中的对象`key`名称自动在`service`层的类中生成对应的方法,降低手动复制的低效率! - 已实现功能,但未整合进项目!