Angular 6如何实现带非闭合标签的可复用组件?
嘿,我懂你想通过两个类似“开始/结束”的组件来包裹部分页面内容的需求,但Angular的模板编译器对标签闭合有严格检查,你遇到的Unexpected closing tag "section"错误,本质是因为<openCenteredPage>和<closeCenteredPage>是两个独立组件,它们各自模板里的标签无法形成完整的闭合结构,编译器自然会报错。
下面是符合Angular规范的最佳实现方案:
优先使用「内容投影(Content Projection)」实现单组件包裹
这是Angular官方推荐的方式,用一个组件就能完成你要的“包裹部分内容”的需求,完全避开标签不匹配的问题。
步骤1:创建一个统一的CenteredPageComponent
把你原来openCenteredPage和closeCenteredPage的模板内容合并,用<ng-content></ng-content>作为中间内容的占位符:
centered-page.component.html代码:
<div class="bounds page-wrapper"> <div class="content" fxLayout="row" fxLayout.xs="column" fxFlexFill> <div fxFlex="10" fxFlex.xs="55"></div> <div fxFlex="80"> <div class="main-div"> <section class="mat-typography"> <ng-content></ng-content> <!-- 这里就是要插入自定义内容的位置 --> </section> </div> </div> </div> </div>
步骤2:在页面中使用该组件
用闭合标签包裹你需要的内容即可,完全符合Angular的使用习惯:
<centered-page> <!-- 这里放你要包裹的HTML内容 --> <h2>我的居中页面内容</h2> <p>这部分内容会被自动嵌入到组件的<section>标签内部</p> <mat-button>一个示例按钮</mat-button> </centered-page>
这种方式的优势很明显:
- 符合Angular组件的设计规范,不会触发模板编译错误
- 只用维护一个组件,逻辑和结构更集中,后期修改更方便
- 内容投影是Angular原生支持的特性,稳定性和兼容性都有保障
不推荐:模拟“开始/结束”指令(仅作补充)
如果你非要模拟那种“成对非闭合标签”的形式,理论上可以通过两个指令配合DOM操作实现,但这种方式需要手动处理DOM元素的插入/移除,违背了Angular的声明式编程理念,容易引发DOM操作相关的bug,而且维护成本极高,非常不推荐。
错误原因回顾
你之前的写法之所以报错,是因为Angular会把每个组件的模板当成独立的DOM片段处理:<openCenteredPage>的模板里只开了<section>标签,却没有在同一个组件内闭合;<closeCenteredPage>也没有对应的开启标签,编译器自然会判定标签不匹配。
内容的提问来源于stack exchange,提问作者Tom - Lunabee.com

