带 angular2 的非 SPA

Posted

技术标签:

【中文标题】带 angular2 的非 SPA【英文标题】:Non-SPA with angular2 【发布时间】:2016-06-22 04:31:25 【问题描述】:

我开始使用 angular2(带有 express.js 后端)的目的是将页面的几个部分的控制权传递给 angular2 组件,但我最终意识到,当 angular2 控制整个区域时,系统会更有效。页。但是,我的应用程序不是 SPA,除了包含我的 angular2 根组件的选择器的路由之外,还有其他服务器呈现的路由。

我有2个问题,后面是代码sn-ps:

    每当我加载一个服务器控制的路由,其服务器端渲染的模板不包含我的根组件的选择器<main-comp></main-comp>,angular2 基本上都会向控制台吐出说它没有任何地方可以初始化。我将所有 angular2 初始化代码放在整个应用程序的共享标头中。如果页面上根本不存在它的选择器,有没有办法告诉 angular2 根组件不要呈现自己?

    呈现 angular2 根组件的服务器端路由是 /writing,特定博客文章的 angular2 路由 URL 类似于 /writing/2016/03/post。但是,每当我直接浏览到 URL 时,System.js 都会尝试加载相对于该位置的 app/boot,即/writing/2016/03/app/boot,这显然会失败并显示 404。我认为这是因为我的服务器控制了/writing相对于向服务器请求的基本 URL 的路由和角度负载。因此,我知道的唯一解决方案是将我的应用程序变成一个单服务器路由为'/' 的 SPA,这需要对前端进行大量重写。我该如何解决这个问题?

这是我的根组件:

@Component(
    selector: 'main-comp',
    template: '<router-outlet></router-outlet>',
    providers: [TagService, PostService, BlogStateService],
    directives: [ROUTER_DIRECTIVES, BlogComponent]
)
@RouteConfig([
    path: '/writing/...', name: 'Blog', component: BlogComponent   
])
export class AppComponent 
    constructor(private _blogState : BlogStateService, 
        private _postService : PostService) 
    

这里是&lt;head&gt; 元素:

<head>
    <script src="/js/jquery.min.js"></script>
    <script src="/js/modernizr-2.6.2-respond-1.1.0.min.js"></script>

    <!-- Angular Dependencies -->
    <script src="/app/node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="/app/node_modules/es6-shim/es6-shim.js"></script>

    <script src="/app/node_modules/systemjs/dist/system.src.js"></script>
    <script src="/app/node_modules/moment/moment.js"></script>

    <script>
        System.config(
            packages: 
                app: 
                    format: 'register',
                    defaultExtension: 'js'
                ,
                moment: 
                    main: 'moment.js',
                    type: 'cjs',
                    defaultExtension: 'js'
                
            ,
            map: 
                moment: '/app/node_modules/moment/'
            
        );
    </script>

    <script src="/app/node_modules/rxjs/bundles/Rx.js"></script>
    <script src="/app/node_modules/angular2/bundles/angular2.dev.js"></script>
    <script src="/app/node_modules/angular2/bundles/http.dev.js"></script>
    <script src="/app/node_modules/angular2/bundles/router.dev.js"></script>

    <script>
        System.import('app/js/boot').then(null, console.error.bind(console)); 
    </script>
    <base href="/">

</head>

【问题讨论】:

【参考方案1】:

1) 我想您需要在调用 bootstrap() 之前手动检查,如果未找到选择器,则跳过 bootstrap()

2) 使用&lt;base&gt; 标记或提供APP_BASE_HREF 设置基本URL 可能会解决这个问题。另见Angular 2 router no base href set

【讨论】:

谢谢@Gunter。我尝试了&lt;base&gt; 标签并没有看到任何区别,然后作为测试我尝试&lt;base href="/blah"&gt; 看看实际做了什么,当我点击由RouteConfig 控制的链接时,它在开头附加了“blah”每个角度路由,后跟服务器请求的整个 URL。在另一个问题上,我会看看在调用引导程序之前检查页面上的元素是否可行。还是觉得有点hacky。 您还可以在github.com/angular/angular 中创建错误报告,以便为您所需的引导行为提供开箱即用的支持。【参考方案2】:

对于第一个问题,我在调用引导方法之前在页面上添加了&lt;main-comp&gt; 是否存在的检查(感谢@Gunter 的想法)。

对于上面的第二个问题,我在 system.js 配置中添加了引导文件的路径,如下所示,这样 system.js 就不会加载相对于请求 URL 的 app/boot。

    System.config(
        packages: 
            app: 
                format: 'register',
                defaultExtension: 'js'
            ,
            moment: 
                main: 'moment.js',
                type: 'cjs',
                defaultExtension: 'js'
            
        ,
        map: 
            app: '/app',   //<----------added this line
            moment: '/app/node_modules/moment/'
        
    );

【讨论】:

以上是关于带 angular2 的非 SPA的主要内容,如果未能解决你的问题,请参考以下文章

ObjectDataSource 未能找到带参数的非泛型方法

使用带参数方式新增或修改可为空的非字符串类型数据到oralce数据库

二叉树的非递归遍历(面试常考)

如何使用文本掩码中的 angular2 createNumberMask 用小数格式化百分比

iOS 10.3 APFS 不支持大部分的非英文字符解决方案

如何在 Angular 2 中执行无限动画?