Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

taro3.0版本获取不到元素的dataset属性 #7313

Closed
xwJin opened this issue Aug 12, 2020 · 31 comments
Closed

taro3.0版本获取不到元素的dataset属性 #7313

xwJin opened this issue Aug 12, 2020 · 31 comments
Labels
T-weapp Target - 编译到微信小程序 V-3 Version - 3.x

Comments

@xwJin
Copy link

xwJin commented Aug 12, 2020

相关平台

微信小程序

小程序基础库: 2.12.1
使用框架: Nerv

复现步骤

taro官方模板项目, 在任意view标签上加data-*属性, 在点击事件的event对象里获取的dataset为空

期望结果

能够获取到dataset

实际结果

获取不到dataset

环境信息

Taro CLI 3.0.7 environment info:
    System:
      OS: macOS 10.14.1
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 10.14.1 - /usr/local/bin/node
      Yarn: 1.16.0 - /usr/local/bin/yarn
      npm: 6.4.1 - /usr/local/bin/npm
    npmPackages:
      @tarojs/components: 3.0.7 => 3.0.7 
      @tarojs/mini-runner: 3.0.7 => 3.0.7 
      @tarojs/runtime: 3.0.7 => 3.0.7 
      @tarojs/taro: 3.0.7 => 3.0.7 
      @tarojs/webpack-runner: 3.0.7 => 3.0.7 
      babel-preset-taro: 3.0.7 => 3.0.7 
      eslint-config-taro: 3.0.7 => 3.0.7 
      nervjs: ^1.5.7 => 1.5.7 
@taro-bot2 taro-bot2 bot added F-nerv T-weapp Target - 编译到微信小程序 V-3 Version - 3.x labels Aug 12, 2020
@Chen-jj
Copy link
Contributor

Chen-jj commented Aug 13, 2020

@xwJin 用 React 的语法逻辑进行编码,这种情况你事件函数 bind 一下固定参数就行了,ref 取 Taro DOM 节点获取上面的 props 应该也可以。

@xwJin
Copy link
Author

xwJin commented Aug 13, 2020

@Chen-jj 感谢回答,但是目前的遇到场景其实是,要对商品列表的每个商品做可视上报,这里就用到createIntersectionObserver,之前用2.0版本是通过给每个商品的data- 加上商品信息,然后在createIntersectionObserver.observe 监听到后,做上报处理,现在升级到3.0 不提供dataset了,就没有找到好的方法获取监听到显示的商品的信息,求解~

@Chen-jj
Copy link
Contributor

Chen-jj commented Aug 13, 2020

document.getElementById('#id').xxx 试试

@xwJin
Copy link
Author

xwJin commented Aug 13, 2020

@Chen-jj 试了下,报错没有getElementById这个方法,而且添加了data-属性的元素上也没有显示这个属性,
1597306800361

@xwJin
Copy link
Author

xwJin commented Aug 13, 2020

@Chen-jj 用SelectorQuery也是获取不到元素的dataset的,是不是框架在编译的时候把与标签的这个属性忽略了~

@Chen-jj
Copy link
Contributor

Chen-jj commented Aug 13, 2020

不是设置 dataset,你就当 H5 操作

@haihaigang
Copy link

在小程序中 createIntersectionObserver 获取 dom 上的数据只能通过 dataset 的形式,目前 dom 上都没有 data- 对应的属性

@xwJin
Copy link
Author

xwJin commented Aug 13, 2020

@Chen-jj 目前想在createIntersectionObserver 监听到商品显示的时候,获取对应元素的data- 属性,但是目前对应元素data-属性是空,刚刚用document.getElementById这个方法试了,但是报错没有这个方法

@shinken008
Copy link
Collaborator

@Chen-jj 使用bind是能解决事件参数传值的问题,但是支持 dataset 不是让框架接近原生吗,不应该抛弃这个特性吧。

@digiaries
Copy link
Contributor

这个是因为 taro 在编译的时候只有把基本的属性如 class 写到了标签上,其它的东西很多都被内部接管了。这样在使用一些原生方法获取到页面的节点的时候由于节点上实际没有对应的属性而取不到。dataset 还是希望官方支持一下。

@Chen-jj
Copy link
Contributor

Chen-jj commented Aug 14, 2020

