feat: add event bus

pr675
Hufe921 3 years ago
parent 2d16866892
commit 0bacc113cd

@ -11,7 +11,9 @@
"deletable", "deletable",
"dppx", "dppx",
"esbenp", "esbenp",
"eventbus",
"inputarea", "inputarea",
"keyof",
"linebreak", "linebreak",
"noopener", "noopener",
"Parens", "Parens",

@ -39,7 +39,8 @@ export default defineConfig({
{ {
text: '监听', text: '监听',
items: [ items: [
{ text: '事件监听', link: '/guide/listener' } { text: '事件监听(listener)', link: '/guide/listener' },
{ text: '事件监听(eventBus)', link: '/guide/eventbus' }
] ]
}, },
{ {

@ -0,0 +1,101 @@
# 事件监听(eventBus)
## 使用方式
```javascript
import Editor from "@hufe921/canvas-editor"
const instance = new Editor(container, <IElement[]>data, options)
// 注册
instance.eventBus.on<K keyof EventMap>(
eventName: K,
callback: EventMap[K]
)
// 移除
instance.eventBus.off<K keyof EventMap>(
eventName: K,
callback: EventMap[K]
)
```
## rangeStyleChange
功能:选区样式发生改变
用法:
```javascript
instance.eventBus.on('rangeStyleChange', (payload: IRangeStyle) => void)
```
## visiblePageNoListChange
功能:可见页发生改变
用法:
```javascript
instance.eventBus.on('visiblePageNoListChange', (payload: number[]) => void)
```
## intersectionPageNoChange
功能:当前页发生改变
用法:
```javascript
instance.eventBus.on('intersectionPageNoChange', (payload: number) => void)
```
## pageSizeChange
功能:当前页数发生改变
用法:
```javascript
instance.eventBus.on('pageSizeChange', (payload: number) => void)
```
## pageScaleChange
功能:当前页面缩放比例发生改变
用法:
```javascript
instance.eventBus.on('pageScaleChange', (payload: number) => void)
```
## contentChange
功能:当前内容发生改变
用法:
```javascript
instance.eventBus.on('contentChange', () => void)
```
## controlChange
功能:当前光标所在控件发生改变
用法:
```javascript
instance.eventBus.on('controlChange', (payload: IControl | null) => void)
```
## pageModeChange
功能:页面模式发生改变
用法:
```javascript
instance.eventBus.on('pageModeChange', (payload: PageMode) => void)
```
## saved
功能:文档执行保存
用法:
```javascript
instance.eventBus.on('saved', (payload: IEditorResult) => void)
```
## zoneChange
功能:区域发生改变
用法:
```javascript
instance.eventBus.on('zoneChange', (payload: EditorZone) => void)
```

@ -1,4 +1,6 @@
# 事件监听 # 事件监听(listener)
> listener只能响应一个方法推荐使用eventBus进行事件监听
## 使用方式 ## 使用方式

@ -79,6 +79,8 @@ import { INLINE_ELEMENT_TYPE } from '../../dataset/constant/Element'
import { ListParticle } from './particle/ListParticle' import { ListParticle } from './particle/ListParticle'
import { Placeholder } from './frame/Placeholder' import { Placeholder } from './frame/Placeholder'
import { WORD_LIKE_REG } from '../../dataset/constant/Regular' import { WORD_LIKE_REG } from '../../dataset/constant/Regular'
import { EventBus } from '../event/eventbus/EventBus'
import { EventBusMap } from '../../interface/EventBus'
export class Draw { export class Draw {
private container: HTMLDivElement private container: HTMLDivElement
@ -95,6 +97,7 @@ export class Draw {
private elementList: IElement[] private elementList: IElement[]
private footerElementList: IElement[] private footerElementList: IElement[]
private listener: Listener private listener: Listener
private eventBus: EventBus<EventBusMap>
private i18n: I18n private i18n: I18n
private canvasEvent: CanvasEvent private canvasEvent: CanvasEvent
@ -146,7 +149,8 @@ export class Draw {
rootContainer: HTMLElement, rootContainer: HTMLElement,
options: DeepRequired<IEditorOption>, options: DeepRequired<IEditorOption>,
data: IEditorData, data: IEditorData,
listener: Listener listener: Listener,
eventBus: EventBus<EventBusMap>
) { ) {
this.container = this._wrapContainer(rootContainer) this.container = this._wrapContainer(rootContainer)
this.pageList = [] this.pageList = []
@ -159,6 +163,7 @@ export class Draw {
this.elementList = data.main this.elementList = data.main
this.footerElementList = data.footer || [] this.footerElementList = data.footer || []
this.listener = listener this.listener = listener
this.eventBus = eventBus
this._formatContainer() this._formatContainer()
this.pageContainer = this._createPageContainer() this.pageContainer = this._createPageContainer()
@ -336,6 +341,9 @@ export class Draw {
if (this.listener.visiblePageNoListChange) { if (this.listener.visiblePageNoListChange) {
this.listener.visiblePageNoListChange(this.visiblePageNoList) this.listener.visiblePageNoListChange(this.visiblePageNoList)
} }
if (this.eventBus.isSubscribe('visiblePageNoListChange')) {
this.eventBus.emit('visiblePageNoListChange', this.visiblePageNoList)
}
} }
public getIntersectionPageNo(): number { public getIntersectionPageNo(): number {
@ -347,6 +355,9 @@ export class Draw {
if (this.listener.intersectionPageNoChange) { if (this.listener.intersectionPageNoChange) {
this.listener.intersectionPageNoChange(this.intersectionPageNo) this.listener.intersectionPageNoChange(this.intersectionPageNo)
} }
if (this.eventBus.isSubscribe('intersectionPageNoChange')) {
this.eventBus.emit('intersectionPageNoChange', this.intersectionPageNo)
}
} }
public getPageNo(): number { public getPageNo(): number {
@ -569,6 +580,10 @@ export class Draw {
return this.listener return this.listener
} }
public getEventBus(): EventBus<EventBusMap> {
return this.eventBus
}
public getCursor(): Cursor { public getCursor(): Cursor {
return this.cursor return this.cursor
} }
@ -709,6 +724,9 @@ export class Draw {
if (this.listener.pageModeChange) { if (this.listener.pageModeChange) {
this.listener.pageModeChange(payload) this.listener.pageModeChange(payload)
} }
if (this.eventBus.isSubscribe('pageModeChange')) {
this.eventBus.emit('pageModeChange', payload)
}
}) })
} }
@ -1801,10 +1819,18 @@ export class Draw {
if (this.listener.pageSizeChange) { if (this.listener.pageSizeChange) {
this.listener.pageSizeChange(this.pageRowList.length) this.listener.pageSizeChange(this.pageRowList.length)
} }
if (this.eventBus.isSubscribe('pageSizeChange')) {
this.eventBus.emit('pageSizeChange', this.pageRowList.length)
}
// 文档内容改变 // 文档内容改变
if (this.listener.contentChange && isSubmitHistory) { if (isSubmitHistory) {
if (this.listener.contentChange) {
this.listener.contentChange() this.listener.contentChange()
} }
if (this.eventBus.isSubscribe('contentChange')) {
this.eventBus.emit('contentChange')
}
}
}) })
} }

