为外部网站使用导出 ReactJS 编译后的组件

3
我的问题始于我想在外部网站中使用一个组件作为小部件。首先,我使用React Router创建了一个路由来仅打印该组件,以便我可以在iframe中使用它,但问题是该组件有下拉菜单,因此当它们打开时,您必须滚动才能访问它们。
因此,我在互联网上研究了如何使组件“可小部件化”,但我找不到任何东西,或者至少找不到清晰的内容。
我的问题是,有没有一种方法可以将我的组件与样式和所有内容分开导出,以便将其用作外部网站的小部件?是否有一种标准方法来实现这一点?
此外,是否有一种方法可以通过webpack编译组件?如果可能的话,编译后如何在外部网站中使用它?
为了给您更多信息,我的组件是一个表单,该表单具有下拉日历和弹出窗口,并且使用react-router在/widgets/form上创建了一个路由,仅打印表单组件。
谢谢阅读!
更新1
我希望避免在外部网站中添加React,我只想让他们向其正文添加JS片段,就像这样:
((d, s, u) => {
    const h = d.getElementsByTagName(s)[0],
        j = d.createElement(s);
    j.async = true;
    j.src = 'http://localhost:3000/files/widgets/ibb-form.min.js';
    j.onload = () => {
        console.log('Widget: ibblue form loaded!');
        start({ url: u });
    };
    h.parentNode.insertBefore(j, h);
})(document, 'script', 'http://localhost:3000/widgets/form');

function start({ url }) {
    new window.IBBForm({ url });
}

我在这个片段中使用的JS代码如下:

(() => {
    const IBBForm = class {
        constructor({ id, url }) {
            this._elementID = id || '#ibblue_form';
            this._target = document.querySelector(this._elementID);

            if (!url) throw new Error('No URL specified');
            this._url = url;

            this._iframe = this._createIframe();
            this._target.append(this._iframe);
        }

        _createIframe() {
            const iframe = document.createElement('iframe');
            iframe.id = 'ibblue_form_iframe_' + new Date().getTime();
            iframe.src = this._url;
            iframe.style =
                'width: 100%; height: 600px; border: medium none; background-color: transparent; display: initial;';
            iframe.allowTransparency = 'true';
            return iframe;
        }
    };

    window['IBBForm'] = IBBForm;
})();

更新二

我修改了下载的脚本,使其变为以下内容:

import BookingSearch from './../../src/components/sections/BookingSearch';

(() => {
    const IBBForm = class {
        constructor({ id, url }) {
            this._elementID = id || '#ibblue_form';
            this._target = document.querySelector(this._elementID);

            if (!url) throw new Error('No URL specified');
            this._url = url;

            this._addRequirements().then(() => {
                this._element = this._createForm();
            });
        }

        async _addRequirements() {
            await this._addScript('https://unpkg.com/react@17/umd/react.production.min.js');
            await this._addScript('https://unpkg.com/react-dom@17/umd/react-dom.production.min.js');
        }

        async _addScript(url) {
            return new Promise((resolve, reject) => {
                const h = document.getElementsByTagName(s)[0],
                    j = document.createElement(s);
                j.async = true;
                j.type = 'module';
                j.src = url;
                j.crossorigin = '';
                j.onload = resolve();
                h.parentNode.insertBefore(j, h);
            });
        }

        _createForm() {
            return ReactDOM.render(<BookingSearch widget={true} dataTheme={{}} />, this._target);
        }
    };

    window['IBBForm'] = IBBForm;
})();

当我执行它时,控制台会抛出一些错误:
Uncaught SyntaxError: expected expression, got '<'

Uncaught TypeError: window.IBBForm is not a constructor

一般的回答是,您可以只导出单个组件,然后开发人员可以使用 ReactDOM.render(<YourWidget />, '#foo') 进行渲染。 - azium
我不想将React添加到外部网站中,我希望它像一个简单的代码片段,我会附上一个示例。 - Marc J Cabrer
2
那么,您可能需要导出一个函数来调用 ReactDOM.render,以便消费者可以调用您的函数来调用 React。 - azium
如果你制作一个jQuery小部件,同样的原则也适用--但这还取决于你的消费者期望什么。 - azium
不看出有什么问题 - 只要代码片段是已编译的代码。 - azium
显示剩余5条评论
2个回答

0
通过创建一个指向“widget”(/widgets/form)的iframe,基本上解决了问题,想法是提供react widget的构建js,但这是不可能的。
我也可以将widget的dom打印到网站中,但出于某些内部原因,我拒绝了这个选项。
感谢所有评论并帮助我做出决定!

0

我认为您没有正确理解 OP。目标环境不一定是 React 网站。 - azium
消费者只需导入一小段简单的代码,我刚刚更新了帖子。顺便说一下,谢谢! - Marc J Cabrer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接