铁人赛最後一天!
今天要跟各位分享的呢,是昨天与前天 Banana in a box 系列的延伸,关於 Angular 怎麽处理 event 与 property binding。
因为是延伸的内容,所以我会继续以昨天的程序码作为范例!
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineComponent"]({
// ... 略
consts: [[3, "sliderValue", "sliderValueChange"]],
template: function AppComponent_Template(rf, ctx) {
if (rf & 1) {
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](
0,
"app-slider-wrapper",
0
);
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵlistener"](
"sliderValueChange",
function AppComponent_Template_app_slider_wrapper_sliderValueChange_0_listener(
$event
) {
return (ctx.slider = $event);
}
);
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](1, "div");
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](2, "label");
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtext"](3, "Slider value: ");
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementStart"](4, "label");
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtext"](5);
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelementEnd"]();
}
if (rf & 2) {
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵproperty"](
"sliderValue",
ctx.slider
);
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵadvance"](5);
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵtextInterpolate"](
ctx.slider
);
}
}
});
↑ Block 1
首先从编译後的程序码可以看到有 ɵɵlistener
这个 instruction,而这个 instruction 的实作内容如下:
export function ɵɵlistener(
eventName: string,
listenerFn: (e?: any) => any,
useCapture = false,
eventTargetResolver?: GlobalTargetResolver
): typeof ɵɵlistener {
const lView = getLView();
const tView = getTView();
const tNode = getCurrentTNode()!;
listenerInternal(
tView,
lView,
lView[RENDERER],
tNode,
eventName,
listenerFn,
useCapture,
eventTargetResolver
);
return ɵɵlistener;
}
↑ Block 2
ɵɵlistener 传入的参数除了 eventName(本例是 sliderValueChange)、listenerFn 之外,还可以传入 useCapture 与 eventTargetResolver,後两者除非是有特殊需求,否则不会用到。
将 eventName 与 listenerFn 传入之後 Angular 会透过 getLView
、getTView
、getCurrentTNode
方法来取得当前的 LView、TView 与 TNode。
最後则是呼叫 listenerInternal
函式(Link)并将相关的资讯传递给它,来做以下的事:
ObjectOrientedRenderer3
还是 ProceduralRenderer3
,不同的 renderer 会有不同的处理方式。Angular 会在 update block 的时候呼叫 ɵɵproperty instruction 来处理 property 相关的事情,以下是它的实作内容(Link):
export function ɵɵproperty<T>(
propName: string, value: T, sanitizer?: SanitizerFn|null): typeof ɵɵproperty {
const lView = getLView();
const bindingIndex = nextBindingIndex();
if (bindingUpdated(lView, bindingIndex, value)) {
const tView = getTView();
const tNode = getSelectedTNode();
elementPropertyInternal(
tView, tNode, lView, propName, value, lView[RENDERER], sanitizer, false);
ngDevMode && storePropertyBindingMetadata(tView.data, tNode, propName, bindingIndex);
}
return ɵɵproperty;
}
↑ Block 3
ɵɵproperty 在执行更新的操作之前,会先透过 bindingUpdated
函式来确认传入的值跟先前在 lView 内纪录的值是否相同,如果有变动的话才会执行 elementPropertyInternal 函式来更新 property,否则的话就直接回传 ɵɵproperty instruction,让 Angular 可以透过 ɵɵproperty('a', 'v1')('b', 'v2') 这样的方法来设定 property binding。
以上就是今天的「你可以不用知道的 Angular」!简洁扼要的说明了 Angular 是怎麽实作 event binding 与 property binding。
30 天,有够累。
主要是因为自己筹备期间因为刚开始翻阅 Angular 原始码,艰涩难懂到让我一直发懒,所以直到正式开赛前一天才觉得应该拟定每天的内容,接着就开始了每天绞尽脑汁产出一篇的生活。其中有几篇真的是困难重重,像是最开头的 Dependency Injection 系列,那个原始码我真的是迟迟无法参悟阿……
总之感谢各位读者这 30 天的陪伴,因为比赛时间限制,所以我做了一些艰难的抉择,像是不小心忽略部分说明之类的。
发布在铁人赛的这系列未来不会有其他更新,但我会在个人的 Medium(这里)逐步将内容完善!热烈欢迎有兴趣的读者跟我一起转移阵地噢!
再次感谢!
<<: Day 30 - 使用 CDK 创建 Open Unlight 游戏
>>: [DAY-30] 最後一幕只是故事的结尾,你也知道故事没有结尾是行不通的。
作为物理模拟开场的第一进程,当然就要来讲一下最经典的物理模拟案例:『弹跳球』~ 其实很多国外的Can...
上一篇,我们学到了如何用CSS选取HTML物件,但我们只选取了HTML物件,而没有改变HTML物件的...
今天介绍步进马达,疑?昨天不是才说过马达吗?昨天的是伺服马达,今天的则是伺服马达 这两者有甚麽不一样...
前言 以为很顺畅的,结果发现Python 3.9无法支援,那就只好用3.8罗!因为采了不小的雷,因此...
在大大们的留言下 好心告诉我在哪边 我终於找到了 原来还要特别去永丰的网站填资料申请才会寄到信箱 今...