fabricjs给元素添加事件侦听导致可能的内存泄漏问题

14 篇文章 0 订阅
7 篇文章 6 订阅

场景

由于需要给每一种元素设置一个独立的工具栏,所以就需要给每一个元素设置一个独立的事件去修改对应的工具栏的值

比如一个元素的角度显示问题。
我们可以给元素添加一个rotate事件,去动态修改工具栏的angle的值。
在这里插入图片描述
代码:

    this.gettersTarget.on('rotating', arg => {
      // 设置角度的angle值
      this.angleValue = parseInt(arg.target.angle)
    })

但是在测试的时候,发现触发的速度越来越快。
由于工具栏是根据元素而动态变化的,从而导致在设计的时候,用户选择一个元素的时候都需要根据元素去加载对应的组件,并且由于作用域的问题,我们不能去提前绑定,只能在组件加载的时候去绑定,才能通过this去访问工具栏的值。

提前绑定事件不可行

我试过提前绑定事件,但是由于需求是需要重新加载,即使是提前绑定好事件,但是重新加载场景后,this无法正确访问到对应的作用域,也就无法修改对应的值了。这样,原本 绑定事件就失效了。

源码找答案

我们都知道,fabric事件肯定是一个数组管理的,不然也无法解释为什么每次点击后,事件触发的越来越快。所以我们只需要找到fabricjs上的事件管理的数组,在上面去进行判断,让每一个元素只能绑定一个事件,这样就可以避免重复绑定相同的事件而导致的内存泄漏的问题。
在这里插入图片描述
在继承的fabric.object上找到on方法
在这里插入图片描述
在这里插入图片描述
发现事件都绑定到对象的__eventListeners上了。
我们输出看看:
在这里插入图片描述
可以看出来,我们每一次点击而导致的工具栏加载,都会触发重复添加事件。
我们在事件添加判断该事件是否大于0就可以了,当然可以根据需求去进行修改。

    // // 绑定旋转按钮; gettersTarget为当前选择元素的object对象
    let {rotating} = this.gettersTarget.__eventListeners
    if (rotating.length < 1) {
      this.gettersTarget.on('rotating', arg => {
        console.log('1')
        this.angleValue = parseInt(arg.target.angle)
      })
    }

在这里插入图片描述
发现达成目的了,但是出现了一个新的问题。

重新加载事件没用

虽然达到了绑定事件的内存问题,但是由于需求是需要动态加载属性的,如果用户刷新页面,通过fabric的objectTocanvas方法加载回来的canvas,发现工具栏同样无法触发,所以我们需要修改逻辑,需要保证每次点击元素,都需要更新元素对象上的事件是最新的。
这样重新加载都可以修改组件上的input,因为事件绑定是实时的。

在这里插入图片描述

    let rotating = null
    if (this.gettersTarget.__eventListeners) {
      rotating = this.gettersTarget.__eventListeners.rotating
      //   清楚事件
      rotating.pop()
    }
    console.log('1')

    this.gettersTarget.on('rotating', arg => {
      this.angleValue = parseInt(arg.target.angle)
    })
    console.log(this.gettersTarget.__eventListeners)

也保证了事件唯一。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用内部类来实现多个按钮添加事件侦听的功能,具体步骤如下: 1. 定义一个外部类,该类中包含多个按钮对象。 2. 在外部类中定义一个内部类,该内部类实现 ActionListener 接口,用于处理按钮事件。 3. 在内部类的 actionPerformed 方法中,通过 getSource 方法获取事件源对象,根据事件源对象的不同,执行不同的操作。 4. 在外部类中,为每个按钮对象添加事件侦听器,将内部类的实例作为参数传递给 addActionListener 方法。 示例代码如下: ``` public class ButtonDemo { private JButton button1; private JButton button2; public ButtonDemo() { button1 = new JButton("Button 1"); button2 = new JButton("Button 2"); ButtonListener listener = new ButtonListener(); button1.addActionListener(listener); button2.addActionListener(listener); } private class ButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == button1) { // 处理 Button 1 的事件 } else if (source == button2) { // 处理 Button 2 的事件 } } } } ``` 在上面的示例代码中,ButtonDemo 类中包含两个按钮对象 button1 和 button2,通过内部类 ButtonListener 实现了 ActionListener 接口,用于处理按钮事件。在构造函数中,为每个按钮对象添加事件侦听器,将内部类的实例作为参数传递给 addActionListener 方法。在内部类的 actionPerformed 方法中,通过 getSource 方法获取事件源对象,根据事件源对象的不同,执行不同的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值