@ -7,13 +7,15 @@ import {
IControlOption IControlOption
} from '../../../interface/Control' } from '../../../interface/Control'
import { IElement, IElementPosition } from '../../../interface/Element' import { IElement, IElementPosition } from '../../../interface/Element'
import { EventBusMap } from '../../../interface/EventBus'
import { IRange } from '../../../interface/Range' import { IRange } from '../../../interface/Range'
import { deepClone, splitText } from '../../../utils' import { deepClone, nextTick, splitText } from '../../../utils'
import { import {
formatElementContext, formatElementContext,
pickElementAttr, pickElementAttr,
zipElementList zipElementList
} from '../../../utils/element' } from '../../../utils/element'
import { EventBus } from '../../event/eventbus/EventBus'
import { Listener } from '../../listener/Listener' import { Listener } from '../../listener/Listener'
import { RangeManager } from '../../range/RangeManager' import { RangeManager } from '../../range/RangeManager'
import { Draw } from '../Draw' import { Draw } from '../Draw'
@ -29,6 +31,7 @@ export class Control {
private draw: Draw private draw: Draw
private range: RangeManager private range: RangeManager
private listener: Listener private listener: Listener
private eventBus: EventBus<EventBusMap>
private options: IControlOption private options: IControlOption
private activeControl: IControlInstance | null private activeControl: IControlInstance | null
@ -36,6 +39,8 @@ export class Control {
this.draw = draw this.draw = draw
this.range = draw.getRange() this.range = draw.getRange()
this.listener = draw.getListener() this.listener = draw.getListener()
this.eventBus = draw.getEventBus()
this.options = draw.getOptions().control this.options = draw.getOptions().control
this.activeControl = null this.activeControl = null
} }
@ -132,8 +137,11 @@ export class Control {
this.activeControl = new CheckboxControl(element, this) this.activeControl = new CheckboxControl(element, this)
} }
// 激活控件回调 // 激活控件回调
setTimeout(() => { nextTick(() => {
if (this.listener.controlChange) { const controlChangeListener = this.listener.controlChange
const isSubscribeControlChange =
this.eventBus.isSubscribe('controlChange')
if (!controlChangeListener && !isSubscribeControlChange) return
let payload: IControl let payload: IControl
const value = this.activeControl?.getValue() const value = this.activeControl?.getValue()
if (value && value.length) { if (value && value.length) {
@ -141,7 +149,11 @@ export class Control {
} else { } else {
payload = pickElementAttr(deepClone(element)).control! payload = pickElementAttr(deepClone(element)).control!
} }
this.listener.controlChange(payload) if (controlChangeListener) {
controlChangeListener(payload)
}
if (isSubscribeControlChange) {
this.eventBus.emit('controlChange', payload)
} }
}) })
} }
@ -153,9 +165,16 @@ export class Control {
} }
this.activeControl = null this.activeControl = null
// 销毁控件回调 // 销毁控件回调
setTimeout(() => { nextTick(() => {
if (this.listener.controlChange) { const controlChangeListener = this.listener.controlChange
this.listener.controlChange(null) const isSubscribeControlChange =
this.eventBus.isSubscribe('controlChange')
if (!controlChangeListener && !isSubscribeControlChange) return
if (controlChangeListener) {
controlChangeListener(null)
}
if (isSubscribeControlChange) {
this.eventBus.emit('controlChange', null)
} }
}) })
} }

