}
}
@Component({
template: `
<div>
<h1>{{ title }}</h1>
<p>Counted: {{ counter }}</p>
</div>
`
})
export default class TimerPage extends Mixins(PageMixin, DisposableMixin) {
counter = 0
mounted() {
const timer = setInterval(() => {
if (this.counter++ >= 3) {
return this.redirectTo('/otherpage')
}
console.log('count to', this.counter);
}, 1000)
this.registerDisposable({
dispose() {
clearInterval(timer)
}
})
}
}
count to 1
count to 2
count to 3
calling reidrectTo /otherpage
about to clear disposables
注意到直接 extends Vue 的 DisposableMixin 并不是一个有效的 Vue 组件,也不可以直接在 mixins 选项里使用,如果要被以 Vue.extend 方式扩展的自定义组件使用,记住使用 Component 包装一层。
const ExtendedComponent = Vue.extend({
name: 'ExtendedComponent',
mixins: [Component(DisposableMixin)],
})Abstract class
在业务系统中会使用到的 Mixin 其实多数情况下会更复杂,提供一些基础功能,但有些部分需要留给继承者自行实现,这个时候使用抽象类就很合适。
abstract class AbstractMusicPlayer extends Vue {
abstract audioSrc: string
playing = false
togglePlay() {
this.playing = !this.playing
}
}
class MusicPlayerA extends AbstractMusicPlayer {
audioSrc = '/audio-a.mp3'
}
class MusicPlayerB extends AbstractMusicPlayer {
staticBase = '/statics'
get audioSrc() {
return `${this.staticBase}/audio-b.mp3`
}
}但抽象类是无法被实例化的,并不满足
{ new(): T } 这个要求,因此只能被继承,而不能被混入,由于同样的原因,抽象类也无法被
'vue-class-component' 的 Component 函数装饰。这时候只好将实现了的功能写入 Mixin 中,待实现的功能放到接口里,让具体类来实现。
interface IMusicSourceProvider {
audioSrc: string
}
/**
* @implements IPlayerImplementation
*/
class PlayerMixin extends Vue {
/** @abstract */
audioSrc: string
logSrc() {
console.log(this.audioSrc)
}
}
interface IPlayerImplementation extends IMusicSourceProvider {}
class RealPlayer extends Mixins(PlayerMixin) implements IPlayerImplementation {
audioSrc = '/audio-c.mp3'
}这种欺骗编译器的方式其实还是比较拙劣的,如果一个具体类继承了 PlayerMixin,却没有显示声明实现 IPlayerImplementation ,编译器无法告诉你这个错误。我们只能在代码里小心翼翼写上注释,期待使用者不要忘了这件事。










