uni-app renderjs中数据多次频繁变化 不会每次都触发 change中绑定的方法

发布于 1周前 作者 yibo5220 来自 Uni-App

uni-app renderjs中数据多次频繁变化 不会每次都触发 change中绑定的方法

测试过的手机:

  • iphone6
  • 华为

操作步骤:

`:WBData=“WBData” :change:WBData=“fabric.handleWBData” 实现和远端画板同步,我接收远端的WBData数据改变的时候,触发renderjs中的handleWBData方法绘制笔迹,发现不是每次WBData改变都会触发一次handleWBData方法,导致绘制的笔迹丢失了很多

预期结果:

预期每次WBData改变都会触发一次handleWBData方法

实际结果:

不是每次WBData改变都会触发handleWBData方法

bug描述:

`:WBData=“WBData” :change:WBData=“fabric.handleWBData” 实现和远端画板同步,我接收远端的WBData数据改变的时候,触发renderjs中的handleWBData方法绘制笔迹,发现不是每次WBData改变都会触发一次handleWBData方法,导致绘制的笔迹丢失了很多


13 回复

提供可以复现的demo,方便排查


大佬看下我下面的回复,我测试发现绑定越多的变量监听:change, 传递的数据的复杂度越复杂(一个number比一个对象丢失的数据要少),和更改变量的频率越高, 好像renderjs中方法调用次数丢失的更多

回复 ZFZF: 你好 解决了吗,

我上传了一个test.txt文件可以更改为test.vue,然后放到uniapp的项目中,路由进入这个页面,控制台会打印出来更改WBData变量的次数,和renderjs中handleWBData方法的调用次数

前辈如何解决的?我也遇到同样的问题,官方文档没有找到解决方案

回复 9***@qq.com: 您好 有解决吗

我用 renderjs + zrender 绘制自定义 canvas 的时候也会有这种问题,有的时候自定义的图片绘制不出来,数据并没有频繁更改

感觉确实有,我在数据层mounted同时发了三个异步请求,但是只是随机响应2个。。

请问这个问题有解决吗,我现在也遇到了同样的问题

解决办法是有的,不过很蠢,每次检测到响应,通过 callMethod 去通知视图层,定时去检测哪些数据没执行,再重新赋值一次触发数据 update

我也遇到这个问题。请问有解决的办法吗?

同样的问题,目前只能通过用settimeout去短暂延时解决,感觉很扯

在uni-app中,如果你发现使用renderjs时数据频繁变化但并未每次都触发绑定在change事件中的方法,这通常是由于事件绑定或数据监听机制的问题。renderjs提供了高效的性能优化,但也需要正确地设置监听机制来确保数据变化时能够触发相应的处理逻辑。

以下是一个示例,展示如何在renderjs中正确设置数据监听,确保数据变化时能够触发相应的方法:

// 在页面的.vue文件中
<template>
  <view>
    <text>{{ data }}</text>
  </view>
</template>

<script>
export default {
  data() {
    return {
      data: 'Initial Data'
    };
  },
  methods: {
    updateData(newData) {
      this.data = newData; // 这通常不会触发renderjs中的change事件
    },
    onDataChange(newVal, oldVal) {
      console.log('Data changed from', oldVal, 'to', newVal);
    }
  },
  mounted() {
    // 使用renderjs监听数据变化
    this.$nextTick(() => {
      const renderScript = `
        const observer = new MutationObserver((mutations) => {
          mutations.forEach(mutation => {
            if (mutation.type === 'childList' || mutation.type === 'characterData') {
              const newVal = document.querySelector('text').textContent;
              // 假设我们在某个地方存储了旧值,这里为了演示直接使用当前值的前一个状态
              const oldVal = uni.__render_data__.data; // 注意:这是示例,实际获取旧值需要额外逻辑
              uni.postMessage({
                type: 'dataChange',
                newVal: newVal,
                oldVal: oldVal
              });
            }
          });
        });

        const targetNode = document.querySelector('text');
        observer.observe(targetNode, {
          characterData: true, // 监听文本内容变化
          subtree: true, // 监听子节点变化
          characterDataOldValue: true // 记录旧值
        });

        // 监听来自Vue实例的消息
        window.addEventListener('message', (event) => {
          if (event.data.type === 'updateData') {
            document.querySelector('text').textContent = event.data.newData;
          }
        });
      `;
      this.$mp.page.addScript(renderScript);

      // 发送数据更新消息给renderjs
      window.postMessage({
        type: 'updateData',
        newData: this.data
      });

      // 监听来自renderjs的数据变化消息
      window.addEventListener('message', (event) => {
        if (event.data.type === 'dataChange') {
          this.onDataChange(event.data.newVal, event.data.oldVal);
        }
      });
    });
  }
};
</script>

注意,上述代码是一个简化的示例,用于说明如何在renderjs中监听DOM变化并通过postMessage与Vue实例通信。实际应用中,你可能需要更复杂的逻辑来管理旧值和新值,以及确保数据同步的正确性。此外,由于renderjs运行环境与Vue实例是隔离的,因此数据同步和事件处理需要仔细设计。

回到顶部