NervJS / taro

开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/
https://docs.taro.zone/
Other
35.68k stars 4.79k forks source link

CustomWrapper 包裹后无法通过id查找到canvas实例 #14398

Open moseszhou opened 1 year ago

moseszhou commented 1 year ago

相关平台

微信小程序

小程序基础库: 2.32.1 使用框架: React

复现步骤

CustomWrapper 包裹

期望结果

例如我开发一个qrcode组件,会用到 const ctx = Taro.createCanvasContext(id, $scope),在taro3.x中 $scope 一般为 getCurrentInstance().page,但是qrcode组件不知道这个组件是否被引用时是否包裹了CustomWrapper,以及他的的父组件是否也被CustomWrapper包裹。是否有办法让我在做qrcode组件时,有一个固定的方式拿到$scope,不管他的上层被包裹过一次或者多次CustomWrapper

实际结果

不知道被包裹多少层CustomWrapper,从而无法找到canvas对象

环境信息

 Taro CLI 3.5.12 environment info:
    System:
      OS: macOS 13.4.1
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 14.19.3 - ~/.nvm/versions/node/v14.19.3/bin/node
      Yarn: 1.22.17 - /usr/local/bin/yarn
      npm: 6.14.17 - ~/.nvm/versions/node/v14.19.3/bin/npm
    npmPackages:
      @tarojs/cli: 3.5.12 => 3.5.12 
      @tarojs/components: 3.5.12 => 3.5.12 
      @tarojs/helper: 3.5.12 => 3.5.12 
      @tarojs/mini-runner: 3.5.12 => 3.5.12 
      @tarojs/plugin-framework-react: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-alipay: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-jd: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-qq: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-swan: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-tt: 3.5.12 => 3.5.12 
      @tarojs/plugin-platform-weapp: 3.5.12 => 3.5.12 
      @tarojs/react: 3.5.12 => 3.5.12 
      @tarojs/rn-runner: 3.5.12 => 3.5.12 
      @tarojs/rn-supporter: 3.5.12 => 3.5.12 
      @tarojs/router: 3.5.12 => 3.5.12 
      @tarojs/runtime: 3.5.12 => 3.5.12 
      @tarojs/shared: 3.5.12 => 3.5.12 
      @tarojs/taro: 3.5.12 => 3.5.12 
      @tarojs/taro-h5: 3.5.12 => 3.5.12 
      @tarojs/taro-rn: 3.5.12 => 3.5.12 
      @tarojs/webpack5-runner: 3.5.12 => 3.5.12 
      babel-preset-taro: 3.5.12 => 3.5.12 
      eslint-config-taro: 3.5.12 => 3.5.12 
      expo: ~45.0.2 => 45.0.8 
      react: ^18.1.0 => 18.2.0 
      react-native: 0.68.5 => 0.68.5 
      taro-ui: 2.3.4 => 2.3.4 
ChengGPBU commented 1 year ago

我也遇到了相同的问题,Taro 3.5.12版本 在微信小程序端 当canvas组件嵌套过深(20层)时,canvas无法正常绘制

linhaobin commented 1 year ago

遇到相同问题,不知道有什么解决方案

Chen-jj commented 1 year ago

@moseszhou @ChengGPBU @linhaobin 可以参考这篇文档试试: https://docs.taro.zone/docs/ref/#%E4%BD%BF%E7%94%A8%E4%BA%86-customwrapper-%E6%97%B6

linhaobin commented 1 year ago

@moseszhou @ChengGPBU @linhaobin 可以参考这篇文档试试。

?? 哪篇文档

linhaobin commented 1 year ago

找到一种解决方法

export interface Node {
  tagName: string;
  parentNode?: Node;
  ctx: any;
}

