[Angular 基础] - 视图封装 局部引用 父子组件中内容传递

[Angular 基础] - 视图封装 & 局部引用 & 父子组件中内容传递

之前的笔记:

  • [Angular 基础] - Angular 渲染过程 & 组件的创建

  • [Angular 基础] - 数据绑定(databinding)

  • [Angular 基础] - 指令(directives)

    以上为静态页面,即不涉及到跨组件交流的内容

    以下涉及到组件内的沟通,从这开始数据就“活”了

  • [Angular 基础] - 自定义事件 & 自定义属性

下面的例子依旧会沿用 [Angular 基础] - 自定义事件 & 自定义属性 这里创建的项目

视图封装(view encapsulation)

在 [Angular 基础] - Angular 渲染过程 & 组件的创建 中曾经提到过 CSS 的作用域为当前组件,这是因为 Angular 实现的 view encapsulation。

这个部分可以在 @Component 中修改,如:

@Component({
  selector: 'my-component',
  template: `
    <p>My Component</p>
  `,
  encapsulation: ViewEncapsulation.Emulated // default
})

Angular 的 view encapsulation 有 3 个值:Emulated, NoneShadowDom

Emulated

这也是 Angular 默认的实现,在这个实现里,Angular 会为当前组件增添独特的属性,这样当前组件的 CSS 只能绑定于当前的组件上,是一个对 shadow dom 的拟态实现,如下:

在这里插入图片描述

注意这里的 _ngcontent-hash-value,这就是 Angular 随机生成的属性名称,有且只会作用于当前组件上。我这里搜索的是对应的属性名称,可以看到整个 app-server-element 下的 HTML 标签都共享同一个属性名称,无论是 server 还是 blueprint,只要是被 app-server-element 渲染的,都是如此:

在这里插入图片描述

None

None 代表着 Angular 将不会提供任何的 view encapsulation。

如修改一下 app.component.ts,将其 view encapsulation 修改为 None,同时为 p 标签增加颜色:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  encapsulation: ViewEncapsulation.None,
})
p {
  color: blue;
}

其效果如下:

在这里插入图片描述

鉴于该样式写在 app.component.css 中,会被所有的组件访问,因此它会成为所有 p 标签的默认样式,一直到被覆盖为止

ShadowDom

这个使用方法就是仰仗原生浏览器去实现 Shadow DOM,这里将其添加到 app-server-elemen 中:

@Component({
  selector: 'app-server-element',
  templateUrl: './server-element.component.html',
  styleUrl: './server-element.component.css',
  encapsulation: ViewEncapsulation.ShadowDom,
})

实现效果如下:

在这里插入图片描述

可以看到,不仅 Angular 没有新增对应的属性,并且其他的样式也消失不见了。这是因为对于浏览器来说,CSS 库不会自动被应用的,因此如果要使用 CSS 库的话,要么手动导入,要么重新实现一下,或者使用 JS 动态绑定

前者依旧会引入大量的重复,因此在常见的 2C 项目中是一个比较少见的实现,比较常规的使用是在自己写库的时候会用到

局部引用(local reference)

local reference 在 [Angular 基础] - 指令(directives) 中的 ngIf 中出现过:

<p *ngIf="serverCreated; else noServer">
  Sever was created, server name is {{ serverName }}
</p>
<ng-template #noServer>
  <p>No server was created!</p>
</ng-template>

其中 #noServer 就是对 ng-template 的 local reference,这里起到的作用就是可以让 Angular 直接在 else 这个条件中获取 <ng-template #noServer> <p>No server was created!</p> </ng-template> 这个元素。

这个做法其实和 React 中的 ref 的作用有些相似,比如说以当前的代码为例,在 cockpit 中获取 server name 和 server content 用的方法是双向绑定,也就是这样的语法 [(ngModel)]="newServerName",但是如果不需要追踪这个值的变化,只需要在点击提交的时候获取元素中的值,则是可以通过 local reference 去实现:

  • V 层修改

    <!-- <input type="text" class="form-control" [(ngModel)]="newServerName" /> -->
    <input type="text" class="form-control" #serverNameInput />
    <!-- 省略若干实现,注意这里传的值 -->
    <button class="btn btn-primary" (click)="onAddServer(serverNameInput)">
      Add Server
    </button>
    

    其中需要注意的一点就是,local reference 只能在 View 层中传递,它无法 直接 在 VM 层中被访问

  • VM 层修改

    export class CockpitComponent {
      onAddServer(nameInput: HTMLInputElement) {
        console.log(nameInput);
    
        console.dir(nameInput);
      }
    }
    

    输出结果为:

    在这里插入图片描述

