angular11源码探索二[Renderer2]
其实我通过这段时间的深入学习,已经写到第6,7篇的,每天晚上都熬夜很晚,我发现了angular的宝贵东西,也慢慢明白了这个好东西,由于第一篇个人写的质量比较高,后面写的质量不高,感觉有点初级,一直没发,自己也开始迷茫了,研究源码的目标是为了什么,啃源码是一个很迷茫很打击自信有挑战性的东西,需要要一堆迷迷糊糊的东西去理解本质,加上前面几个月没怎么深入angular导致很多东西也忘记了,自己也是抱着一个初学者的态度去探究源码,已经编写的质量一直达不到自己的要求,但是我编写的一些东西,都是抱着初学者的态度去理解的,对于解决问题和从实际问题去理解angular还是有很大帮助的
技术成长分为三个阶段:
第一阶段:化难为易
第二阶段:由易变难
第三阶段:分割难易
自己的编写的时候是不是应该先做个第一阶段的事,理解怎么能全面的去,精通这个api,官网上面的介绍,说实例有点浅,自己能不能做到,遇到这个api基本能理解全部的方法,相信自己能编写20篇过后的质量可能有明显的提高,所以急不来,慢慢来,别过于抱着目的性去弄,有时候遇到太难的问题,容易导致心态崩溃,可以跟以前一样,从源码的基础上去啃透这个api,希望未来的自己能变得更强,学东西还是尽量让自己变得更加自信...
Renderer2
<div data="[1,2,3]" #apps>121212</div>
export class UserComponent implements OnInit ,AfterViewInit{
@ViewChild('apps') ages:ElementRef;
constructor(private kvDiffers: KeyValueDiffers, private http: HttpClient,private renderer:Renderer2) {}
ngAfterViewInit() {
// 创建dom
let app = this.renderer.createElement('div');
// 创建文本
let text = this.renderer.createText('大帅比');
// 创建注释
let com=this.renderer.createComment('我是注释')
//添加创建的dom
this.renderer.appendChild(this.ages.nativeElement,app)
//添加创建的文字
this.renderer.appendChild(this.ages.nativeElement,text)
this.renderer.appendChild(this.ages.nativeElement,com)
}
}
insertBefore
this.renderer.insertBefore(父节点,要添加的子节点newChild,现节点前面添加newChild,isMove:boolean 是否触发动画)
removeChild
this.renderer.removeChild(父节点,删除的子节点,)
删除所有子节点
const childElements = this.el.nativeElement.children;
for (let child of childElements) {
this.renderer.removeChild(this.el.nativeElement, child);
}
源码地址
\packages\platform-browser\src\dom\dom_renderer.ts
createElement
export const NAMESPACE_URIS: {[ns: string]: string} = {
'svg': 'http://www.w3.org/2000/svg',
'xhtml': 'http://www.w3.org/1999/xhtml',
'xlink': 'http://www.w3.org/1999/xlink',
'xml': 'http://www.w3.org/XML/1998/namespace',
'xmlns': 'http://www.w3.org/2000/xmlns/',
};
createElement(name: string, namespace?: string): any {
if (namespace) {
// 命名空间,个人觉得没多大用处
return document.createElementNS(NAMESPACE_URIS[namespace] || namespace, name);
}
return document.createElement(name);
}
// 创建文本
createText(value: string): any {
return document.createTextNode(value);
}
// 添加dom ,父节点 子节点
appendChild(parent: any, newChild: any): void {
parent.appendChild(newChild);
}
// 插入节点, 父节点 新的子节点 现有的前面插入(新的子节点)
insertBefore(parent: any, newChild: any, refChild: any): void {
if (parent) {
parent.insertBefore(newChild, refChild);
}
}
// 父节点直接删除子节点
removeChild(parent: any, oldChild: any): void {
if (parent) {
parent.removeChild(oldChild);
}
}
// 卧槽竟然原生里面可以创造出,注释
createComment(value: string): any {
return document.createComment(value);
}
剩下的几个属性
//父节点
parentNode(node: any): any {
return node.parentNode;
}
// 下一个兄弟节点
nextSibling(node: any): any {
return node.nextSibling;
}
// 设置
setAttribute(el: any, name: string, value: string, namespace?: string): void {
// 有命令空间
if (namespace) {
...
} else {
el.setAttribute(name, value);
}
}
// 删除属性
removeAttribute(el: any, name: string, namespace?: string): void {
// 有命令空间的删去
if (namespace) {
...
} else {
el.removeAttribute(name);
}
}
// 添加class
addClass(el: any, name: string): void {
el.classList.add(name);
}
// 删除class
removeClass(el: any, name: string): void {
el.classList.remove(name);
}
export enum RendererStyleFlags2 {
Important = 1 << 0,
// 1
DashCase = 1 << 1
// 2
}
setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void {
if (flags & (RendererStyleFlags2.DashCase | RendererStyleFlags2.Important)) {
el.style.setProperty(style, value, flags & RendererStyleFlags2.Important ? 'important' : '');
} else {
el.style[style] = value;
}
}
removeStyle(el: any, style: string, flags: RendererStyleFlags2): void {
if (flags & RendererStyleFlags2.DashCase) {
el.style.removeProperty(style);
} else {
// IE 情况下 null为删除样式
el.style[style] = '';
}
}
第四个参数是可选参数,默认是添加优先级
this.renderer.setStyle(a,'background','red',1) //添加优先级,2是取消优先级
也可以使用枚举的形式
this.renderer.setStyle(a,'background','red',RendererStyleFlags2.Important)
也可以直接在第三个参数上添加
this.renderer.setStyle(a,'background','red!important')
setProperty
修改内置属性
// 摇摆树的内容暂时不太懂
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
setProperty(el: any, name: string, value: any): void {
NG_DEV_MODE && checkNoSyntheticProp(name, 'property');
el[name] = value;
}
const AT_CHARCODE = (() => '@'.charCodeAt(0))();
const AT_CHARCODE = '@'.charCodeAt(0);
// 思考这两种写法有什么区别...
function checkNoSyntheticProp(name: string, nameKind: string) {
if (name.charCodeAt(0) === AT_CHARCODE) {
throw new Error(`Found the synthetic ${nameKind} ${
name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`);
}
}
属性name第一个参数不能是
@
this.renderer.setProperty(a,'type','button') // 修改input的type类型
setValue
setValue(node: any, value: string): void {
node.nodeValue = value;
}
let a = document.querySelector('#bbb');
a.childNodes[0].nodeValue='bbb'
nodeValue 文本节点
childNodes 子节点合集
nodeName 节点名称 大写的 DIV
或者其他标签
nodeType 节点类型
- 元素节点 1
- 属性节点 2
- 文本节点 3
- 注释节点 8
案例
<div id="bbb">
dddd
</div>
要有文本节点才能添加
let a = document.querySelector('#bbb');
this.renderer.setValue( a.childNodes[0],'eeee')
listen
用法
let a = document.querySelector('#bbb');
this.renderer.listen(a,'click',e=>{
console.log(e);
})
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