我看过很多关于通过 MarkupWriter 以编程方式添加 html 的教程,但它会在使用组件的地方添加 html。
有没有办法告诉作者在结束正文标记之前添加它?
另外,我怎样才能得到组件的主体?
我认为不需要那么复杂
@Environmental
private Heartbeat heartbeat;
@SetupRender
void setupRender(MarkupWriter writer) {
writer.element("div");
}
// let the body render as normal
@AfterRender
void afterRender(final MarkupWriter writer) {
Element wrapper = writer.element();
writer.end();
final String bodyMarkup = wrapper.getChildMarkup();
// remove the body
wrapper.remove();
heartbeat.defer(new Runnable() {
public void run() {
Element pageBody = writer.getDocument().find("html/body");
pageBody.raw(bodyMarkup);
}
});
}
要获取组件的主体,您应该 @Inject ComponentResources 并调用 getBody()。
在身体的末端添加一些东西需要更多的思考。我可以看到两种方式。
使用@HeartbeatDeferred 注解,您可以在所有其他组件呈现后访问 DOM。像这样的东西:
public class MyComponent {
private Element body;
void setupRender(MarkupWriter writer) {
body = writer.getDocument().find("html/body");
}
@HeartbeatDeferred
void addToBody() {
body.text("Some text here");
}
}
另一种方法是直接在 body 标记下定义一个组件,该组件嵌套所有其他组件。该组件在其 @SetupRender 方法中将模型对象推送到环境中。然后,定义为顶级组件的子组件的组件可以使用 @Environmental 注释来查找模型对象并为其做出贡献。然后顶级组件呈现模型。
例如:
<html>
<body>
<t:toplevelcomponent>
<t:childcomponent />
<div>...</div>
<div>...</div>
</t:toplevelcomponent>
</body>
</html>
public class TopLevelModel {
private List<String> contributions;
// getters and setters
}
public class TopLevelComponent {
@Inject
Environment environment;
public void setupRender() {
environment.push(TopLevelModel.class, new TopLevelModel());
}
public void afterRender(MarkupWriter writer) {
TopLevelModel model = environment.pop(TopLevelModel.class);
for (String contribution : model.getContributions()) {
// add text to the body tag
writer.getElement().text(contribution);
}
}
}
public class ChildComponent {
@Environmental
private TopLevelModel topLevelModel;
public void setupRender() {
topLevelModel.getContributions().add("Foo");
topLevelModel.getContributions().add("Bar");
}
}
解决方案:
private Element pageBody;
private String componentBodyMarkup;
private Element wrapper;
@Environmental
private Heartbeat heartbeat;
@SetupRender
private RenderCommand setupRender() {
return new RenderCommand() {
public void render(MarkupWriter writer, RenderQueue queue) {
wrapper = writer.element("div");
RenderCommand renderBody = new RenderCommand() {
public void render(MarkupWriter writer, RenderQueue queue2) {
RenderCommand bodyRenderCommand = typeCoercer.coerce(componentResources.getBody(), RenderCommand.class);
queue2.push(bodyRenderCommand);
}
};
queue.push(renderBody);
}
};
}
@BeforeRenderBody
private boolean beforeRenderBody(MarkupWriter writer) {
return false;
}
@AfterRender
private void afterRender(MarkupWriter writer) {
pageBody = writer.getDocument().find("html/body");
writer.end();
componentBodyMarkup = wrapper.getChildMarkup();
wrapper.remove();
Runnable appendToBody = new Runnable() {
public void run() {
pageBody.raw(componentBodyMarkup);
}
};
heartbeat.defer(appendToBody);
}