将html <img/>组件作为参数属性传递给带有react.js的<li>标签

时间:2016-01-19 02:54:14

标签: javascript html reactjs

我正在将字符串转换为一系列图像标记,如下所示:

for (var i = 0; i < cardCollection.length; i++) {
  cardCollection[i].manaCost = cardCollection[i].manaCost.replace(/\{([0-z]+)\}/g, "<img src='\\data\\img\\$1.png' height='20px'/>");
}

这会将类似{1} {G}的内容转换为

<img src='./data/img/1.png' height='20px'/><img src='./data/img/G.png' height='20px'/>

我认为路径设置正确,因为js文件存在于与'data'文件夹相同的文件夹中(我尝试使用和不使用。之前/数据)。然后,我想将此html插入到现有的&lt;李&GT;成分:

< ul onClick = {this.handleListClick} > 
{ cardCollection.map(function(card) {
    if (card.manaCost != undefined) {
        return <li>{card.name} {card.manaCost} </li>; 
    }
    else {
        return <li>{card.name}</li > ;
    }
  })
} < /ul>

这个“有效”,因为它向我显示原始html和图像标签,但不是我想要的实际图像。从card.manaCost周围删除{}只给我'card.manaCost'。假设我的路径是正确的,我需要做些什么才能将其解析为实际的HTML?

2 个答案:

答案 0 :(得分:1)

如果您希望解析HTML字符串,可以使用dangerouslySetInnerHTML属性:

<ul onClick = {this.handleListClick}> 
{ cardCollection.map(function(card) {
    if (card.manaCost != undefined) {
        var html = card.name + ' ' + card.manaCost;
        return <li dangerouslySetInnerHTML={{__html: html}} />;
    }
    else {
        return <li>{card.name}</li>;
    }
  })
} </ul>

然而,请注意看起来有多糟糕。这是故意的,因为React团队不希望您使用它:

  

innerHTML使用不当可能会导致cross-site scripting (XSS)次攻击。消除用户输入以进行显示非常容易出错,无法正确消毒是互联网上的leading causes of web vulnerabilities之一。

我建议不要改变数组(即删除for循环)并直接将图像创建为React元素:

<ul onClick = {this.handleListClick}> 
{ cardCollection.map(function(card, i) {
    var manaCost;
    if (card.manaCost) {
      manaCost = card.manaCost
        .match(/\{[0-z]+\}/g)
        .map(function (basename, i) {
          var src = './data/img/' + basename.substring(1, basename.length - 1) + '.png';
          return <img key={i} src={src} height='20px' />;
        });
    }
    return <li key={i}>{card.name} {manaCost}</li>;
  })
} </ul>

答案 1 :(得分:1)

我不完全确定字符串操作对你有什么影响,也不确定你为什么需要它。

如果你正在编译JSX,那么在你的插值部分内没有理由停止它的转换。

const freeCard = (card, i) => <li key={i}>{ card.title }</li>;
const pricedCard = (card, i) => {
  const src = `./data/img/${card.src}.png`;
  return <li key={i}>{ card.title } <img src={ src } width="20px" /></li>;
};

render () {
  <ul >
    { cards.map((card, i) => card.src ? pricedCard(card) : freeCard(card) }
  </ul>
}

这应该可以正常工作。
请注意,我使用的是ES6模板字符串(用于构建src),
和ES6箭头功能(但function freeCard (card, i) { return <li key={i}>{card.title}</li>; }是等效的。)

如果您正在使用Babel进行转换(您应该如此),并且您正在使用足够新版本的React,那么上述内容就足够了。

唯一未展示的部分是将所有字符串操作更改为:

const parseCost = cost => cost.replace(/\{[0-z]+\}/, "$1");
cards.forEach(card => card.src = parseCost(card.manaCost));

你真正的问题是React阻止你将字符串作为HTML注入 如果你考虑为什么,它应该有意义;如果您决定创建论坛,或者添加博客评论,则React不会在默认情况下插入HTML。

您可以使用元素的dangerouslySetInnerHTML属性,为其提供具有__html属性的对象...

function pricedCard (card, i) {
  const htmlString = "" + card.title + " <img src=\"./data/img/" + card.src + "\" />";
  const content = {
    __html: htmlString
  };

  return <li key={i} dangerouslySetInnerHTML={ content } />;
}

但是你可以看到,这可能不像你希望的那样。

就个人而言,我做的事情如下:

const FreeCard = ({ title }) => <li >{ title }</li>;
const PricedCard = ({ title, src }) => <li >{ title } <img src={ src } /></li>;

render () {
  const list = cards.map((card, i) => card.src ?
    <PricedCard key={i} {...card} /> :
    <FreeCard key={i} {...card} />
  );
  return <ul>{ list }</ul>;
}

我会进一步分析我的结构<li>,但是没有费用的卡在你的例子中没有根结构。