首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何解析包含HTML的字符串以响应组件

如何解析包含HTML的字符串以响应组件
EN

Stack Overflow用户
提问于 2018-05-18 23:01:32
回答 4查看 21.1K关注 0票数 16

我正在使用这个库:html-to-react,因为我发现可以将HTML作为字符串进行“编译”以响应组件。

我们正在做一个基于小部件的系统,它们可能会随着时间的推移而改变(即add / remove / update / etc),所以我们计划将小部件HTML从数据库发送到前端,这是使用React完成的。

我已经成功地使用HTML完成了一个简单的小部件,现在我尝试这个小部件来响应单击事件,所以我考虑从HTML添加onclick=method()方法,或者从React添加onClick={method}方法。但是,由于我在浏览器的控制台中得到了这些错误,所以无法获得所需的输出。

代码语言:javascript
复制
Warning: Invalid event handler property `onclick`. React events use the camelCase naming convention, for example `onClick`.
    in label
    in span
    in div
Warning: Invalid event handler property `onclick`. Did you mean `onClick`?
    in label
    in span
    in div
    in DireccionComponent (at App.js:51)
    in div (at App.js:50)
    in GridItem (created by ReactGridLayout)
    in div (created by ReactGridLayout)
    in ReactGridLayout (at App.js:49)
    in App (at index.js:11)

我使用的代码如下:

App.js

代码语言:javascript
复制
import React, { Component } from 'react';
import './App.css';
import DireccionComponent from './DireccionComponent.js';

class App extends Component {
    render() {
        return (
            <DireccionComponent />
        );
    }
}

export default App;

DireccionComponent.js

代码语言:javascript
复制
import React, {Component} from 'react';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            +   '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" onClick={this.myFunction}>Hello</label>'
            +       '</span>'
            +   '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            reactElement
        )
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

export default DireccionComponent;

package.json

代码语言:javascript
复制
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "html-to-react": "^1.3.3",
    "primereact": "^1.5.1",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-dom-server": "0.0.5",
    "react-grid-layout": "^0.16.6",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

是否可以使用上面的库来解析alert来响应组件,从而获得一个或类似的东西?如果是的话,我怎么做呢?或者我做错什么了?

编辑

它不一定是我正在使用的库,如果您使用过另一个库并做了类似的事情,我愿意接受这个建议(注意,我不是在请求软件或库,而是如何在包含我的onClick或解决方案的字符串中调用该方法)

编辑2

在尝试了一些东西之后,我发现删除了这一行:

代码语言:javascript
复制
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);

处理掉其中一条消息。库使用该元素来测试当前HTML和解析HTML是否都是相同的。对于我的情况,我不需要它,但这仍然在控制台中留下当前的错误:

代码语言:javascript
复制
 Warning: Invalid event handler property `onclick`. Did you mean `onClick`?
    in label
    in span
    in div
    in DireccionComponent (at App.js:47)
    in App (at index.js:11)

编辑3

经过一番调查,我发现dangerousSetInnerHTML这个答案

然后,我试图跟随这个答案,在alert中放置一个alert,如下所示:

代码语言:javascript
复制
'<label htmlFor="float-input" onclick="alert(\'Hello\')">Hello2</label>'

它触发了alert,但是如果我在下面的代码中声明了myFunction (请注意,我试图将其声明为类外的function、类内的function以及var myFunction = function() { ... } ):

代码语言:javascript
复制
import React, {Component} from 'react';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            //+ '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" onclick="myFunction()">Hello2</label>'
            +       '</span>'
            //+     '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: htmlInput}}>

            </div>
        )
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

function myFunction() {
    console.log('Hola');
    alert("Hola");
}

export default DireccionComponent;

但这次我又犯了一个错误:

代码语言:javascript
复制
ReferenceError: myFunction is not defined[Learn More]

我发现了一个类似的问题:危险设置inside /正则html中的标记与这个问题,并试图调查更多,并找到了这句话,其中说,从dangerouslySetInnerHTML事件不会被触发的方式和链接到文档

因此,虽然当我直接从alert方法编写一个onclick时,这似乎是一个解决方案,或者我可能没有以正确的方式编写它,所以如果有更多经验的人能够尝试并澄清它,那就太好了。

编辑4