@ -0,0 +1,46 @@
export class EventBus<EventMap> {
private eventHub: Map<string, Set<Function>>
constructor() {
this.eventHub = new Map()
}
public on<K extends string & keyof EventMap>(
eventName: K,
callback: EventMap[K]
) {
if (!eventName || typeof callback !== 'function') return
const eventSet = this.eventHub.get(eventName) || new Set()
eventSet.add(callback)
this.eventHub.set(eventName, eventSet)
}
public emit<K extends string & keyof EventMap>(
eventName: K,
payload?: EventMap[K] extends (payload: infer P) => void ? P : never
) {
if (!eventName) return
const callBackSet = this.eventHub.get(eventName)
if (!callBackSet) return
if (callBackSet.size === 1) {
const callBack = [...callBackSet]
return callBack[0](payload)
}
callBackSet.forEach(callBack => callBack(payload))
}
public off<K extends string & keyof EventMap>(
eventName: K,
callback: EventMap[K]
) {
if (!eventName || typeof callback !== 'function') return
const callBackSet = this.eventHub.get(eventName)
if (!callBackSet) return
callBackSet.delete(callback)
}
public isSubscribe<K extends string & keyof EventMap>(eventName: K): boolean {
const eventSet = this.eventHub.get(eventName)
return !!eventSet && eventSet.size > 0
}
}