Local Reference 的主要用法如下:

  • 直接访问 DOM 元素

  • 直接访问子元素

    这点下面会提到怎么实现

  • 搭配 structural directives 进行条件渲染

  • 获取第三方库中的值

父子组件间内容的访问与投射

[Angular 基础] - 自定义事件 & 自定义属性 是父子组件中的属性与事件的交流,这里是内容 (content, DOM) 之间的投射与访问

@ViewChild

虽然说是父组件访问子组件的方法,不过也可以用在同组件的 VM 层和 V 层

获取 Element Ref

具体的方法也是通过绑定 local reference 和 @ViewChild decorator 去实现,代码如下:

  • V 层

    这里的修改和 local reference 中对 V 层的修改类似

    <input type="text" class="form-control" #serverContentInput />
    
  • VM 层

    export class CockpitComponent {
      @ViewChild('serverContentInput', { static: true })
      serverContentInput: ElementRef;
    
      onAddServer(nameInput: HTMLInputElement) {
        console.log(this.serverContentInput);
      }
    }
    

输出结果如下:

在这里插入图片描述

在这里插入图片描述

⚠️:和直接使用 local reference 不同,这里创造的是一个 ElementRef

父组件获取子组件

这里只有 VM 层的修改,在 app.component.ts 中添加一下代码:

export class AppComponent {
  @ViewChild(CockpitComponent, { static: true })
  cockpitComponent: CockpitComponent;

  onServerAdded(serverData: Omit<ServerElement, 'type'>) {
    console.log(this.cockpitComponent);
  }
}

输出结果如下:

在这里插入图片描述

⚠️:这个方法只能获取第一个 instance,如果有多个子组件,可以用 @ViewChildren 进行实现,这个用法暂时不会涉及,等到用到时再补充

❗: 一般不推荐用这种方法去访问/获取 V 层的数据

投射内容

这里是在父元素中渲染一个 placeholder,随后等数据接收完毕后,让子元素重写这个 placeholder,以当前项目为例,目前 server-element 渲染的内容为:

<p>
  <strong *ngIf="aliasElement.type === 'server'" style="color: red"
    >{{ aliasElement.content }}</strong
  >
  <em *ngIf="aliasElement.type === 'blueprint'">{{ aliasElement.content }}</em>
</p>

这样的数据是在 child component 中处理的,不过在有些情况下,对应的数据处理可能需要在父组件完成,而不是通过传递 props 在子组件中进行二次检查——尤其很多时候需要传递 onclick, onsubmit 这种点击事件到子组件中,但是逻辑处理依旧存在于父组件里就会显得比较麻烦——也是可以实现的,如这里将 p 标签的渲染改放到父组件中:

<app-server-element
  *ngFor="let serverElement of serverElements"
  [element]="serverElement"
>
  <p>
    <strong *ngIf="serverElement.type === 'server'" style="color: red"
      >{{ serverElement.content }}</strong
    >
    <em *ngIf="serverElement.type === 'blueprint'"
      >{{ serverElement.content }}</em
    >
  </p>
</app-server-element>

不过直接这么修改会导致数据丢失:

在这里插入图片描述

这时候,需要在 server-element 中放置一个 ng-content 的指令(directive),这样当前组件就会接受从父组件传来的 内容(content),并且将其投射出来,现在的 server-element 代码如下:

<div class="panel panel-default">
  <div class="panel-heading">{{ aliasElement.name }}</div>
  <div class="panel-body">
    <ng-content></ng-content>
  </div>
</div>

这一部分相对于 React 来说确实更加的动态,子组件不需要从父组件接受数据——当然,也可以动态绑定属性和事件进行实现

@ContentChild

使用 @ContentChild 可以让子组件访问 父组件投射到子组件中的 内容(content),也就是上面使用 ng-content 进行投射的渲染内容

