Javascript 如何使用Aurelia.io增强服务器端生成的页面?

Javascript 如何使用Aurelia.io增强服务器端生成的页面?,javascript,aurelia,progressive-enhancement,Javascript,Aurelia,Progressive Enhancement,我正在写一个应用程序,其中一些部分是SPA,一些页面是在服务器端为SEO生成的。我选择了Aurelia.io框架,并使用enhanced方法在页面上启用自定义元素。但我找不到在服务器端页面上使用特定于aurelia的模板指令和插值的最佳方法。让我们从一个例子开始 我的所有页面都包含一个动态标题。此标题将是名为my cool header的自定义元素。此标题将加载经过身份验证的用户并显示其名称,或者,如果当前没有经过身份验证的用户,将显示指向登录的链接。页面主体将在服务器端生成并缓存。因此,我们将

我正在写一个应用程序,其中一些部分是SPA,一些页面是在服务器端为SEO生成的。我选择了Aurelia.io框架,并使用
enhanced
方法在页面上启用自定义元素。但我找不到在服务器端页面上使用特定于aurelia的模板指令和插值的最佳方法。让我们从一个例子开始

我的所有页面都包含一个动态标题。此标题将是名为
my cool header
的自定义元素。此标题将加载经过身份验证的用户并显示其名称,或者,如果当前没有经过身份验证的用户,将显示指向登录的链接。页面主体将在服务器端生成并缓存。因此,我们将有类似的内容:


${user.name}
可计算内容
然后,我的标题将由以下内容定义:

从“/user”导入{UserService};
从“aurelia框架”导入{inject};
@注入(用户服务)
导出类MyCoolHeader{
构造函数(用户服务){
this.userService=userService;
}
异步连接(){
this.user=等待this.userService.get();
}
}
使用以下模板:


这个引导脚本:

导出功能配置(aurelia){ 奥雷莉亚。用途 .standardConfiguration() .developmentLogging() .globalResources(“my-cool-header”); 然后(a=>a.enhance(document.body)); } 在这个配置中,自定义元素被很好地加载和实例化。但是,我无法访问
节点内节点的viewModel。因此,将忽略所有插值(
${user.name})和属性(
show.bind
)。如果我在我的内容模板中包含一个自定义元素,那么只有当它在引导中声明为全局时,它才会被加载:
`标记被忽略

我找到了一种解决方法,可以在阅读文档后通过将自定义viewModel设置为Enhanced方法,然后将其注入到我的自定义元素类中来更改viewModel。比如:

从“/main data”导入{MainData};
导出功能配置(aurelia){
const mainData=aurelia.container.get(mainData);
奥雷莉亚。用途
.standardConfiguration()
.developmentLogging()
.globalResources(“my-cool-header”);
然后(a=>a.enhance(mainData,document.body));
}
自定义元素:

从“/user”导入{UserService};
从“aurelia框架”导入{inject};
从“/main data”导入{MainData};
@注入(用户服务,主数据)
导出类MyCustomElement{
构造函数(用户服务、主数据){
this.userService=userService;
this.mainData=mainData;
}
异步连接(){
this.mainData.user=等待this.userService.get();
}
}
最后,如果我这样更改模板,它将起作用:


${user.name}
可计算内容

我不敢相信这是正确的方法,因为它很难看,并且不能解决
标签的问题。所以我的问题是:最好的方法是什么?

将MyColHeader的模板从以下位置更改为:


致:


${user.name}
然后将服务器生成的页面更改为以下内容:


可计算内容
希望有帮助。如果这不能解决问题或不是一个可接受的解决方案,请告诉我

编辑 在阅读了您的回复并仔细思考之后,我倾向于删除
元素。它不提供任何行为,它只是作为一个数据加载器,它的模板由服务器端渲染过程提供,并且预期它将在aurelia模板系统之外进行渲染,不需要重新渲染。下面是这种方法的样子,如果它看起来更合适,请告诉我:


${user.name}
可计算内容
从“/main data”导入{MainData};
从“./user”导入{UserService};
导出功能配置(aurelia){
const mainData=aurelia.container.get(mainData);
constuserservice=aurelia.container.get(userService);
奥雷莉亚。用途
.standardConfiguration()
.developmentLogging();
我保证([
this.userService.get(),
aurelia.start()
])。然后(([user,a])=>{
mainData.user=用户;
a、 增强(主数据、文档、正文);
});
}

补充Jeremy的答案,如果您将模板更改为:


${user.name}
当Aurelia处理元素时,该内容就会出现,在没有内容选择器的情况下,自定义元素标记中的任何内容都会被模板替换

如果随后将非javascript内容放入自定义元素标记中:


当JS关闭时,这些内容将可见
在上面的例子中,如果没有JS,
div
应该仍然存在,因为Aurelia不会将其从DOM中删除

(当然,这是假设您的服务器端技术在服务页面时不会因为某种原因而损坏/修复DOM中未知的HTML标记-这可能不会,因为它会破坏Aurelia)

编辑:

您可能正在寻找的替代方法是
@processContent
装饰器

这允许您传递在Aurelia检查元素之前运行的回调函数

此时,您可以在自定义元素标记之间提升内容,并将其添加为模板元素的子元素。然后,内容应该在viewmodel的范围内

通过这种方式,您可以在自定义元素标记之间使用相同的标记,而不使用javascript,并且在运行Aurelia时在模板的正确范围内使用相同的标记

import {processContent, TargetInstruction, inject} from 'aurelia-framework';

@inject(Element, TargetInstruction)
@processContent(function(viewCompiler, viewResources, element, instruction) {
    // Do stuff
    instruction.templateContent = element;

    return true;
})
class MyViewModel {
    constructor(element, targetInstruction) {
        var behavior = targetInstruction.behaviorInstructions[0];
        var userTemplate = behavior.templateContent;

        element.addChild(userTemplate);
    }
}
免责声明:上面的代码还没有经过测试,我是从我的网格中提取的
import {processContent, noView} from 'aurelia-framework';

@processContent(function(viewCompiler, viewResources, element, instruction) {
  instruction.viewFactory = viewCompiler.compile(`<template>${element.innerHTML}</template>`, viewResources, instruction);
  element.innerHTML = '';
  return false;
})
@noView
export class MyCustomElement {
  attached() {
    this.world = 'World!';
    this.display = true;
  }  
}
<body>
  <my-custom-element>
    <require="./other-custom-element"></require>
    <p
      if.bind="display">Hello ${world}</p>
    <other-custom-element></other-custom-element>
  </my-custom-element>
</body>