@ -308,6 +308,10 @@ export function keydown(evt: KeyboardEvent, host: CanvasEvent) {
if (listener.saved) { if (listener.saved) {
listener.saved(draw.getValue()) listener.saved(draw.getValue())
} }
const eventBus = draw.getEventBus()
if (eventBus.isSubscribe('saved')) {
eventBus.emit('saved', draw.getValue())
}
evt.preventDefault() evt.preventDefault()
} else if (evt.key === KeyMap.ESC) { } else if (evt.key === KeyMap.ESC) {
// 退出格式刷 // 退出格式刷

@ -4,9 +4,12 @@ import { TEXTLIKE_ELEMENT_TYPE } from '../../dataset/constant/Element'
import { ControlComponent } from '../../dataset/enum/Control' import { ControlComponent } from '../../dataset/enum/Control'
import { IEditorOption } from '../../interface/Editor' import { IEditorOption } from '../../interface/Editor'
import { IElement } from '../../interface/Element' import { IElement } from '../../interface/Element'
import { EventBusMap } from '../../interface/EventBus'
import { IRangeStyle } from '../../interface/Listener'
import { IRange, RangeRowArray, RangeRowMap } from '../../interface/Range' import { IRange, RangeRowArray, RangeRowMap } from '../../interface/Range'
import { getAnchorElement } from '../../utils/element' import { getAnchorElement } from '../../utils/element'
import { Draw } from '../draw/Draw' import { Draw } from '../draw/Draw'
import { EventBus } from '../event/eventbus/EventBus'
import { HistoryManager } from '../history/HistoryManager' import { HistoryManager } from '../history/HistoryManager'
import { Listener } from '../listener/Listener' import { Listener } from '../listener/Listener'
import { Position } from '../position/Position' import { Position } from '../position/Position'
@ -16,6 +19,7 @@ export class RangeManager {
private options: Required<IEditorOption> private options: Required<IEditorOption>
private range: IRange private range: IRange
private listener: Listener private listener: Listener
private eventBus: EventBus<EventBusMap>
private position: Position private position: Position
private historyManager: HistoryManager private historyManager: HistoryManager
@ -23,6 +27,7 @@ export class RangeManager {
this.draw = draw this.draw = draw
this.options = draw.getOptions() this.options = draw.getOptions()
this.listener = draw.getListener() this.listener = draw.getListener()
this.eventBus = draw.getEventBus()
this.position = draw.getPosition() this.position = draw.getPosition()
this.historyManager = draw.getHistoryManager() this.historyManager = draw.getHistoryManager()
this.range = { this.range = {
@ -241,7 +246,10 @@ export class RangeManager {
} }
public setRangeStyle() { public setRangeStyle() {
if (!this.listener.rangeStyleChange) return const rangeStyleChangeListener = this.listener.rangeStyleChange
const isSubscribeRangeStyleChange =
this.eventBus.isSubscribe('rangeStyleChange')
if (!rangeStyleChangeListener && !isSubscribeRangeStyleChange) return
// 结束光标位置 // 结束光标位置
const { startIndex, endIndex, isCrossRowCol } = this.range const { startIndex, endIndex, isCrossRowCol } = this.range
if (!~startIndex && !~endIndex) return if (!~startIndex && !~endIndex) return
@ -281,7 +289,7 @@ export class RangeManager {
const painter = !!this.draw.getPainterStyle() const painter = !!this.draw.getPainterStyle()
const undo = this.historyManager.isCanUndo() const undo = this.historyManager.isCanUndo()
const redo = this.historyManager.isCanRedo() const redo = this.historyManager.isCanRedo()
this.listener.rangeStyleChange({ const rangeStyle: IRangeStyle = {
type, type,
undo, undo,
redo, redo,
@ -300,18 +308,27 @@ export class RangeManager {
level, level,
listType, listType,
listStyle listStyle
}) }
if (rangeStyleChangeListener) {
rangeStyleChangeListener(rangeStyle)
}
if (isSubscribeRangeStyleChange) {
this.eventBus.emit('rangeStyleChange', rangeStyle)
}
} }
public recoveryRangeStyle() { public recoveryRangeStyle() {
if (!this.listener.rangeStyleChange) return const rangeStyleChangeListener = this.listener.rangeStyleChange
const isSubscribeRangeStyleChange =
this.eventBus.isSubscribe('rangeStyleChange')
if (!rangeStyleChangeListener && !isSubscribeRangeStyleChange) return
const font = this.options.defaultFont const font = this.options.defaultFont
const size = this.options.defaultSize const size = this.options.defaultSize
const rowMargin = this.options.defaultRowMargin const rowMargin = this.options.defaultRowMargin
const painter = !!this.draw.getPainterStyle() const painter = !!this.draw.getPainterStyle()
const undo = this.historyManager.isCanUndo() const undo = this.historyManager.isCanUndo()
const redo = this.historyManager.isCanRedo() const redo = this.historyManager.isCanRedo()
this.listener.rangeStyleChange({ const rangeStyle: IRangeStyle = {
type: null, type: null,
undo, undo,
redo, redo,
@ -330,7 +347,13 @@ export class RangeManager {
level: null, level: null,
listType: null, listType: null,
listStyle: null listStyle: null
}) }
if (rangeStyleChangeListener) {
rangeStyleChangeListener(rangeStyle)
}
if (isSubscribeRangeStyleChange) {
this.eventBus.emit('rangeStyleChange', rangeStyle)
}
} }
public shrinkBoundary() { public shrinkBoundary() {

@ -59,6 +59,10 @@ export class Zone {
if (listener.zoneChange) { if (listener.zoneChange) {
listener.zoneChange(payload) listener.zoneChange(payload)
} }
const eventBus = this.draw.getEventBus()
if (eventBus.isSubscribe('zoneChange')) {
eventBus.emit('zoneChange', payload)
}
}) })
} }

@ -57,10 +57,13 @@ import { IPlaceholder } from './interface/Placeholder'
import { defaultPlaceholderOption } from './dataset/constant/Placeholder' import { defaultPlaceholderOption } from './dataset/constant/Placeholder'
import { Plugin } from './core/plugin/Plugin' import { Plugin } from './core/plugin/Plugin'
import { UsePlugin } from './interface/Plugin' import { UsePlugin } from './interface/Plugin'
import { EventBus } from './core/event/eventbus/EventBus'
import { EventBusMap } from './interface/EventBus'
export default class Editor { export default class Editor {
public command: Command public command: Command
public listener: Listener public listener: Listener
public eventBus: EventBus<EventBusMap>
public register: Register public register: Register
public destroy: () => void public destroy: () => void
public use: UsePlugin public use: UsePlugin
@ -179,6 +182,8 @@ export default class Editor {
}) })
// 监听 // 监听
this.listener = new Listener() this.listener = new Listener()
// 事件
this.eventBus = new EventBus<EventBusMap>()
// 启动 // 启动
const draw = new Draw( const draw = new Draw(
container, container,
@ -188,7 +193,8 @@ export default class Editor {
main: mainElementList, main: mainElementList,
footer: footerElementList footer: footerElementList
}, },
this.listener this.listener,
this.eventBus
) )
// 命令 // 命令
this.command = new Command(new CommandAdapt(draw)) this.command = new Command(new CommandAdapt(draw))

@ -0,0 +1,25 @@
import {
IContentChange,
IControlChange,
IIntersectionPageNoChange,
IPageModeChange,
IPageScaleChange,
IPageSizeChange,
IRangeStyleChange,
ISaved,
IVisiblePageNoListChange,
IZoneChange
} from './Listener'
export interface EventBusMap {
rangeStyleChange: IRangeStyleChange
visiblePageNoListChange: IVisiblePageNoListChange
intersectionPageNoChange: IIntersectionPageNoChange
pageSizeChange: IPageSizeChange
pageScaleChange: IPageScaleChange
saved: ISaved
contentChange: IContentChange
controlChange: IControlChange
pageModeChange: IPageModeChange
zoneChange: IZoneChange
}
Loading…
Cancel
Save