具体方法如下:

  • 父组件中声明一个 local reference

    这里的实现在 V 层:

    <p #contentParagraph>
      <strong *ngIf="serverElement.type === 'server'" style="color: red"
        >{{ serverElement.content }}</strong
      >
      <em *ngIf="serverElement.type === 'blueprint'"
        >{{ serverElement.content }}</em
      >
    </p>
    
  • 子组件中从 VM 层访问 local reference

    export class ServerElementComponent {
      @ContentChild('contentParagraph', { static: true }) paragraph: ElementRef;
    
      // 这个在 lifecycle 会重新提一下
      ngAfterContentInit() {
        console.log('ngAfterContentInit in ServerElementComponent');
        console.log(this.paragraph, this.paragraph.nativeElement.textContent);
      }
    }
    

    渲染结果如下:

    在这里插入图片描述

⚠️:这个 directive 其实和 @ViewChild/@ViewChildren 一样,也可以用在父组件中获取子组件的投射,并且在 ngAfterContentInit 确认投射完成后做一些对应操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/394717.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APP出海类型有哪些?流量主如何选择广告变现平台?

APP出海成了目前的新趋势&#xff0c;对开发者而言&#xff0c;广告策略和流量分配的方法上也面临着诸多挑战。 一、APP出海类型 01、游戏类应用 游戏类应用是移动应用出海中最受欢迎的类型之一。这类应用通常具有较高的娱乐性和互动性&#xff0c;能够吸引大量用户下载和使…

Eclipse - Expressions Add Watch Expression

Eclipse - Expressions & Add Watch Expression References Window -> Show View -> Other… Show View -> Debug -> Expressions -> Open Debug 模式下出现 Expressions 窗口 Debug 模式下&#xff0c;如果需要查看指定变量或者返回函数的值&#xff0c;直…

区块链技术和Hyperledger Fabric介绍

1 区块链介绍 1.1 区块链技术形成 1.1.1 起源 在比特币诞生之时&#xff0c;技术专家们开始研究比特币的底层技术&#xff0c;并抽象提取出来&#xff0c;形成区块链技术&#xff0c;或者称分布式账本技术。 1.1.2 定义 简称BT&#xff08;Blockchain technology&#xff…

跨境电商无货源如何实现自动化对接1688货源商品上架?1688商品采集API来帮你

阿里巴巴集团旗下的B2B电子商务网站&#xff0c;提供海量优质商品&#xff0c;为采购商和供应商提供交流、合作、采购等服务&#xff0c;是很多没有货源优势的电商卖家首选的货源途径&#xff0c;也是国内最大、货源种类最齐全的货源网站。 不少做跨境电商无货源的朋友都想要直…

UE5 C++ UObject实例化

一.创建UObject C类 在MyObject中声明结构体FMyDataTableStruct 在MyPawn里面&#xff0c;先将头文件里包含 MyObject.h 在MyPawn中声明一个UMyObject类型的指针 TSubclassOf 是提供 UClass 类型安全性的模板类。例如您在创建一个投射物类&#xff0c;允许设计者指定伤害类型…

SSH密钥认证登陆流程(Vscode连接到远程)

目录 前言连接远程步骤1. 下载工具包wsCli到本地机器2. 本地机器上生成ssh密钥3. 在服务器上安装公钥4. vscode连接到远程 参考资料 前言 SSH&#xff08;Secure Shell&#xff09;是一种用于远程登录和安全传输数据的网络协议。它提供了两种主要的远程连接方式&#xff1a; 密…

迁移公众号必须公证吗?

公众号迁移的好处有哪些&#xff1f;迁移后原公众号还能用吗&#xff1f;公众号迁移的好处有很多哦&#xff01;比如可以获得更多权限功能、公司变更或注销时可以保证账号的正常使用、收购账号后可以改变归属权或使用权等等。不过要注意的是&#xff0c;迁移后原公众号就不能再…

用户权限管理系统需求分析(附文档下载)

整体目录 引言 1.1 项目简介 本文档对通用用户权限管理系统的总体设计、接口设计、界面总体设计、数据结构设计、系统出错处理设计以及系统安全数据进行了说明。 1.2 编写说明 1&#xff0e;3参考资料 《通用权限管理系统需求规格说明书》 《通用权限管理系统数据库设计说…

mysql 2-18

加密与解密函数 其他函数 聚合函数 三者效率 GROUP BY HAVING WHERE和HAVING的区别 子查询 单行子查询和多行子查询 单行比较操作符 多行比较操作符 把平均工资生成的结果当成一个新表 相关子查询 EXISTS 一条数据的存储过程 标识符命名规则 创建数据库 MYSQL的数据类型 创建表…

