在教培服务小程序“优能助教”中,我们引入了一个节拍器功能插件,以提供更好的用户体验。在这个插件中,我们采用了Canvas技术,解决了页面频繁渲染引起的性能瓶颈问题。以下是我们的实现方案和优化措施的简要介绍。
Canvas技术的运用
我们选择了Canvas作为解决方案,主要是因为它具有高性能的绘制能力,并且可以减少页面频繁渲染的问题。通过Canvas,我们可以将节拍器功能实现得更为流畅和高效。
实现布局参考与事件定位
在实现过程中,我们参考了mini-program-rc的布局实现,并借助Canvas的OffscreenCanvasRenderingContext2D接口实现了事件定位。这使得我们能够更精确地处理用户的操作,并且提升了用户的交互体验。
事件代理模式的应用
由于节拍器项目实现布局事件的嵌套处理,我们发现参考的项目无法满足我们的需求。因此,我们采用了事件代理模式,在mini-program-rc基础上对原有项目事件处理模块进行了重构。事件代理模式的核心思想是利用JS事件的冒泡机制,将事件委托给父元素来处理,从而优化了事件处理的流程。
通过以上优化措施,我们成功地提升了教培服务小程序“优能助教”中节拍器功能的性能表现,让用户能够更流畅地使用该功能,提升了用户的满意度和体验质量。
欢迎大家体验“优能助教”小程序,搜索关键词“优能助教”,即可登录注册并使用我们优化后的节拍器功能。
附核心代码,供大家参考
export default class Event implements ScriptEvent {
stageX!: number
stageY!: number
dx!: number
dy!: number;
[_type]: string;
[_bubbles]: boolean;
[_originalEvent]: any;
[_eventListeners]: EventListeners;
[_captureEventListeners]: EventListeners
cancelBubble: boolean
target!: Node
next: any
constructor() {
this[_eventListeners] = {}
this[_captureEventListeners] = {}
this[_type] = ""
this[_originalEvent] = null
this[_bubbles] = true
this.cancelBubble = false
this.next = null
}
__dispatchEvent(id: string, evt: ScriptEvent) {}
setHandler(handler: any) {
this.next = handler
}
/**
* 检测当前存在事件OR下一个区域存在才会绑定
* eventIsExist nextIsExist
* @param {*} eventName
* @param {*} param
*/
handleEvent(eventName: string, event: any) {
const listeners = this[_eventListeners] && this[_eventListeners][event.type]
if (!this.cancelBubble && listeners) {
listeners.forEach(({ listener, once }) => {
event.target = this
listener.call(this, event)
if (once) {
this.removeEventListener(event.type, listener, {
capture: false,
})
}
if (!this.cancelBubble && this.next) {
this.next.handleEvent(eventName, event)
}
})
} else if (this.next) {
this.next.handleEvent(eventName, event)
}
}
stopPropagation() {
this.cancelBubble = true
}
addEventListener(
type: string,
listener: (event: ScriptEvent) => void,
options?: EventOptions | boolean
) {
if (typeof options === "boolean") options = { capture: options }
const { capture, once } = options || {}
const eventListeners = capture ? _captureEventListeners : _eventListeners
this[eventListeners][type] = this[eventListeners][type] || []
this[eventListeners][type].push({ listener, once })
}
removeEventListener(
type: string,
listener: (event: ScriptEvent) => void,
options?: EventOptions | boolean
) {
if (typeof options === "boolean") options = { capture: options }
const { capture } = options || {}
const eventListeners = capture ? _captureEventListeners : _eventListeners
if (this[eventListeners][type]) {
const listeners = this[eventListeners][type]
for (let i = 0; i < listeners.length; i++) {
const { listener: _listener } = listeners[i]
if (listener === _listener) {
this[eventListeners][type].splice(i, 1)
break
}
}
}
}
get type() {
return this[_type]
}
set type(value) {
this[_type] = value
}
get originalEvent() {
return this[_originalEvent]
}
set originalEvent(value) {
this[_originalEvent] = value
}
get bubbles() {
return this[_bubbles]
}
set bubbles(value) {
this[_bubbles] = value
}
}
![](https://img-blog.csdnimg.cn/direct/b8b513b46c8e4f17a12a59be91f3253f.jpeg)
参考资料:
canvas 进阶 —— 如何实现 canvas 的事件系统 - 我的蓝猫被削了的文章 - 知乎
我的蓝猫被削了:canvas 进阶 —— 如何实现 canvas 的事件系统
一个轻量级的微信小程序 Canvas (type=“2d“) 渲染引擎