Taro 3 是运行时框架,通过模板拼接渲染 DOM,可以看 dist/base.xml。因为小程序 DOM 不能动态添加属性,所有属性都是提前写死的,不能支持用户自定义设置 data-。Taro 3 把各个小程序看作渲染器,让框架接近原生并不是最大的目标。

Taro 1、2可以支持是因为它们是编译时框架,xml 是编译时根据用户的代码生成的。

我的理解是直接用 ref 或 document.getElementById 找到对应 Taro DOM 节点,取上面的属性即可:

function Index () {
  const ref = useRef(null)
  useEffect(() => {
    console.log('el.props.a: ', ref.current.props.a)
    console.log(document.getElementById('xxx').props.a)
  })

  return (
    <View>
      <View id='xxx' a={1} ref={ref}></View>
    </View>
  )
}

如果这样满足不了你们的场景,可以提供一份 demo,我们再看看

@xwJin
Copy link
Author

xwJin commented Aug 17, 2020

@Chen-jj 用document.getElementById('xxx')可以了,感谢帮忙解答!!

@Chen-jj Chen-jj closed this as completed Aug 19, 2020
@lavapapa
Copy link

建议taro可以给每个元素的dataset设置一个空对象,提供一个读写这个对象的方法

@JimmyLv
Copy link

JimmyLv commented Nov 29, 2020

用户自定义设置 data-

期望能支持已选 用户自定义设置 data- 和小程序 dataset 呀 @Chen-jj

@focus0802
Copy link

@Chen-jj 比如weui.wxss里面写死了的样式,很多都是[data-weui-theme="light"]这种的选择符,在不修改官方weui.wxss的情况下支持 dataset 是最好了

@ws456999
Copy link

ws456999 commented Apr 16, 2021

@xwJin @JimmyLv

翻了下源码,可以通过taro内置实现的bom,获取taroElement实例,该实例上有dataset,代码如下:

import { document } from '@tarojs/runtime';

const node = document.querySelector(xxx);
console.log(node.dataset);

@Rambos
Copy link

Rambos commented Apr 21, 2021

@Chen-jj 比如weui.wxss里面写死了的样式,很多都是[data-weui-theme="light"]这种的选择符,在不修改官方weui.wxss的情况下支持 dataset 是最好了

这个问题就很尴尬了,这种css选择符直接失效了,小程序也是支持这种写法的,我觉得还是需要支持这个 @Chen-jj

@zicjin
Copy link

zicjin commented May 3, 2021

希望h5渲染器能支持data-*属性,这个需求太普遍了。

@cuiyajie
Copy link

cuiyajie commented Jun 1, 2021

@Chen-jj ,如果不支持动态添加属性,不知道是否可以写死若干个data-*的属性,比如固定data-prop1, data-prop2, data-prop3。至少让用户在某些场景下能够使用dataset属性,不过这样会增加base.xml的尺寸,希望权衡一下

@bluescurry
Copy link
Contributor

Taro 3 是运行时框架,通过模板拼接渲染 DOM,可以看 dist/base.xml。因为小程序 DOM 不能动态添加属性,所有属性都是提前写死的,不能支持用户自定义设置 data-。Taro 3 把各个小程序看作渲染器,让框架接近原生并不是最大的目标。

Taro 1、2可以支持是因为它们是编译时框架,xml 是编译时根据用户的代码生成的。

我的理解是直接用 ref 或 document.getElementById 找到对应 Taro DOM 节点,取上面的属性即可:

function Index () {
  const ref = useRef(null)
  useEffect(() => {
    console.log('el.props.a: ', ref.current.props.a)
    console.log(document.getElementById('xxx').props.a)
  })

  return (
    <View>
      <View id='xxx' a={1} ref={ref}></View>
    </View>
  )
}

如果这样满足不了你们的场景,可以提供一份 demo,我们再看看

@Chen-jj 你好,现在有个不得不用到 data-x 属性的场景,就是小程序的自定义埋点,通过 dataset 属性配合 className 的方式进行埋点上报,我们是从原生小程序转到 taro 的,大量埋点都是这么做的,现在 taro 不支持获取data-x 属性,这个埋点都无法迁移了,所以想问下 taro 3 后续有可能会支持获取 data-x 属性吗,如果没有计划的话,我们只能再使用其他方法上报埋点数据了

