Javascript 用React中的Gallery替换img标签

Javascript 用React中的Gallery替换img标签,javascript,html,reactjs,Javascript,Html,Reactjs,渲染库组件存在问题: 我从服务器上获取带有html的字符串 let serverResponse = ` <h3>Some title</h3> <p>Some text</p> <p> <img src=""> <img src=""> <img src=""> <br> <

渲染库组件存在问题: 我从服务器上获取带有html的字符串

let serverResponse = `
  <h3>Some title</h3>
  <p>Some text</p>
  <p>
    <img src="">
    <img src="">
    <img src="">
    <br>
  </p>
...
`
但当我得到2个或更多重复的
标记时,我想用组件替换它们。 我该怎么做?我试着用
Regex
来做这件事,并用
来代替它们,但它不起作用。我想我需要在标记数组中拆分字符串,然后用
组件替换图像。 我试着用
renderToString

...
getGallery = images => {
    // Loop throw images and get sources
  let sources = [];
  if (images) {
  images.map(img => {
    let separatedImages = img.match(/<img (.*?)>/g);
    separatedImages.map(item => sources.push(...item.match(/(https?:\/\/.*\.(?:png|jpg))/)));
  });
  }

  if (sources.length) {
    return <Gallery items={sources}>
  }

  return <div/>
}; 

...
<div dangerouslySetInnerHTML={{__html: serverResponse.replace(/(<img (.*?)>){2,}/g,
                    renderToString(this.getGallery(serverResponse.match(/(<img (.*?)>){2,}/g))))}}/>}
。。。
getGallery=图像=>{
//循环抛出图像并获取源
让源=[];
如果(图像){
images.map(img=>{
让separatedImages=img.match(//g);
separatedImages.map(item=>sources.push(…item.match(/(https?:\/\/.*。(?:png|jpg))/);
});
}
if(源.长度){
返回
}
返回
}; 
...
}

这不起作用,因为我得到的只是没有逻辑的html:(

TLDR:您可以使用或类似的库

虽然JSX看起来非常相似,但它会被解析成一堆
React.createElement
,因此将React组件插入HTML字符串将不起作用。
renderToString
也不起作用,因为它用于服务器端呈现React页面,在您的情况下不起作用


要用React组件替换HTML标记,您需要一个解析器来解析HTML字符串到节点,将节点映射到React元素并呈现它们。幸运的是,有一些库可以做到这一点,例如。

首先,
危险的setinenerHTML
不是办法,您无法将gallery插入到Ini中你需要做的是多步骤的过程

1.将HTML解析为文档。在此阶段,您将把字符串转换为有效的DOM文档。使用DOMParser很容易做到这一点:

function getDOM (html) {
  const parser = new DOMParser()
  const doc = parser.parseFromString(`<div class="container">${html}</div>`, 'text/html')
  return doc.querySelector('.container')
}
这就足够从DOM中创建JSX了。它可以这样使用:

const JSX = getJSX(getDOM(htmlString))
import React from 'react'
import { func, string } from 'prop-types'

function getDOM (html) {
  const parser = new DOMParser()
  const doc = parser.parseFromString(`<div class="container">${html}</div>`, 'text/html')
  return doc.querySelector('.container')
}

function getJSX(root, injectGallery) {
  return [...root.children].map(element => {
    let children

    if (element.querySelector('img + img') && injectGallery) {
      const imageSources = [...element.querySelectorAll('img')].map(img => img.src)
      children = injectGallery(imageSources)
    } else {
      children = element.children.length ? getJSX(element) : element.textContent
    }

    const props = [...element.attributes].reduce((prev, curr) => ({
      ...prev,
      [curr.name]: curr.value
    }), {})

    return React.createElement(element.tagName, props, children)
  })
}

const HTMLContent = ({ content, injectGallery }) => getJSX(getDOM(content), injectGallery)

HTMLContent.propTypes = {
  content: string.isRequired,
  injectGallery: func.isRequired,
}

export default HTMLContent
3.Inject Gallery。现在,如果
元素
包含超过1个图像标记,您可以改进JSX创建,将Gallery注入到已创建的JSX中。我会将Inject函数作为第二个参数传递到
getJSX
。与上述版本的唯一区别是在Gallery情况下如何计算
子对象

if (element.querySelector('img + img') && injectGallery) {
  const imageSources = [...element.querySelectorAll('img')].map(img => img.src)
  children = injectGallery(imageSources)
} else {
  children = element.children.length ? getJSX(element) : element.textContent
}
4.创建图库组件。现在是创建图库组件本身的时候了。该组件如下所示:

const JSX = getJSX(getDOM(htmlString))
import React from 'react'
import { func, string } from 'prop-types'

function getDOM (html) {
  const parser = new DOMParser()
  const doc = parser.parseFromString(`<div class="container">${html}</div>`, 'text/html')
  return doc.querySelector('.container')
}

function getJSX(root, injectGallery) {
  return [...root.children].map(element => {
    let children

    if (element.querySelector('img + img') && injectGallery) {
      const imageSources = [...element.querySelectorAll('img')].map(img => img.src)
      children = injectGallery(imageSources)
    } else {
      children = element.children.length ? getJSX(element) : element.textContent
    }

    const props = [...element.attributes].reduce((prev, curr) => ({
      ...prev,
      [curr.name]: curr.value
    }), {})

    return React.createElement(element.tagName, props, children)
  })
}

const HTMLContent = ({ content, injectGallery }) => getJSX(getDOM(content), injectGallery)

HTMLContent.propTypes = {
  content: string.isRequired,
  injectGallery: func.isRequired,
}

export default HTMLContent
从“React”导入React
从“属性类型”导入{func,string}
函数getDOM(html){
const parser=new DOMParser()
const doc=parser.parseFromString(`${html}`,'text/html')
return doc.querySelector(“.container”)
}
函数getJSX(根,注入库){
返回[…root.children].map(元素=>{
让孩子
if(element.querySelector('img+img')&&injectGallery){
const imageSources=[…element.querySelectorAll('img')].map(img=>img.src)
children=injectGallery(图像源)
}否则{
children=element.childrence.length?getJSX(element):element.textContent
}
常量属性=[…元素.属性].reduce((上一个,当前)=>({
…上一页,
[当前名称]:当前值
}), {})
return React.createElement(element.tagName、props、children)
})
}
constHtmlContent=({content,injectGallery})=>getJSX(getDOM(content),injectGallery)
HTMLContent.propTypes={
内容:string.isRequired,
注:需要功能,
}
导出默认HTMLContent
5.使用它!以下是您将如何一起使用:

<HTMLContent
  content={serverResponse}
  injectGallery={(images) => (
    <Gallery images={images} />
  )}
/>
(
)}
/>
下面是上述代码的演示


演示:

解析当然是一种更好的方式。但是你能确切地告诉我你尝试了什么,以及它是如何不符合你的期望的吗?非常感谢!!!它在react 16上像一个符咒一样工作,但在react 15上不起作用。我在15.6.4上尝试过,但出现了一些问题。如果你能说,我必须做什么在react 15中进行更改。谢谢!您有任何错误吗?请在v15.x中尝试此版本