export function findCustomWrapperParent(nodeRef: React.RefObject<unknown>) {
  let node = (nodeRef.current as Node)?.parentNode;
  while (node) {
    if (node.tagName === 'CUSTOM-WRAPPER') {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

export async function getClientRect({
  ref,
  selectorStr,
}: {
  ref?: React.RefObject<unknown>;
  selectorStr: string;
}) {
  let selector = Taro.createSelectorQuery();

  if (ref) {
    const customWrapper = findCustomWrapperParent(ref);
    if (customWrapper) {
      selector = selector.in(customWrapper.ctx);
    }
  }

  return new Promise<Taro.NodesRef.BoundingClientRectCallbackResult[]>((resolve) => {
    selector
      .select(selectorStr)
      .boundingClientRect()
      .exec((res) => {
        resolve(res);
      });
  });
}
function MyComponent() {
  const ref = useRef(null);

  useReady(async () => {
    const result = await getClientRect({ ref, selectorStr: '#linhaobin' });
    console.info(result);
  });

  return (
    <View ref={ref} id="linhaobin">
      hello bin
    </View>
  );
}
moseszhou commented 1 year ago

找到一种解决方法

export interface Node {
  tagName: string;
  parentNode?: Node;
  ctx: any;
}

export function findCustomWrapperParent(nodeRef: React.RefObject<unknown>) {
  let node = (nodeRef.current as Node)?.parentNode;
  while (node) {
    if (node.tagName === 'CUSTOM-WRAPPER') {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

export async function getClientRect({
  ref,
  selectorStr,
}: {
  ref?: React.RefObject<unknown>;
  selectorStr: string;
}) {
  let selector = Taro.createSelectorQuery();

  if (ref) {
    const customWrapper = findCustomWrapperParent(ref);
    if (customWrapper) {
      selector = selector.in(customWrapper.ctx);
    }
  }

  return new Promise<Taro.NodesRef.BoundingClientRectCallbackResult[]>((resolve) => {
    selector
      .select(selectorStr)
      .boundingClientRect()
      .exec((res) => {
        resolve(res);
      });
  });
}
function MyComponent() {
  const ref = useRef(null);

  useReady(async () => {
    const result = await getClientRect({ ref, selectorStr: '#hbin' });
    console.info(result);
  });

  return (
    <View ref={ref} id="linhaobin">
      hello bin
    </View>
  );
}

我们现在也是按照这个方案做的

zqingr commented 1 year ago

找到一种解决方法

export interface Node {
  tagName: string;
  parentNode?: Node;
  ctx: any;
}

export function findCustomWrapperParent(nodeRef: React.RefObject<unknown>) {
  let node = (nodeRef.current as Node)?.parentNode;
  while (node) {
    if (node.tagName === 'CUSTOM-WRAPPER') {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

export async function getClientRect({
  ref,
  selectorStr,
}: {
  ref?: React.RefObject<unknown>;
  selectorStr: string;
}) {
  let selector = Taro.createSelectorQuery();

  if (ref) {
    const customWrapper = findCustomWrapperParent(ref);
    if (customWrapper) {
      selector = selector.in(customWrapper.ctx);
    }
  }

  return new Promise<Taro.NodesRef.BoundingClientRectCallbackResult[]>((resolve) => {
    selector
      .select(selectorStr)
      .boundingClientRect()
      .exec((res) => {
        resolve(res);
      });
  });
}
function MyComponent() {
  const ref = useRef(null);

  useReady(async () => {
    const result = await getClientRect({ ref, selectorStr: '#hbin' });
    console.info(result);
  });

  return (
    <View ref={ref} id="linhaobin">
      hello bin
    </View>
  );
}

findCustomWrapperParent要找到所有的CustomWrapper父节点才行,不然的话不支持多层嵌套

linhaobin commented 1 year ago

不然的话不支持多层嵌套

实测嵌套也可以,只要找到第一个CustomWrapper 父节点

moseszhou commented 1 year ago

@moseszhou @ChengGPBU @linhaobin 可以参考这篇文档试试: https://docs.taro.zone/docs/ref/#%E4%BD%BF%E7%94%A8%E4%BA%86-customwrapper-%E6%97%B6

你没有看清楚我的诉求,问题是找到合适scope,开发组件时需要不知道自己是否会被customwrapper包裹。

例如我开发一个qrcode组件,会用到 const ctx = Taro.createCanvasContext(id, $scope),在taro3.x中 $scope 一般为 getCurrentInstance().page,但是qrcode组件不知道这个组件是否被引用时是否包裹了CustomWrapper,以及他的的父组件是否也被CustomWrapper包裹。是否有办法让我在做qrcode组件时,有一个固定的方式拿到$scope,不管他的上层被包裹过一次或者多次CustomWrapper

Chen-jj commented 1 year ago

@moseszhou @ChengGPBU @linhaobin 可以参考这篇文档试试: https://docs.taro.zone/docs/ref/#%E4%BD%BF%E7%94%A8%E4%BA%86-customwrapper-%E6%97%B6

你没有看清楚我的诉求,问题是找到合适scope,开发组件时需要不知道自己是否会被customwrapper包裹。

例如我开发一个qrcode组件,会用到 const ctx = Taro.createCanvasContext(id, $scope),在taro3.x中 $scope 一般为 getCurrentInstance().page,但是qrcode组件不知道这个组件是否被引用时是否包裹了CustomWrapper,以及他的的父组件是否也被CustomWrapper包裹。是否有办法让我在做qrcode组件时,有一个固定的方式拿到$scope,不管他的上层被包裹过一次或者多次CustomWrapper

qrcode 组件里主动使用 CustomWrapper 组件进行包裹是否可行?

moseszhou commented 1 year ago

@moseszhou @ChengGPBU @linhaobin 可以参考这篇文档试试: https://docs.taro.zone/docs/ref/#%E4%BD%BF%E7%94%A8%E4%BA%86-customwrapper-%E6%97%B6

你没有看清楚我的诉求,问题是找到合适scope,开发组件时需要不知道自己是否会被customwrapper包裹。 例如我开发一个qrcode组件,会用到 const ctx = Taro.createCanvasContext(id, $scope),在taro3.x中 $scope 一般为 getCurrentInstance().page,但是qrcode组件不知道这个组件是否被引用时是否包裹了CustomWrapper,以及他的的父组件是否也被CustomWrapper包裹。是否有办法让我在做qrcode组件时,有一个固定的方式拿到$scope,不管他的上层被包裹过一次或者多次CustomWrapper

qrcode 组件里主动使用 CustomWrapper 组件进行包裹是否可行? 实测要求 selectComponent('#customWrapper_1 >>> #customWrapper_2 >>> ..... >>> #customWrapper_n') 才能找到找到最终的scope, 如果缺失部分#customWrapper_2 是无法找到最终的scope的 也就是说需要完整的#customWrapper_id的路径