在开发一个前端程序时,肯定会有很多相似的逻辑或布局,这时就需要提取公共组件或样式来尽可能的复用代码。在angular中,提供了ng-content来更方便的编写组件和布局。
ng-content在一个Angular组件中的view层起到的作用类似于占位符。外部内容被投射进当前组件,替代ng-content的位置,另:不管是否存在外部内容ng-content都不会被渲染到页面中。
主要作用及特点:
- 在组件中嵌入内容
- 在组件中嵌入模板代码
- select属性支持css选择器(”#id”,”.class”等等)
Demo环境:
使用 @angular/cli: 12.0.3的ng new xxx指令所生成的标准开发环境
Package.json
{ "name": "angular-projection", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "watch": "ng build --watch --configuration development", "test": "ng test" }, "private": true, "dependencies": { "@angular/animations": "~12.0.3", "@angular/common": "~12.0.3", "@angular/compiler": "~12.0.3", "@angular/core": "~12.0.3", "@angular/forms": "~12.0.3", "@angular/platform-browser": "~12.0.3", "@angular/platform-browser-dynamic": "~12.0.3", "@angular/router": "~12.0.3", "rxjs": "~6.6.0", "tslib": "^2.1.0", "zone.js": "~0.11.4" }, "devDependencies": { "@angular-devkit/build-angular": "~12.0.3", "@angular/cli": "~12.0.3", "@angular/compiler-cli": "~12.0.3", "@types/jasmine": "~3.6.0", "@types/node": "^12.11.1", "jasmine-core": "~3.7.0", "karma": "~6.3.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "~2.0.3", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "typescript": "~4.2.3" } }
简单投射:
创建一个组件
<div class="demo">
<ng-content></ng-content>
</div>
.demo {
font-size: 16px;
background-color: orange;
}
在app.component.html中引用组件
<app-demo>此文字为投射内容</app-demo>
可以看到文字被正确投射在了子组件app-demo中,效果如下:
针对性投射:
如果同时存在几个需要被投射的外部内容 ,它们将如何被正确定位呢?这需要用到select属性。它可以让你在特定的地方投射具体的内容。该属性支持 CSS 选择器(标签选择器、类选择器、属性选择器、...)来匹配你想要的内容。如果 ng-content 上没有设置 select 属性,它将接收全部内容,或接收不匹配任何其他 ng-content 元素的内容
修改一下app-demo
<div class="demo">
<div class="orange">
<ng-content></ng-content>
</div>
<div class="blue">
<ng-content select="header"></ng-content>
</div>
<div class="red">
<ng-content select=".demo2"></ng-content>
</div>
<div class="green">
<ng-content select="[name=demo3]"></ng-content>
</div>
</div>
.demo {
font-size: 16px;
}
.orange {
background-color: orange;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
以及app.component.html
<app-demo>
此段文字是外部嵌入的内容,
<header>
这是外部嵌入的内容,在header中
</header>
<div class="demo2">
这是外部嵌入的内容,所在div的class为"demo2"
</div>
<div name="demo3">
这是外部嵌入的内容demo,所在div的属性name为"demo3"
</div>
这里的文字也会被定位到上没有设置 select 属性的 ng-content 中
</app-demo>
效果如下图:
注:select属性只能获取到直接子节点,假如上面的例子中header被包在一个div中,select=”header”获取不到内容。这时可用ngProjectAs
<div ngProjectAs="header">
<header>
Header 不是直接子节点, 需要在作为直接子节点的div使用 ngProjectAs
</header>
</div>
实践应用:
ng-content除了能投射文本和h5标签以外,还能投射组件。
创建一个表单输入框组件app-form-input和两个标题组件app-form-label-svg, app-form-label-text
app-form-input的input元素是固定的,label可变。这种情况下可以使用ng-content灵活的进行配置
app-form-input
<div class="form-input">
<ng-content></ng-content>
<input type="text">
</div>
app-form-label-svg
<div class="form-label-svg">
<svg …
</svg>
</div>
.form-label-svg {
display: inline-block;
stroke: gray;
}
app-form-label-text
<p class="form-label-text">
<ng-content></ng-content>
</p>
.form-label-text {
display: inline-block;
font-size: 14px;
}
在app.cmponent.html中使用
<app-form-input>
<app-form-label-svg></app-form-label-svg>
</app-form-input>
<app-form-input>
<app-form-label-text>文字标题</app-form-label-text>
</app-form-input>
效果如下:
注:如上例ng-content虽然可以用来投射组件,但是面对复杂的组件如果还是使用ng-content,则会造成组件之间传值的复杂程度大幅上升。这对后期的代码维护很不友好,所以ng-content可以在简单的场景下使用,没有过多的参数,不需要过多的交互。