Angular 进阶之 一: Projection (ng-content)

在开发一个前端程序时,肯定会有很多相似的逻辑或布局,这时就需要提取公共组件或样式来尽可能的复用代码。在angular中,提供了ng-content来更方便的编写组件和布局。

ng-content在一个Angular组件中的view层起到的作用类似于占位符。外部内容被投射进当前组件,替代ng-content的位置,另:不管是否存在外部内容ng-content都不会被渲染到页面中。

主要作用及特点:

  1. 在组件中嵌入内容
  2. 在组件中嵌入模板代码
  3. 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可以在简单的场景下使用,没有过多的参数,不需要过多的交互。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值