Вы можете проверить мою интерактивную ДЕМО
Итак, в чем здесь логика?
Как только Angular встречает структурную директиву, он пытается ее проанализировать:
*dir="..."
/\
indicates that it's a structural directive
В начале есть 3 случая:
*dir="expr
\/
[dir]="expr"
*dir="let var // also var can have value
\/ // starts with keyword 'let', indicates variable
[dir] let-x="$impicit"
*dir="as var
\/ // starts with keyword 'as'
let-x="$impicit" // it won't fail but your directive won't be instantiated
После выражения вы можете использовать ключевое слово as
для определения входной переменной шаблона для этого выражения или разделитель, такой как пробел, двоеточие, точка с запятой или запятая:
*dir="expr as var
\/
[dir]="exp" let-var="dir"
*dir="expr[ ]
*dir="expr:
*dir="expr;
*dir="expr,
Обратите внимание, что dir
здесь рассматривается как первый ключ привязки шаблона.
Теперь пришло время для другого ключа или переменной:
*dir="expr key2
*dir="expr:key2
*dir="expr;key2
*dir="expr,key2
И мы можем присвоить значение этому ключу через пробел или точку с запятой:
*dir="expr key2 exp2
*dir="expr:key2 exp2
*dir="expr;key2 exp2
*dir="expr,key2 exp2
or
*dir="expr key2:exp2
И таким образом мы можем производить другие ключи. Эти ключи пишутся с заглавной буквы и соединяются с первым ключом.
*dir="expr key2 exp2 key3 exp3 ...
\/
[dir]="expr " [dirKey2]="exp2 " [dirKey3]="exp3"
let node; when: hasChild; otherKey: otherValue
\/ \/ \/
var key value
\/
dir [dirWhen]="hasChild" [dirOtherKey]="otherValue" let-node="$implicit"
*dir="let x of y; index = i; trackBy: f"
\/
dir [dirOf]="y" [dirIndex]="= i" [dirTrackBy]="f" let-x="$implicit"
*dir="let x of y; let index = i; trackBy: f"
\/ \/ \/ \/ \/ \/
var key value var key value
\/
dir [dirOf]="y" [dirTrackBy]="f" let-x="$implicit" let-index="i"
Как вы можете видеть, мы можем либо определить ключ-значение, либо установить входные переменные шаблона * от 1037 * до let
или как keywords
Если вы считаете, что Angular docs не полностью это объясняет, тогда вы можете следовать исходному коду
// Parses the AST for `<some-tag *tplKey=AST>`
parseTemplateBindings(tplKey: string): TemplateBindingParseResult {
let firstBinding = true;
const bindings: TemplateBinding[] = [];
const warnings: string[] = [];
do {
const start = this.inputIndex;
let rawKey: string;
let key: string;
let isVar: boolean = false;
if (firstBinding) {
rawKey = key = tplKey;
firstBinding = false;
} else {
isVar = this.peekKeywordLet();
if (isVar) this.advance();
rawKey = this.expectTemplateBindingKey();
key = isVar ? rawKey : tplKey + rawKey[0].toUpperCase() + rawKey.substring(1);
this.optionalCharacter(chars.$COLON);
}
let name: string = null !;
let expression: ASTWithSource|null = null;
if (isVar) {
if (this.optionalOperator('=')) {
name = this.expectTemplateBindingKey();
} else {
name = '\$implicit';
}
} else if (this.peekKeywordAs()) {
this.advance(); // consume `as`
name = rawKey;
key = this.expectTemplateBindingKey(); // read local var name
isVar = true;
} else if (this.next !== EOF && !this.peekKeywordLet()) {
const start = this.inputIndex;
const ast = this.parsePipe();
const source = this.input.substring(start - this.offset, this.inputIndex - this.offset);
expression = new ASTWithSource(ast, source, this.location, this.errors);
}
bindings.push(new TemplateBinding(this.span(start), key, isVar, name, expression));
if (this.peekKeywordAs() && !isVar) {
const letStart = this.inputIndex;
this.advance(); // consume `as`
const letName = this.expectTemplateBindingKey(); // read local var name
bindings.push(new TemplateBinding(this.span(letStart), letName, true, key, null !));
}
if (!this.optionalCharacter(chars.$SEMICOLON)) {
this.optionalCharacter(chars.$COMMA);
}
} while (this.index < this.tokens.length);
return new TemplateBindingParseResult(bindings, warnings, this.errors);
}
Приведенный выше код описывает алгоритм синтаксического анализа структурной директивы.