如何使用 React 在标签中设置 img?

How to set img in label using React?

我正在使用 react-chartist 创建图表。在标签上,我想在标签文本旁边添加图像。我尝试了所有想法,但 none 奏效了。一切 return [object Object]。这个问题是否有好的解决方案?我也可以只使用 css 添加标签,但如果我可以在 <Chartist /> 组件中添加标签,那就容易多了。

我尝试的简单代码示例(下面的 codesandbox 演示):

class Chart extends React.Component {
  render() {
    const labels = ["label 1", "label 2", "label 3"];
    const images = [
      "http://placekitten.com/100/100",
      "http://placekitten.com/101/101",
      "http://placekitten.com/102/102"
    ];
    const series = [[40, 30, 20]];

    const labelsInsideReactFragment = labels.map((el, key) => (
      <React.Fragment>
        <img src={images[key]} /> {el}
      </React.Fragment>
    ));

    const labelsViaGhIssue = labels.map((el, key) => {
      return {
        label: el,
        image: images[key]
      };
    });

    const labelsInsideDiv = labels.map((el, key) => (
      <div>
        <img src={images[key]} /> {el}
      </div>
    ));

    const labelsOnlyImg = labels.map((el, key) => <img src={images[key]} />);

    const data1 = {
      labels,
      series
    };

    const data2 = {
      labels: labelsViaGhIssue,
      series
    };

    const data3 = {
      labels: labelsInsideDiv,
      series
    };

    const data4 = {
      labels: labelsInsideReactFragment,
      series
    };

    const data5 = {
      labels: labelsOnlyImg,
      series
    };

    const options = {
      height: "200px",
      width: "500px"
    };

    return (
      <div>
        <ChartistGraph data={data1} options={options} type="Bar" />
        <ChartistGraph data={data2} options={options} type="Bar" />
        <ChartistGraph data={data3} options={options} type="Bar" />
        <ChartistGraph data={data4} options={options} type="Bar" />
        <ChartistGraph data={data5} options={options} type="Bar" />
      </div>
    );
  }
}

演示:https://codesandbox.io/s/chartist-8oeju

我也在 jsbin 上找到了这个演示:https://jsbin.com/gulokelide/edit?js,output 但我猜它在 React 中不起作用。

根据你给的jsbinlink,我们也可以更新react版本

检查我创建的新沙箱。

https://codesandbox.io/s/chartist-m1yv9

方法是:每个 React chartist 组件都附加了它的 chartist 对象。所以添加一个 ref 来捕获它并从每个图表的上下文更新标签,就像 jsbin 示例一样。

import Chartist from "chartist";

//in componentDidMount()
      const chart = this.refTwo.current;
      chart.chartist.on("draw", context => {
        if (context.type === "label" && context.axis.units.pos === "x") {
          if (context.text && context.text.image) {
            const group = new Chartist.Svg("g");
            group.append(
              new Chartist.Svg("image", {
                "xlink:href": context.text.image,
                width: "30px",
                height: "30px",
                x: context.x + 55,
                y: context.y + 5
              })
            );

            context.element.replace(group);
          }
        }
      });


// in render()
<ChartistGraph
          ref={this.refTwo}
          data={data2}
          options={options}
          type="Bar"
 />

您好,您可以对以下元素执行 "on draw":

<ChartistGraph
          listener={{
            draw: e => this.onDrawHandler(e)
          }}
          data={data2}
          options={options}
          type="Bar"
        />

并执行您的 class 方法:

onDrawHandler = context => {
//...code
}

示例如下:

https://codesandbox.io/s/chartist-f7c7d

JSbin 示例使用了 react-chartist 不支持的自定义 on("draw") 函数(并且它还在手动计算标签位置,因此如果宽度或数量不会缩放系列中的数据变化)。也就是说,最简单的解决方案是制作您自己的 Chartist 实例并根据您的需要对其进行更改。

工作示例(无论宽度如何,标签和图像都会缩放到中心 and/or series 中的项目数):

Demo

Source


components/Chart

import React, { Component, cloneElement, Children } from "react";
import Chartist from "chartist";
import PropTypes from "prop-types";

class Chart extends Component {
  componentDidUpdate(prevProps) {
    if (this.props !== prevProps) this.updateChart(this.props);
  }

  componentWillUnmount() {
    if (this.chart) {
      try {
        this.chart.detach();
      } catch (err) {
        throw new Error("Internal chartist error", err);
      }
    }
  }

  componentDidMount = () => this.updateChart(this.props);

  updateChart = ({ data, listener, options, responsiveOptions, type }) => {
    let event;

    if (this.chartist) {
      this.chart.update(data, options, responsiveOptions);
    } else {
      this.chart = new Chartist[type](
        this.chart,
        data,
        options || {},
        responsiveOptions || []
      ).on("draw", context => {
        if (type === "Pie") return;
        if (context.type === "label" && context.axis.units.pos === "x") {
          if (context && context.text) {
            const group = new Chartist.Svg("g");
            const isBar = type === "Bar";
            const hasImage = context.text.image;
            const hasLabel = context.text.label;

            if (hasImage) {
              const x = isBar
                ? context.x + context.width / 2 - 15
                : context.x + 5;
              const y = isBar
                ? context.y + context.height / 2 - 10
                : context.y + 0;

              group.append(
                new Chartist.Svg("image", {
                  "xlink:href": context.text.image,
                  width: "30px",
                  height: "30px",
                  x,
                  y
                })
              );
            }

            if (hasLabel) {
              const x = isBar
                ? context.x + context.width / 2 + 5
                : context.x + 30;
              const y = hasImage
                ? context.y + context.height / 2 + 30
                : context.y + context.height / 2;

              group.append(
                new Chartist.Svg("text", {
                  width: "100px",
                  height: "40px",
                  x,
                  y,
                  "text-anchor": "middle",
                  "alignment-baseline": "hanging"
                }).text(context.text.label || "")
              );
            }

            context.element.replace(group);
          }
        }
      });

      if (listener) {
        for (event in listener) {
          if (listener.hasOwnProperty(event)) {
            this.chart.on(event, listener[event]);
          }
        }
      }
    }

    return this.chart;
  };

  render = () => {
    const { className, style, children, data, type } = this.props;
    const childrenWithProps =
      children &&
      Children.map(children, child =>
        cloneElement(child, {
          type,
          data
        })
      );
    return (
      <div
        className={`ct-chart ${className || ""}`}
        ref={ref => (this.chart = ref)}
        style={style}
      >
        {childrenWithProps}
      </div>
    );
  };
}

Chart.propTypes = {
  type: PropTypes.oneOf(["Line", "Bar", "Pie"]).isRequired,
  data: PropTypes.object.isRequired,
  className: PropTypes.string,
  options: PropTypes.object,
  responsiveOptions: PropTypes.array,
  style: PropTypes.object
};

export default Chart;