[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 确认投射完成后做一些对应操作

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记一次有趣的逻辑漏洞挖洞经历

前言 前几天在网上冲浪的时候无意间看到了一个Edu的站点&#xff0c;是一个很常见的类似MOOC的那种在线学习系统&#xff0c;对外开放&#xff0c;同时有注册和登录功能。对于我这种常年低危的菜鸡来说&#xff0c;这是最愿意看到的&#xff0c;因为一个Web网站有了登录功能&a…

第2讲springsecurity+vue通用权限系统

阿里云 maven阿里云镜像 <?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for addition…

数据记笔记:USGS 查看上世纪卫星图

1 先到USGS EarthExplorer 界面&#xff0c;在address 处选择需要的城市/也可以在底下polygon处手动标出需要研究的区域 2&#xff0c;点击show&#xff0c;就会出找到的对应的区域&#xff0c;点击这个区域&#xff0c;polygon处就会有响应了。然后选择date range 3 点击下方的…

AMD FPGA设计优化宝典笔记(4)复位桥

高亚军老师的这本书《AMD FPGA设计优化宝典》&#xff0c;他主要讲了两个东西&#xff1a; 第一个东西是代码的良好风格&#xff1b; 第二个是设计收敛等的本质。 这个书的结构是一个总论&#xff0c;加上另外的9个优化&#xff0c;包含的有&#xff1a;时钟网络、组合逻辑、触…

VS中设置#define _CRT_SECURE_NO_WARNINGS的原因和设置方式

原因&#xff1a; 在编译老的用C语言的开源项目的时候&#xff0c;可能因为一些老的.c文件使用了strcpy,scanf等不安全的函数&#xff0c;而报警告和错误&#xff0c;而导致无法编译通过。 解决方案&#xff1a; 我们有两种解决方案&#xff1a; 1、在指定的源文件的开头定…

跟着pink老师前端入门教程(JavaScript)-day02

三、变量 &#xff08;一&#xff09;变量概述 1、什么是变量 白话&#xff1a;变量就是一个装东西的盒子 通俗&#xff1a;变量是用于存放数据的容器&#xff0c;通过变量名获取数据&#xff0c;甚至数据可以修改 2、变量在内存中的存储 本质&#xff1a;变量是程序在内存…

你的电脑关机吗

目录 程序员为什么不喜欢关电脑&#xff1f; 电脑长时间不关机会怎样? 电脑卡顿 中度风险 硬件损耗 能源浪费 散热问题 软件问题 网络安全问题 程序员为什么不喜欢关电脑&#xff1f; 大部分人都会选择将电脑进行关机操作。其实这不难理解&#xff0c;毕竟人类都需要…

Linux_线程

线程与进程 多级页表 线程控制 线程互斥 线程同步 生产者消费者模型 常见概念 下面选取32位系统举例。 一.线程与进程 上图是曾经我们认为进程所占用的资源的集合。 1.1 线程概念 线程是一个执行分支&#xff0c;执行粒度比进程细&#xff0c;调度成本比进程低线程是cpu…

vue-ESlint (六)

代码规范 代码规范&#xff1a;一套写代码的约定规则。例如&#xff1a;"赋值符号的左右是否需要空格" "一句结束是否是要加;" . 老话说&#xff1a;"没有规矩不成方圆" → 正规的团队 需要 统一的编码风格 JavaScript Standard Style 规范说…

Cocos2dx-lua ScrollView[一]基础篇

一.ScrollView概述 cocos游戏中ScrollView控件大量使用,95%以上的项目都会使用ScrollView,个别游戏可能全部使用翻页的滑动效果。如果想要精通Cocos的UI开发,精通ScrollView控件非常关键,因此对ScrollView的使用进行总结很有必要。 下文缩写说明:sv = ScrollView, item代…

.NET Core WebAPI中使用swagger版本控制,添加注释

一、效果 二、实现步骤 在代码中添加注释 在项目属性中生成API文档 在Program中注册Swagger服务并配置文档信息 // 添加swagger注释 builder.Services.AddSwaggerGen(x > {x.SwaggerDoc("v1", new OpenApiInfo { Title "Swagger标题", Version "…

Unity中关于ScrollRect组件完整解决方案(ScrollRect中元素自动排版+ScrollRect中元素自动定位到Viewport可见范围内)

一、元素自动排版功能 1、首先要往我们的unity项目中导入两个脚本文件&#xff0c;脚本文件名称分别是UIScrollEventListener和CZScrollRect&#xff0c;这两个脚本文件代码如下所示。 1-1、介绍UIScrollEventListener脚本写法。 using System.Collections; using System.Co…

比特币突然大涨

作者&#xff1a;秦晋 2月9日&#xff0c;除夕夜&#xff0c;比特币突然大涨&#xff0c;最高涨至48219美元&#xff0c;涨幅超6%。据CNBC报道&#xff0c;本周比特币已经上涨10.76%&#xff0c;创下自12月8日以来的最佳的一周。本周ETH上涨8.46%&#xff0c;成为自1月12日以来…

SpringBoot+Tess4J实现本地与远程图片的文字识别

Spring Boot应用程序里集成Tess4J来实现OCR&#xff08;光学字符识别&#xff09;&#xff0c;以识别出本地和远程图片中的文字 一、添加依赖 <dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><vers…

MongoDB数据库又被勒索攻击了

前言 朋友发来一张图片&#xff0c;说MongoDB数据库被勒索了&#xff0c;问我是哪个家族的...... &#xff08;上图来源于网络)&#xff0c;当笔者看到朋友发的图片之后&#xff0c;判断应该是黑客入侵了MongoDB数据库服务器&#xff0c;然后删除了数据库里面的数据&#xff0…

Sora 文生视频提示词实例集 2

Prompt: Historical footage of California during the gold rush. 加利福尼亚淘金热期间的历史影像。 Prompt: A close up view of a glass sphere that has a zen garden within it. There is a small dwarf in the sphere who is raking the zen garden and creating patter…

C#,二进制数的非0位数统计(Bits Count)的算法与源代码

计算一个十进制数的二进制表示有多少位1&#xff1f; 1 遍历法&#xff08;递归或非递归&#xff09; 使用循环按位统计1的个数。 2 哈希查表法 利用一个数组或哈希生成一张表&#xff0c;存储不同二进制编码对应的值为1的二进制位数&#xff0c;那么在使用时&#xff0c;只…

Stable Diffusion教程——使用TensorRT GPU加速提升Stable Diffusion出图速度

概述 Diffusion 模型在生成图像时最大的瓶颈是速度过慢的问题。为了解决这个问题&#xff0c;Stable Diffusion 采用了多种方式来加速图像生成&#xff0c;使得实时图像生成成为可能。最核心的加速是Stable Diffusion 使用了编码器将图像从原始的 3512512 大小转换为更小的 46…

美国突然致敬中本聪

作者&#xff1a;秦晋 有点看不懂美国的神操作。 2月16日&#xff0c;据《Bitcoin Magazine》报道&#xff0c;比特币的竞争对手、美国参议员伊丽莎白-沃伦对比特币的立场突然180度大转弯。由反对立场转为支持立场。让很多行业媒体出乎意料&#xff0c;甚至惊掉下巴。 报道称&a…

重塑高校评价体系,缓解内卷,培养有远见的研究者

重塑高校评价体系&#xff0c;缓解内卷&#xff0c;培养有远见的研究者 摘要&#xff1a;当前高等教育和科研环境中普遍存在的“非升即走”制度&#xff0c;尽管表面上看似激励科研人员努力工作&#xff0c;但实际上反映了学术界的内卷状况。这一制度的设置在人才供过于求的背景…