@Chen-jj
Copy link
Contributor

Chen-jj commented Jun 7, 2021

统一回复一下。

一般情况

我们还是建议按 React、 Vue 的 DSL 特性进行思考,毕竟 dataset 是小程序的特性。

dataset

dataset 是特别的模版属性,主要作用是可以在事件回调的 event 对象中获取到 dataset 相关数据。

这点 Taro 是支持的,在事件回调对象中可以通过 event.target.datasetevent.currentTarget.dataset 获取到:

get target () {
const element = document.getElementById(this.mpEvent?.target.id)
return { ...this.mpEvent?.target, ...this.mpEvent?.detail, dataset: element !== null ? element.dataset : EMPTY_OBJ }
}
get currentTarget () {
const element = document.getElementById(this.mpEvent?.currentTarget.id)
if (element === null) {
return this.target
}
return { ...this.mpEvent?.currentTarget, ...this.mpEvent?.detail, dataset: element.dataset }
}

模板属性

上一点所说的,Taro 对于小程序 dataset 的模拟是在小程序的逻辑层实现的。并没有真正在模板设置这个属性

@focus0802 @Rambos @cuiyajie 各位的诉求都是为组件的模板添加一些特殊属性(和 dataset 概念无关了),这点在 Taro3 中是不会考虑实现的。

之前的回答有说过原因:

Taro 3 是运行时框架,通过模板拼接渲染 DOM,可以看 dist/base.xml。因为小程序 DOM 不能动态添加属性,所有属性都是提前写死的,不能支持用户自定义设置 data-。Taro 3 把各个小程序看作渲染器,让框架接近原生并不是最大的目标。

Taro 1、2可以支持是因为它们是编译时框架,xml 是编译时根据用户的代码生成的。

如果实在是需要为组件模板设置一些特殊属性,如 @cuiyajie 所述,可以考虑使用 taro-plugin-inject 插件注入一些通用属性。

@Owen1994
Copy link

Owen1994 commented Nov 3, 2021

@bluescurry 你给元素设置id属性,在observer回调函数的res值可以看到有个id属性,直接用document.getElementById去获取可以解决

@wangzhigang
Copy link

各位楼主,最后有解决方案吗?

@lazyhero
Copy link

这个问题直接导致 用于车联平台的 微信小程序直接不可用……

因为ZBE旋钮实体按键映射是需要通过注入特定dataset属性来识别的。而且不是通用属性……不可能所有节点的data-xxx 都设置为同样的

建议如果不是纯技术原因导致的“做不了” 还是加上吧,哲学没那么重要

@fantasy525
Copy link

fantasy525 commented Dec 27, 2022

我也是认为需要加上,建议如果不是纯技术原因导致的“做不了” 还是加上吧,哲学没那么重要,dataset难道不是html自带的东西吗?https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset
@Chen-jj

@superchow
Copy link

为何不继承HTML的data-*?, 不是说能编译H5?

@ikapta
Copy link

ikapta commented Dec 22, 2023

@bluescurry 你给元素设置id属性,在observer回调函数的res值可以看到有个id属性,直接用document.getElementById去获取可以解决

确实可以通过 id 获取到 TaroElement 对象,而这个对象,包含了所有我们想要的,包括 dataset,可惜调试的时候肉眼看不见data 属性,所以也无法通过这样方式使用 css的[data-*]属性选择器

ps: 我这里主要实现了两个功能
1、实现单个图片的点击预览(可以一次遍历全部扔进去,预览多图)
2、实现 a 链接的外链的点击打开 webview 预览功能

给富文本添加点击事件,代理所有的点击事件。目前观察,每一个节点本身都会携带一个uid, 可以直接通过 event 如下方式获取到 TaroElement document.getElementById(e.mpEvent.target.id) as unknown as TaroElement

