Skip to content

定义

组件必须继承 VueComponent

typescript
import { VueComponent } from 'vue3-oop'

class Foo extends VueComponent {
  render() {
    return (
      <div>我是组件UI</div>
    )
  }
}
import { VueComponent } from 'vue3-oop'

class Foo extends VueComponent {
  render() {
    return (
      <div>我是组件UI</div>
    )
  }
}

属性

属性使用接口定义,在组件的 props 上面获取

tsx
import { VueComponent, ComponentProps } from 'vue3-oop'

interface Foo_Props {
  size: 'small' | 'large'
}

class Foo extends VueComponent<Foo_Props> {
  static defaultProps: ComponentProps<Foo_Props> = ['size']
  render() {
    return <div>{this.props.size}</div>
  }
}

// 泛型组件
interface Bar_Props<T = any> {
  data: T
  onChange: (item: T) => void
}
class Bar<T> extends VueComponent<Bar_Props<T>> {
  static defaultProps: ComponentProps<Bar_Props> = ['data', 'onChange']
  render() {
    return <div 
      onClick={() => this.props.onChange?.(this.props.data)}
    >{this.props.data}</div>
  }
}
import { VueComponent, ComponentProps } from 'vue3-oop'

interface Foo_Props {
  size: 'small' | 'large'
}

class Foo extends VueComponent<Foo_Props> {
  static defaultProps: ComponentProps<Foo_Props> = ['size']
  render() {
    return <div>{this.props.size}</div>
  }
}

// 泛型组件
interface Bar_Props<T = any> {
  data: T
  onChange: (item: T) => void
}
class Bar<T> extends VueComponent<Bar_Props<T>> {
  static defaultProps: ComponentProps<Bar_Props> = ['data', 'onChange']
  render() {
    return <div 
      onClick={() => this.props.onChange?.(this.props.data)}
    >{this.props.data}</div>
  }
}

注意!

定义属性之后一定要在类的静态属性 defaultProps 定义 vue 需要的属性定义

上下文

组件的 context 属性上面存储这个组件的 emit, slots, attrs, expose, 就是setup函数的第二个参数

tsx
import { VueComponent } from './component'

class Foo extends VueComponent {
  static inheritAttrs = false

  render() {
    return <div {...this.context.attrs}>foo</div>
  }
}
import { VueComponent } from './component'

class Foo extends VueComponent {
  static inheritAttrs = false

  render() {
    return <div {...this.context.attrs}>foo</div>
  }
}

响应式变量

响应式变量使用装饰器注解一下,主要有2个 MutComputed,此时忘记 .value 的事情, 就是正常普通的变量定义,加上装饰器就是告诉框架当此变量变化的时候我要刷新视图

tsx
class Foo extends VueComponent {
  @Mut() count = 1

  @Computed()
  get doubleCount() {
    return this.count * 2
  }

  render() {
    return (
      <div onClick={() => this.count++}>
        {this.count}
      </div>
    )
  }
}
class Foo extends VueComponent {
  @Mut() count = 1

  @Computed()
  get doubleCount() {
    return this.count * 2
  }

  render() {
    return (
      <div onClick={() => this.count++}>
        {this.count}
      </div>
    )
  }
}

生命周期

生命周期使用 Hook 装饰器

tsx
class Foo extends VueComponent {
  @Hook('Mounted')
  mounted() {
    console.log('foo mounted')
  }

  render() {
    return <span>foo</span> 
  }
}
class Foo extends VueComponent {
  @Hook('Mounted')
  mounted() {
    console.log('foo mounted')
  }

  render() {
    return <span>foo</span> 
  }
}

watch

watch在构造函数中使用, 构造函数其实就认为是 setup,你可以做任何在setup中使用的方法

tsx
import { watch } from 'vue'

class Foo extends VueComponent {
  constructor() {
    super()
    watch(() => this.count, (n, o) => console.log('change', n, o))
  }

  @Mut() count = 1

  render() {
    return <span onClick={() => this.count++}>{this.count}</span>
  }
}
import { watch } from 'vue'

class Foo extends VueComponent {
  constructor() {
    super()
    watch(() => this.count, (n, o) => console.log('change', n, o))
  }

  @Mut() count = 1

  render() {
    return <span onClick={() => this.count++}>{this.count}</span>
  }
}

插槽

slots本质上其实是属性的一部分,为了模板的需要单独给拿出来,他其实就是类似于 react 中的 renderProps, 所以我们可以在属性定义的时候定义一下,

tsx
import { VNodeChild } from 'vue'
import { VueComponent } from 'vue3-oop'

interface Foo_Props {
  slots: {
    item(name: string): VNodeChild
  }
}

// 此时如果只有slots的话就可以不用定义 defaultProps
class Foo extends VueComponent<Foo_Props> {
  render() {
    return (
      <div>
        {this.context.slots.item?.('aaaa')}
      </div>
    )
  }
}
import { VNodeChild } from 'vue'
import { VueComponent } from 'vue3-oop'

interface Foo_Props {
  slots: {
    item(name: string): VNodeChild
  }
}

// 此时如果只有slots的话就可以不用定义 defaultProps
class Foo extends VueComponent<Foo_Props> {
  render() {
    return (
      <div>
        {this.context.slots.item?.('aaaa')}
      </div>
    )
  }
}

异步组件

异步组件需配合vue提供的Suspense组件使用,需要标记组件的async: true, 并且组件内定义init 方法并且返回promise结果

tsx
class Foo extends VueComponent {
  static async = true 
    
  async init() {
    await new Promise(r => setTimeout(r, 5000))
  }
  
  render() {
    return (
      <div>
        {this.context.slots.item?.('aaaa')}
      </div>
    )
  }
}
class Foo extends VueComponent {
  static async = true 
    
  async init() {
    await new Promise(r => setTimeout(r, 5000))
  }
  
  render() {
    return (
      <div>
        {this.context.slots.item?.('aaaa')}
      </div>
    )
  }
}