0

我们运行一些带有一些页面的 ASP.NET Core 应用程序。这些都是“经典”的多页应用程序。

对于我们的新门户,我们决定使用 piral。虽然我们添加了几个新模块,但我们还希望使用现有的应用程序。

我们如何在 piral 或客户端 (SPA) 微前端中集成多页应用程序?

多页应用程序的一个示例如下所示(托管在某个地址上,例如https://myexample.com/home

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Privacy Policy - DotnetApp</title>
    <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" href="/">DotnetApp</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/Home/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            <h1>Privacy Policy</h1>

<p>Use this page to detail your site's privacy policy.</p>

        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - DotnetApp - <a href="/Home/Privacy">Privacy</a>
        </div>
    </footer>
    <script src="/lib/jquery/dist/jquery.min.js"></script>
    <script src="/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>

</body>
</html>

我们不需要拥有所有脚本 - 由于样板文件,它们中的大多数都在那里。实际上,我们也可以在没有它们的情况下运行。

4

1 回答 1

2

可以通过多种方式将 MPA 迁移到 Piral。

  1. 创建一个通过 iframe 公开不同 SSRed 部分的包装堆
  2. 创建一个包装堆,通过动态获得的片段公开不同的 SSRed 部分
  3. 将您的 Razor 视图转换为 React 部分,并在 FE/BE 之间进行拆分;将 React 部件放入堆中

我不知道您的应用程序有多复杂,但也许 (1) 是最容易上手的(尤其是如果它,例如,只有一个页面)。

让我们看看如何实现(2):

import * as React from 'react';

export function setup(app) {
    const connect = app.createConnector(() => fetch('https://myexample.com/home').then(res => res.text()));
    app.registerPage('/myexample', connect(({ data }) => {
        const __html = data;
        return <div dangerouslySetInnerHTML={{ __html }} />;
    }));
}

在这里,我们延迟加载内容https://myexample.com/home并将其显示在组件(将是一个页面)中。

您应该注意以下几点:

  • 在最好的情况下检测fetch(或发送一个特殊的标头)并且只返回一个片段而不是完整的响应
  • 如果需要样式表,要么从响应中“捞出”它们,要么预先集成它们(见下一点)
  • 上面的代码没有特殊的 SPA 链接处理。因此,所有链接都与给定的页面 URL 相关,并且它们正在进行完整的转换......
  • JavaScript 不会在给定的解决方案中加载/工作

现在关于你可以做的样式表(除其他外):

import './my-style.css';
import * as React from 'react';

export function setup(app) {
  // ...
}

my-style.css看起来像:

@import url(https://myexample.com/css/site.css);

我们可以在这里有更多的 URL 等,但我故意将其省略。请记住,前面显示的方式可能会引入冲突。因此,要么预先“下载”表格并为其添加前缀(“范围”),要么在影子 DOM 解决方案中全部使用它(影子 DOM 始终“不受”父 DOM 样式的影响,需要导入自己的样式表)。

对于链接处理你可以做什么:使用布局效果,a通过选择器获取所有元素,附加事件并取消原始导航。请改用history上下文。

在代码中,这看起来类似于:

import * as React from 'react';
import { useHistory } from 'react-router';

export function setup(app) {
    const connect = app.createConnector(() => fetch('https://myexample.com/home').then(res => res.text()));
    app.registerPage('/myexample', connect(({ data }) => {
        const __html = data;
        const container = React.useRef();
        const history = useHistory();
        React.useLayoutEffect(() => {
            if (container.current) {
                const anchors = container.current.querySelectorAll('a[href]');
                Array.prototype.forEach.call(anchors, anchor => {
                    anchor.addEventListener('click', ev => {
                        ev.preventDefault();
                        history.push(anchor.getAttribute('href'));
                    });
                });
            }
        }, []);
        return <div dangerouslySetInnerHTML={{ __html }} ref={container} />;
    }));
}
于 2020-04-09T14:43:24.220 回答