const captureTap = (e: any) => {
    const el = document.getElementById(e.mpEvent.target.id) as unknown as TaroElement;
    console.log('el', el);

    if (!el) return;
    if (el.nodeName === 'image') {
      openImagePreview(el.props.src);
      return;
      // @ts-ignore TaroElement missing h5tagName
    } else if (el.h5tagName === 'a') {
      gotoWebView({ url: el.props.href });
      return;
    }
  }

  // 修改图片行内默认样式,增加 dataset 属性
  // https://juejin.cn/post/7034744611343958052
  Taro.options.html.transformElement = (el) => {
    if (el.nodeName === "image") {
      el.setAttribute("mode", "widthFix");
      el.dataset.previewSrc = el.props.src;
      el.dataset.others = "others";
    }
    return el;
  };

  return (
    <View
      onClick={captureTap}
      dangerouslySetInnerHTML={{ __html: content }}
    />
  );

image

@gausszhou
Copy link

gausszhou commented Mar 5, 2024

@xwJin @JimmyLv

翻了下源码,可以通过taro内置实现的bom,获取taroElement实例,该实例上有dataset,代码如下:

import { document } from '@tarojs/runtime';

const node = document.querySelector(xxx);
console.log(node.dataset);

非常感谢,确实可以获取到。

import { TaroEvent, document } from '@tarojs/runtime';

const getDatasetFromTaroEvent = (e: TaroEvent) => {
  const id = e.mpEvent?.target.id || '';
  if (id === '') return {};
  const taroElement = document.getElementById(id)
  return taroElement?.dataset || {};
}

dataset

@gausszhou
Copy link

gausszhou commented Mar 5, 2024

其实,只是生成的 wxml 没有 data-* 属性,获取到的 e.target 和 e.currentTarget 上仍然是能获取到 dataset 的

dataset

Taro.document.getElementById 对比 wx.createSelectorQuery

wxvstaro

@kelvshi
Copy link

kelvshi commented Jun 28, 2024

@bluescurry 你给元素设置id属性,在observer回调函数的res值可以看到有个id属性,直接用document.getElementById去获取可以解决

确实可以通过 id 获取到 TaroElement 对象,而这个对象,包含了所有我们想要的,包括 dataset,可惜调试的时候肉眼看不见data 属性,所以也无法通过这样方式使用 css的[data-*]属性选择器

ps: 我这里主要实现了两个功能 1、实现单个图片的点击预览(可以一次遍历全部扔进去,预览多图) 2、实现 a 链接的外链的点击打开 webview 预览功能

给富文本添加点击事件,代理所有的点击事件。目前观察,每一个节点本身都会携带一个uid, 可以直接通过 event 如下方式获取到 TaroElement document.getElementById(e.mpEvent.target.id) as unknown as TaroElement

const captureTap = (e: any) => {
    const el = document.getElementById(e.mpEvent.target.id) as unknown as TaroElement;
    console.log('el', el);

    if (!el) return;
    if (el.nodeName === 'image') {
      openImagePreview(el.props.src);
      return;
      // @ts-ignore TaroElement missing h5tagName
    } else if (el.h5tagName === 'a') {
      gotoWebView({ url: el.props.href });
      return;
    }
  }

  // 修改图片行内默认样式,增加 dataset 属性
  // https://juejin.cn/post/7034744611343958052
  Taro.options.html.transformElement = (el) => {
    if (el.nodeName === "image") {
      el.setAttribute("mode", "widthFix");
      el.dataset.previewSrc = el.props.src;
      el.dataset.others = "others";
    }
    return el;
  };

  return (
    <View
      onClick={captureTap}
      dangerouslySetInnerHTML={{ __html: content }}
    />
  );

image

使用了类似的解决方案,不过神奇的是 el.dataset.xxx 我的用的el.setAttribute('data-xxx'), 然后e.target里就找不到了,呜呜~,使用el.dateset.xxx = xxx 就可以了

@victorWuxz
Copy link

这个问题直接导致 用于车联平台的 微信小程序直接不可用……

因为ZBE旋钮实体按键映射是需要通过注入特定dataset属性来识别的。而且不是通用属性……不可能所有节点的data-xxx 都设置为同样的

建议如果不是纯技术原因导致的“做不了” 还是加上吧,哲学没那么重要

可以通过实现一个平台插件来编写车联平台和wmpf小程序,我就这么实现的,但是把坑挺多,只要写的属性默认就是undefined,比如data-focusindex,不填写的view直接变成了undefined,导致ZEB不准

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-weapp Target - 编译到微信小程序 V-3 Version - 3.x
Projects
None yet
Development

No branches or pull requests