为什么/什么时候ng-content是个好习惯?

时间:2018-08-03 10:22:02

标签: javascript angularjs angular typescript web

关于ng-content /内容投影可能是一个奇怪的问题。我的想法是,您可以动态地放入“内容”,然后可以使用ng-content对其进行投影。我还可以做的一件事是使Input属性传递要在组件中显示的信息。

我遇到过这个项目; https://trimox.github.io/angular-mdc-web/#/home 这是Angular的新材料组件。我在浏览代码时发现的一件事是,他极大地利用了ng-content来投影某些“子组件”。我不禁奇怪...为什么?因为我也可以尝试使用一个卡组件和我传递的JSON /对象之类的配置来解决此问题。

<mdc-card class="demo-card">
<mdc-card-primary-action mdc-ripple>
    <mdc-card-media class="demo-card__media--16-9" [wide]="true"></mdc-card-media>
    <div class="demo-card__primary">
        <h2 class="demo-card__title" mdcHeadline6>Our Changing Planet</h2>
        <h3 class="demo-card__subtitle" mdcSubtitle2>by Kurt Wagner</h3>
    </div>
    <div class="demo-card__secondary" mdcBody2>
        Visit ten places on our planet that are undergoing the biggest changes today.
    </div>
</mdc-card-primary-action>
<mdc-card-actions>
    <mdc-card-action-buttons>
        <button mdc-button mdcCardAction="button">Read</button>
        <button mdc-button mdcCardAction="button">Bookmark</button>
    </mdc-card-action-buttons>
    <mdc-card-action-icons>
        <button mdcIconButton mdcCardAction="icon" iconOn="favorite" iconOff="favorite_border"></button>
        <mdc-icon mdcCardAction="icon" mdcRipple>share</mdc-icon>
        <mdc-icon mdcCardAction="icon" mdcRipple>more_vert</mdc-icon>
    </mdc-card-action-icons>
</mdc-card-actions>

在上面,您可以看到例如带有多个项目的“卡片”组件。我也找到了这些组件的来源。 https://github.com/trimox/angular-mdc-web/blob/master/packages/card/card.ts

我原来的问题仍然存在;什么时候使用ng-content是一个好习惯,什么时候不使用。为什么这是个好习惯?我还看到了DevExpress在他们的devextreme库中使用它; https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/RecordGrouping/Angular/Light/

谢谢

2 个答案:

答案 0 :(得分:2)

想象一下,如果您正在将数据从父级传递给子级。通常,我们将使用Input属性绑定,并在子ts中获取数据,然后将数据绑定。除了执行ng-content之外,我们还可以将内容放置在父级的component标签内并绑定父级数据,并在子级内使用ng-content,从而避免输入属性绑定

父组件

 <parent>
        <child>
             <div class="head">{{heading}}</div>    
         </child>
   </parent>

子组件

 <ng-content select=".head"></ng-content>

在这里,我们直接绑定父数据,而不是使用输入属性绑定来处理数据

答案 1 :(得分:1)

让我简化您的问题。假设您要创建一个card组件。您可以编写自己的子组件(连同执行必要的内容投影的代码),如下所示:

<card>
   <card-title>My Title</card-title>
   <card-content>
      <p>Content here...</p>
      <card-action>Some button here</card-action>
   </card-content>
   <card-footer>My footer</card-footer>
</card>

...或者您可以只创建一个<card>组件并将其放入这样的配置对象中:

config = {
   title: "My title",
   content: {
      innerHTML: "<p>Content here...</p>",
      actions: [ {type: "button", text: "Some button here", onClick: "myFunction()"} ]
   },
   footer: "My footer"
}

那为什么要选择第一个选项?


1。语义HTML

一个原因是,通常,将结构(HTML),表示形式(CSS)和行为(JS / TS)分开是一种好习惯。由于card组件可能包含其他结构元素,例如其标题,内容,动作,页脚等,因此最好用HTML表示此结构,而不要通过JavaScript / TypeScript来实现。您应该让您的HTML标记传达您内容的基本含义。这样做可以使您的代码更具语义性,简洁性,可维护性和可读性。也许如果您只是自己开发应用程序(而不是团队工作),那么由于您了解自己的代码,因此无需使其对他人具有语义/可读性。但是,您仍然应该使其对自己的将来可读,因为如果您希望在一年后查看代码,则可能希望代码具有语义性并且易于阅读。

2。利用Angular的模板synatx

选择第一个选项(使用内容投影和子组件)的另一个原因是,您可以在HTML中利用Angular的强大功能,例如数据绑定和*ngFor。例如,如果要显示卡片列表,每张卡片都显示一个社交媒体帖子(例如在Facebook中),则可以轻松编写:

<card *ngFor="let post of posts">
   <card-title>{{post.title}}</card-title>
   <card-content>
      <p>{{post.content}}</p>
      <card-action>
         <card-button (click)="likePost(post)">Like</card-button>
         <card-button (click)="sharePost(post)">Share</card-button>
      </card-action>
   </card-content>
   <card-footer>{{post.footer}}</card-footer>
</card>

而使用JS / TS配置对象来实现同一件事可能会更加困难。