Files
2024-09-27 01:28:38 +08:00

346 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## TsxVueClassApi
基于`Vue Class Api``TypeScript``JSX`,搭建的一套项目脚手架,实现了很多常用的注解,同时基于`babel`插件通过`Ast`语法树进行路由配置文件的自动生成等。
如果你喜欢`JSX`,那么这套脚手架你应该会十分喜欢,代码语法如下:
```tsx
import "@pageLess/Home.less";
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@components/HelloWorld';
import { HomeLogic } from "@logic/page/Home.logic";
import { Route, RawLocation } from 'vue-router';
import { Getter } from "vuex-class";
import { BaseLayout, RouterMeta } from "@layout/base.layout";
import { IndexUtils } from "@utils/index.utils";
import {Inject} from "@ann/Ioc.annotation";
@Component
export default class Home extends BaseLayout {
private logic: HomeLogic = new HomeLogic(this);
public RouterMeta: RouterMeta = {
title: '首页',
showNav: true,
isLogin: true
}
@Inject()
public readonly Utils!: IndexUtils;
@Getter('GettersTabsContentArr') public readonly getterFoo!: Array<any>;
public async created() {
// 使用 依赖注入 调用utils工具方法
// this.Utils.setToken("1111")
// 使用 装饰器@GlobalMethod() 调用utils工具方法
// this.$setToken("111")
await this.logic.StartUp();
}
beforeRouteEnter(to: Route, from: Route, next: (to?: RawLocation | false | ((vm: Vue) => void)) => void) {
next()
}
public ClickButton(): JSX.Element {
return (
<a-button type="primary" onClick={async ()=>{
await this.logic.getData()
}}>
Primary
</a-button>
)
}
protected render() {
return (
<div class="home">
<HelloWorld msg="向HelloWorld props传参"/>
<input type="text" v-model={this.logic.title}/>
<h2>{this.logic.title}</h2>
{this.ClickButton()}
<ul>
{
this.logic.List.map((v:any)=>{
return <li>{v.name}</li>
})
}
</ul>
</div>
)
}
}
```
**这个脚手架我们正在项目中使用,同时也在不断的开发和完善!!!!**
## 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
```
**注意**
`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 公共组件
│   │   ├── layout 【重要】TSX组件的父类
│   │   ├── logic 【重要】TSX组件中的js逻辑抽象层
│   │   │   ├── Base.logic.ts 【重要】所有TSX组件的js逻辑父类
│   │   │   └── page 【重要】对应页面的TSX组件逻辑抽象
│   │   └── page 【重要】存放TSX页面组件
│   └── core 核心JS层
│   ├── annotation 存放自己开发的装饰器
│   │   ├── 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各种配置
│   │   └── start.run.ts 初始化Vue
│   ├── service 请求的service层封装
│   │   └── impl 请求service的具体类
│   ├── store Vuex的配置
│   ├── types 自定义的声明文件
│   └── utils 工具函数
├── tsconfig.json TS的配置文件
└── vue.config.js Vue-cli3 的配合文件
```
### 2.2:编码注意事项和规范,严格遵守!!!
1`page/`文件夹中的所有`tsx`组件必须继承自`BaseLayout``BaseLayout`是所有页面的父类,可以在这里定义一些公共的声明文件!
2`logic/`文件夹中的所有`logic.ts`必须继承自`BaseLogic`并实现接口`Methods``BaseLogic`是所有页面逻辑层的公共封装,可以把使用率高的接口或者变量放在`BaseLogic`中去定义和实现,这样页面的逻辑层子类可以实现直接使用!
3`logic/`中页面的逻辑层可以使用装饰器`@Inject()`去注入多个`service`的依赖,实现对`ajax`中间层方法的调用,以发送`ajax`请求!具体的看下面代码
```typescript
import { Inject } from "@ann/Ioc.annotation";
// 1核心导入 UserServiceImpl 类
import { UserServiceImpl } from "@impl/User.service.impl";
import { BaseLogic, Methods } from "@logic/Base.logic";
export class HomeLogic extends BaseLogic implements Methods {
// 2核心注入 UserServiceImpl 请求中间层类到 HomeLogic类的属性 UserServiceImpl 中
@Inject()
public readonly user!: UserServiceImpl;
public title: string = "12222";
public List: any = [
{ id: 1, name: '2222' },
{ id: 1, name: '32434' }
];
constructor(point: any) {
super();
this.VueApp = point
}
/**
* 在这里面调用需要打开页面就执行的ajax请求
* @constructor
*/
public async StartUp(): Promise<void> {
}
/**
* 请求首页数据
*/
public async getData(): Promise<void> {
// 3核心调用IndexClass方法并传入ajax请求参数然后发送请求获取数据
// let result: any = await this.UserServiceImpl.IndexClass({ type: 1, page: 1 });
this.VueApp.$setToken("")
await this.VueApp.$router.push('/About')
}
}
```
4`logic/`中必须实现构造函数`constructor`,在构造函数中保存`tsx`页面传入指向`vue`实例的`this`,这样才能在`logic`中正确使用`vue`的一些方法,具体看代码:
```typescript
...
constructor(point: any) {
super();
// 1将point 保存到 VueApp 中
this.VueApp = point
}
/**
* 请求首页数据
*/
public async getData(): Promise<void> {
// 2使用vue实例中的 $router 方法,进行路由的跳转
await this.VueApp.$router.push('/About')
}
...
```
5如何将自定义的方法通过 `Vue.prototype.xxx` 挂载到`Vue`上以方便全局使用?
答:在`utils/index.utils.ts`中定义方法的时候请使用装饰器`@GlobalMethod()`装饰方法,然后如果你在`tsx`页面组件中需要使用此方法,那么请在`base.layout.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 interface VueType extends Vue {
$setToken: (token: string) => void
}
```
如果你觉得上面方式使用全局方法太过于麻烦,那么你可以在你需要使用的`logic`类或`tsx`组件中使用装饰器`@Inject()`来注入`index.utils.ts`到类属性中,代码示例:
```typescript
import "@pageLess/Home.less";
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@components/HelloWorld';
import { HomeLogic } from "@logic/page/Home.logic";
import { Route, RawLocation } from 'vue-router';
import { Getter } from "vuex-class";
import { BaseLayout, RouterMeta } from "@layout/base.layout";
// 1导入需要被注入的类
import { IndexUtils } from "@utils/index.utils";
// 2导入装饰器
import {Inject } from "@ann/Ioc.annotation";
@Component
export default class Home extends BaseLayout {
private logic: HomeLogic = new HomeLogic(this);
// 3将 IndexUtils 注入到属性 Utils 中
@Inject()
public readonly Utils!: IndexUtils;
public async created() {
// 4使用 setToken 方法
this.Utils.setToken("1111")
}
protected render() {
return (
<div class="home">
<HelloWorld msg="向HelloWorld props传参"/>
<input type="text" v-model={this.logic.title}/>
<h2>{this.logic.title}</h2>
{this.ClickButton()}
<ul>
{
this.logic.List.map((v:any)=>{
return <li>{v.name}</li>
})
}
</ul>
</div>
)
}
}
```
同理可得,在`logic`中使用也是一样的!!
### 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 <type> 文件类型: [pagelogicserviceimplless]
-n, --file-name <name> 被创建的文件名称
-i, --is-create <is> 是否为 -t 参数自动创建相关文件类型 (default: false)
-v, --version 显示当前的版本
-h, --help display help for command
```
参数说明:
- -t需要被创建的文件类型取值 pageTSX页面logicTSX页面的js抽象层service请求中间层的接口impl实现接口的类lesscss样式文件。可以多传
- -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开发中功能
- [ ] 【重要】1实现`ajax`请求到的数据和`model`层的映射绑定,这种数据绑定关系,可以完全解决后端改接口字段从而导致前端代码也需要同步大量修改的问题!!
- [ ] 【不太重要】1实时监听`configure.config.ts`配置文件,然后根据`ApiList`中的对象`key`名称自动在`service`层的类中生成对应的方法,降低手动复制的低效率!