我找到了一种以这种方式显示alert的方法:

  • 将HTML写成字符串
  • 通过dangerouslySetInnerHTML设置HTML
  • componentDidMound()函数上,使用纯Javascript来添加onclick函数。
  • 成功

然而,我们要做的是

  • 创建一些方法,例如:addTwoNumbers或类似的方法
  • 从HTML中发送一个onclickonClick,调用addTwoNumbers函数。
  • 重复每次我们需要添加一个新的组件,这个组件需要使用addTwoNumbers方法,只需要为它编写HTML,将它保存在数据库中并检索它,然后只使用它。

类似于:

代码语言:javascript
复制
...
    <label onClick={myFunction}> My Label </label>
...

或者就像我上面说的:

代码语言:javascript
复制
...
    <label onClick={addTwoNumbers}> My Label </label>
...

允许我获得alert的代码如下:

代码语言:javascript
复制
import React, {Component} from 'react';
import Parser from 'html-react-parser';
import {render} from 'react-dom';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            //+ '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" id="myLabel">Hello2</label>'
            +       '</span>'
            //+     '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: htmlInput}}>

            </div>
        )
    }

    componentDidMount() {
        console.log('DONE');

        let myLabel = document.getElementById("myLabel");

        myLabel.onclick = function() {
            alert();
            console.log('clicked');
        }
        console.log(myLabel);
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

function myFunction() {
    console.log('Hola');
    alert("Hola");
}

export default DireccionComponent;

考虑到这一点,你知道还有什么办法可以做我想做的事吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-05-28 07:38:03

解决方案有点麻烦,将粘贴复制到代码框中。

代码语言:javascript
复制
class App extends Component {
  constructor(props) {
    super(props);
    this.myfunc = this.myfunc.bind(this);
  }
  componentDidMount() {
    window.myfunc = this.myfunc;
  }
  myfunc() {
    console.log("from myfunc");
  }
  componentWillUnmount() {
    window.myfunc = null;
  }
  render() {
    let inputhtml = "<a onclick=window.myfunc()>HelloWorld</a>";
    return (
      <div style={styles}>
        <div dangerouslySetInnerHTML={{ __html: inputhtml }} />
      </div>
    );
  }
}
票数 7
EN

Stack Overflow用户

发布于 2018-05-21 14:57:00

我不知道它是否适用于您的特定情况,但一个想法是根本不解析HTML。您可以告诉webpack为不同的文件集生成分离的包。现在,我从来没有这样做过,但是我已经读过几次您可以读到的东西;例如,

然后,您就可以拥有一个main.bundle.js,它包含站点中所有不改变的部分。另外,为每个可以更改的小部件创建一个widget1.bundle.js等等。在您的index.html上导入所有这些。然后,将您的etc服务器配置为永远不要缓存较小的包(widget1等)。每当用户进入网站,它将再次下载这些小部件,有效地更新它们。如果您想变得更花哨,可以提供每个小部件的当前版本的API,并在小部件包上添加一个附加字段和版本,以便在用户有一段时间没有重新加载页面时,定期检查组件是否是最新的。如果您发现一个过时的组件,只需强制重新加载,浏览器将确保获取最新版本。

我知道这与您要走的路径完全不同,但是如果它对您的特定情况有好处,我相信它将更简单、更容易实现和确保稳定性、更易于维护和更全面地解决方案,而不是亲自解析html和自己处理所有请求。

票数 0
EN

Stack Overflow用户

发布于 2018-05-25 10:05:00

为什么不使用浏览器DOMParser API将您的React.createElement()解析为脱离屏幕/分离的DOM,然后遍历该DOM并使用React.createElement()来构建React的DOM?有点像

代码语言:javascript
复制
let str = "... your HTML ..."

function traverse(node) {
  let children = []
  for (let i = 0; i < node.children.length; i++)
    children.push(traverse(node.children.item(i)))
  return React.createElement(node.localName, null, children)
  // or maybe use the following instead (React's API doc
  // isn't very clear about this):
  // return React.createElement(node.localName, null, ...children)
}

let reactElementForStr =
  traverse(new DOMParser().parseFromString(str, 'text/html'))

请注意,我对React的内部运作只有短暂的了解,而且根本没有测试过这一点。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50420248

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档