跳转到内容

Vue 集成

在 Vue 3 中使用 AFSM,推荐用 reactive 包装或 ref 订阅状态。

基本用法

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { FSM, ChangeState } from 'afsm'
class Counter extends FSM {
count = 0
@ChangeState('idle', 'counting')
async increment() {
this.count++
}
}
const counter = new Counter('counter')
const state = ref(counter.state.toString())
const onChange = (newState: any) => {
state.value = newState.toString()
}
onMounted(() => counter.on(FSM.STATECHANGED, onChange))
onUnmounted(() => counter.off(FSM.STATECHANGED, onChange))
</script>
<template>
<p>state: {{ state }}</p>
<p>count: {{ counter.count }}</p>
<button @click="counter.increment()">+1</button>
</template>

组合式函数

封装一个 useFSM

import { ref, onMounted, onUnmounted, type Ref } from 'vue'
import { FSM, type State } from 'afsm'
export function useFSMState(fsm: FSM): Ref<string> {
const state = ref(fsm.state.toString())
const cb = (newState: State) => {
state.value = newState.toString()
}
onMounted(() => fsm.on(FSM.STATECHANGED, cb))
onUnmounted(() => fsm.off(FSM.STATECHANGED, cb))
return state
}

使用:

<script setup lang="ts">
const state = useFSMState(counter)
</script>
<template>
<p>{{ state }}</p>
</template>

中间态与 UI

<template>
<button :disabled="state === 'logining'" @click="auth.login(token)">
{{ state === 'logining' ? 'Logging in...' : 'Login' }}
</button>
</template>

Pinia 集成

AFSM 可以与 Pinia 共存——FSM 管理状态机,Pinia 管理全局 store:

import { defineStore } from 'pinia'
import { FSM, ChangeState } from 'afsm'
class AuthFSM extends FSM {
user?: User
@ChangeState(FSM.INIT, 'loggedIn')
async login(token: string) {
this.user = await fetchUser(token)
}
}
export const useAuthStore = defineStore('auth', () => {
const auth = new AuthFSM('auth')
return { auth }
})

本站点的 Playground 就是 Vue

本站点的 Playground 组件就是用 Vue 3 + AFSM 实现:

<!-- 简化版 -->
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { FSM } from 'afsm'
const fsm = ref<FSM | null>(null)
const history = ref<any[]>([])
function run(example: any) {
const inst = example.create()
inst.on(FSM.STATECHANGED, (newState, oldState) => {
history.value.push({ newState, oldState, time: Date.now() })
})
fsm.value = inst
example.run(inst)
}
</script>

完整源码见 GitHub

下一步