【RT-DETR有效改进】注意力与卷积的高效融合 | ACmix自注意力与卷积混合模型

一、本文介绍 本文给大家带来的改进机制是ACmix自注意力机制的改进版本&#xff0c;它的核心思想是&#xff0c;传统卷积操作和自注意力模块的大部分计算都可以通过1x1的卷积来实现。ACmix首先使用1x1卷积对输入特征图进行投影&#xff0c;生成一组中间特征&#xff0c;然后根…

DS:八大排序之归并排序、计数排序

创作不易&#xff0c;感谢三连支持&#xff01;&#xff01; 一、归并排序 1.1 思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子…

微服务OAuth 2.1认证授权Demo方案(Spring Security 6)

文章目录 一、介绍二、auth微服务代码1. SecurityConfig2. UserDetailsService3. 总结 三、gateway微服务代码1. 统一处理CORS问题 四、content微服务代码1. controller2. SecurityConfig3. 解析JWT Utils4. 总结 五、一些坑 书接上文 微服务OAuth 2.1认证授权可行性方案(Sprin…

【软考高级信息系统项目管理师--第十五章:项目风险管理】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;软考高级–信息系统项目管理师 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 第十五章&#xff1a;项目风险管理 风险的属性风险的分类风险管理过程规划风险管理…

Linux——开发工具的使用

目录 Linux软件包管理器 yum rzsz Linux编辑器——vim vim的使用 vim的基本操作 命令模式的常见命令 底行模式的常见命令 vim是需要配置的 Linux编译器——gcc/g 预处理 编译 汇编 链接 函数库 Linux项目自动化构建工具 make/makefile make原理 项目清理 Linux调试器g…

Home Assistant 接入小米空气净化器

一、在HACS中安装Xiaomi Miot Auto 二、Xiaomi Miot Auto配置基础信息(需要用米家APP加入该设备) 1、选择局域网集成 2、配置小米空气净化器设备基础信息 ip为小米空气净化器设备IP&#xff08;可在米家app中设备详情中查看也可在Get.token中查看&#xff09; Token可以使用Get…

Arduino的PWM应用:舵机控制

目录 概述 1 认识舵机 1.1 舵机分类 1.2 舵机结构 1.3 舵机工作原理 1.4 舵机控制原理 1.5 舵机工作参数介绍 1.5.1 基本参数 1.5.2 舵机扭矩 2 系统硬件 2.1 硬件模块介绍 2.1.1 SG90 9G 360舵机 2.1.2 SG90 9G 180舵机 2.1.3 Arduino UNO 主板 2.2 整体结构…

19. 【Linux教程】nano 编辑器

前面小节介绍了如何使用 vim 编辑器&#xff0c;相比于 vim 编辑器&#xff0c;nano 编辑器就比较简单了。nano 是 UNIX 系统中的一个文本编辑器&#xff0c;大部分 Linux 发行版本默认都安装了 nano 文本编辑器。 和 vim 编辑器相比&#xff0c;nano 编辑器就没有那么强大&am…

Unix I/O 模型及Java I/O 模型详解

在Unix Socket的输入操作中&#xff0c;可以将其分为以下几个阶段&#xff1a; 等待数据就绪(内核空间)&#xff1a; 在这个阶段&#xff0c;应用程序通过调用阻塞式的读取函数&#xff08;如recv&#xff09;或非阻塞式的读取函数&#xff08;如recv、recvfrom&#xff09;等待…

Opencv实战(1)读取与图像操作

Opencv 文章目录 Opencv一、读取图片1.imshow2.namedWindow3.imshow4.效果图 二、像素操作(1).访问像素1. at()2.Mat_ (2).遍历像素1.指针遍历2.迭代器遍历 (3).threshold(4).通道分离1.split2.merge (5)Gamma矫正 三、深浅拷贝 一、读取图片 1.imshow Mat imread(const stri…

数据库所在服务器磁盘满了怎么办?

大家好&#xff0c;我是G探险者。 给大家拜个晚年哈&#xff0c;节后上班第一天&#xff0c;打开电脑&#xff0c;发现数据库服务器连不上了。 幸亏&#xff0c;节后第一天上班的人不太多&#xff0c;领导还没来&#xff0c;我一番鼓捣解决了这个问题。 所以做个总结&#xff0…