Skip to content

agileago/vue3-oop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

May 13, 2025
b89a486 · May 13, 2025
Apr 2, 2025
Apr 2, 2025
May 12, 2025
May 13, 2025
Apr 2, 2025
Apr 1, 2025
Apr 1, 2025
Apr 2, 2025
Apr 3, 2025
Apr 2, 2025
May 13, 2025
Apr 3, 2025
Aug 1, 2023
Apr 2, 2025
May 13, 2025
Apr 2, 2025
Apr 2, 2025
Apr 1, 2025
Apr 2, 2025
Apr 2, 2025

Repository files navigation

vue3 oop 文档

类组件+自动化的依赖注入(可选) = 极致的代码体验 DEMO

前提条件

需要reflect-metadata 的支持

pnpm add @abraham/reflection injection-js 

项目入口需要引入 reflect-metadata

import '@abraham/reflection'

tsconfig.json 需要增加配置:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "useDefineForClassFields": false
  } 
}

安装

pnpm add vue3-oop 

vite配置

因为esbuild不支持装饰器的metadata属性,所以需要安装 @vue3-oop/plugin-vue-jsx 插件使用原始ts编译

定义组件

import { Autobind, ComponentProps, Computed, Hook, Link, Mut, VueComponent } from 'vue3-oop'
import { Directive, VNodeChild, watch } from 'vue'

interface FooProps {
  size: 'small' | 'large'
  // 组件的slots
  slots: {
    item(name: string): VNodeChild
  }
}

class Foo extends VueComponent<FooProps> {
  // vue需要的运行时属性检查
  static defaultProps: ComponentProps<FooProps> = ['size']

  constructor() {
    super()
    // watch在构造函数中初始化
    watch(
      () => this.count,
      () => {
        console.log(this.count)
      },
    )
  }

  // 组件自身状态
  @Mut() count = 1

  // 计算属性
  @Computed()
  get doubleCount() {
    return this.count * 2
  }

  add() {
    this.count++
  }

  // 自动绑定this
  @Autobind()
  remove() {
    this.count--
  }

  // 生命周期
  @Hook('Mounted')
  mount() {
    console.log('mounted')
  }

  // 对元素或组件的引用
  @Link() element?: HTMLDivElement

  render() {
    return (
      <div ref="element">
        <span>{this.props.size}</span>
        <button onClick={() => this.add()}>+</button>
        <span>{this.count}</span>
        <button onClick={this.remove}>-</button>
        <div>{this.context.slots.item?.('aaa')}</div>
        <input type="text" v-focus/>
      </div>
    )
  }
}

定义服务

组件和服务的差距是缺少了render这一个表现UI的函数,其他都基本一样

class CountService extends VueService {
  @Mut() count = 1
  add() {
    this.count++
  }
  remove() {
    this.count--
  }
}

依赖注入

Angular文档

import { VueComponent, VueService } from 'vue3-oop'
import { Injectable } from 'injection-js'

// 组件DI
@Component({
  providers: [CountService]
})
class Bar extends VueComponent {
  constructor(private countService: CountService) {super()}

  render() {
    return <div>{this.countService.count}</div>
  }
}

@Injectable()
class BarService extends VueService {
  constructor(private countService: CountService) {super()}
}

支持我

微信

支付宝

QQ交流群

License

MIT