如何在视图外评估 Aurelia 插值表达式?
How to evaluate an Aurelia interpolation expression outside a view?
在 Aurelia 中,假设我有一个包含插值表达式 "Today at ${value | date: 'time'}"
的字符串和一些表示此 { value: new Date() }
的绑定上下文的对象。
有什么方法可以在视图之外获取该字符串和该对象,并获得结果格式化字符串,即 "Today at 13:44"
?
我查看了 tests,但它们都涉及创建一个 HTML 元素、绑定,然后解除绑定 - 我想知道所有这些的性能开销是多少,以及是否有更简单的方法来实现这一目标吗?如果有一种轻量级的方法来根据上下文对象评估这样的字符串,而无需设置和拆除绑定等,那将是非常棒的。
举个例子:https://gist.run?id=a12470f6e9f7e6a605b3dd002033fdc7
表达式-evaluator.js
import {inject} from 'aurelia-dependency-injection';
import {ViewResources} from 'aurelia-templating';
import {Parser, createOverrideContext} from 'aurelia-binding';
@inject(Parser, ViewResources)
export class ExpressionEvaluator {
constructor(parser, resources) {
this.parser = parser;
this.lookupFunctions = resources.lookupFunctions;
}
evaluate(expressionText, bindingContext) {
const expression = this.parser.parse(expressionText);
const scope = {
bindingContext,
overrideContext: createOverrideContext(bindingContext)
};
return expression.evaluate(scope, this.lookupFunctions);
}
}
app.js
import {inject} from 'aurelia-dependency-injection';
import {ExpressionEvaluator} from './expression-evaluator';
@inject(ExpressionEvaluator)
export class App {
message = 'Hello World!';
constructor(evaluator) {
this.message = evaluator.evaluate('foo.bar.baz | test', { foo: { bar: { baz: 'it works' } } });
}
}
编辑
我错过了您需要解析 interpolation 表达式而不是正则绑定表达式的事实...
aurelia-validation 中有一个这样的例子:https://github.com/aurelia/validation/blob/master/src/implementation/validation-message-parser.ts
感谢 Jeremy 的回答,这成为我们最终的解决方案:
import { autoinject, BindingLanguage, Expression, ViewResources, createOverrideContext } from "aurelia-framework";
// Represents the sequence of static and dynamic parts resulting from parsing a text.
type TemplateStringParts = (Expression | string)[];
// Cache containing parsed template string parts.
const cache = new Map<string, TemplateStringParts>();
/**
* Represents an interpolation expression, such as "The price is ${price | currency}",
* which when evaluated against a binding context results in a formatted string,
* such as "The price is 42 USD".
*/
@autoinject
export class TemplateString
{
private text: string;
private viewResources: ViewResources;
private bindingLanguage: BindingLanguage;
/**
* Creates a new instance of the TemplateString type.
* @param text The text representing the interpolation expression.
* @param viewResources The view resources to use when evaluating the interpolation expression.
* @param bindingLanguage The BindingLanguage instance.
*/
public constructor(text: string, viewResources: ViewResources, bindingLanguage: BindingLanguage)
{
this.text = text;
this.viewResources = viewResources;
this.bindingLanguage = bindingLanguage;
}
/**
* Evaluates the interpolation expression against the specified context.
* @param bindingContext The context against which expressions should be evaluated.
* @param overrideContext The override context against which expressions should be evaluated.
* @returns The string resulting from evaluating the interpolation expression.
*/
public evaluate(bindingContext?: any, overrideContext?: any): string
{
let parts = cache.get(this.text);
if (parts == null)
{
parts = (this.bindingLanguage as any).parseInterpolation(null, this.text) || [this.text];
cache.set(this.text, parts);
}
const scope =
{
bindingContext: bindingContext || {},
overrideContext: overrideContext || createOverrideContext(bindingContext)
};
const lookupFunctions = (this.viewResources as any).lookupFunctions;
return parts.map(e => e instanceof Expression ? e.evaluate(scope, lookupFunctions) : e).join("");
}
/**
* Gets the string representation of this template string.
* @returns The string from which the template string was created.
*/
public toString(): string
{
return this.text;
}
}
/**
* Represents a parser that parses strings representing interpolation expressions,
* such as "The price is ${price | currency}".
*/
@autoinject
export class TemplateStringParser
{
private resources: ViewResources;
private bindingLanguage: BindingLanguage;
/**
* Creates a new instance of the TemplateStringParser type.
* @param resources The view resources to use when evaluating expressions.
* @param bindingLanguage The BindingLanguage instance.
*/
public constructor(resources: ViewResources, bindingLanguage: BindingLanguage)
{
this.resources = resources;
this.bindingLanguage = bindingLanguage;
}
/**
* Parses the specified text as an interpolation expression.
* @param text The text representing the interpolation expression.
* @returns A TemplateString instance representing the interpolation expression.
*/
public parse(text: string): TemplateString
{
return new TemplateString(text, this.resources, this.bindingLanguage);
}
}
要在视图模型中使用它,只需注入 TemplateStringParser
并使用它创建一个 TemplateString
实例,然后可以根据上下文对象对其进行评估。
在 Aurelia 中,假设我有一个包含插值表达式 "Today at ${value | date: 'time'}"
的字符串和一些表示此 { value: new Date() }
的绑定上下文的对象。
有什么方法可以在视图之外获取该字符串和该对象,并获得结果格式化字符串,即 "Today at 13:44"
?
我查看了 tests,但它们都涉及创建一个 HTML 元素、绑定,然后解除绑定 - 我想知道所有这些的性能开销是多少,以及是否有更简单的方法来实现这一目标吗?如果有一种轻量级的方法来根据上下文对象评估这样的字符串,而无需设置和拆除绑定等,那将是非常棒的。
举个例子:https://gist.run?id=a12470f6e9f7e6a605b3dd002033fdc7
表达式-evaluator.js
import {inject} from 'aurelia-dependency-injection';
import {ViewResources} from 'aurelia-templating';
import {Parser, createOverrideContext} from 'aurelia-binding';
@inject(Parser, ViewResources)
export class ExpressionEvaluator {
constructor(parser, resources) {
this.parser = parser;
this.lookupFunctions = resources.lookupFunctions;
}
evaluate(expressionText, bindingContext) {
const expression = this.parser.parse(expressionText);
const scope = {
bindingContext,
overrideContext: createOverrideContext(bindingContext)
};
return expression.evaluate(scope, this.lookupFunctions);
}
}
app.js
import {inject} from 'aurelia-dependency-injection';
import {ExpressionEvaluator} from './expression-evaluator';
@inject(ExpressionEvaluator)
export class App {
message = 'Hello World!';
constructor(evaluator) {
this.message = evaluator.evaluate('foo.bar.baz | test', { foo: { bar: { baz: 'it works' } } });
}
}
编辑
我错过了您需要解析 interpolation 表达式而不是正则绑定表达式的事实...
aurelia-validation 中有一个这样的例子:https://github.com/aurelia/validation/blob/master/src/implementation/validation-message-parser.ts
感谢 Jeremy 的回答,这成为我们最终的解决方案:
import { autoinject, BindingLanguage, Expression, ViewResources, createOverrideContext } from "aurelia-framework";
// Represents the sequence of static and dynamic parts resulting from parsing a text.
type TemplateStringParts = (Expression | string)[];
// Cache containing parsed template string parts.
const cache = new Map<string, TemplateStringParts>();
/**
* Represents an interpolation expression, such as "The price is ${price | currency}",
* which when evaluated against a binding context results in a formatted string,
* such as "The price is 42 USD".
*/
@autoinject
export class TemplateString
{
private text: string;
private viewResources: ViewResources;
private bindingLanguage: BindingLanguage;
/**
* Creates a new instance of the TemplateString type.
* @param text The text representing the interpolation expression.
* @param viewResources The view resources to use when evaluating the interpolation expression.
* @param bindingLanguage The BindingLanguage instance.
*/
public constructor(text: string, viewResources: ViewResources, bindingLanguage: BindingLanguage)
{
this.text = text;
this.viewResources = viewResources;
this.bindingLanguage = bindingLanguage;
}
/**
* Evaluates the interpolation expression against the specified context.
* @param bindingContext The context against which expressions should be evaluated.
* @param overrideContext The override context against which expressions should be evaluated.
* @returns The string resulting from evaluating the interpolation expression.
*/
public evaluate(bindingContext?: any, overrideContext?: any): string
{
let parts = cache.get(this.text);
if (parts == null)
{
parts = (this.bindingLanguage as any).parseInterpolation(null, this.text) || [this.text];
cache.set(this.text, parts);
}
const scope =
{
bindingContext: bindingContext || {},
overrideContext: overrideContext || createOverrideContext(bindingContext)
};
const lookupFunctions = (this.viewResources as any).lookupFunctions;
return parts.map(e => e instanceof Expression ? e.evaluate(scope, lookupFunctions) : e).join("");
}
/**
* Gets the string representation of this template string.
* @returns The string from which the template string was created.
*/
public toString(): string
{
return this.text;
}
}
/**
* Represents a parser that parses strings representing interpolation expressions,
* such as "The price is ${price | currency}".
*/
@autoinject
export class TemplateStringParser
{
private resources: ViewResources;
private bindingLanguage: BindingLanguage;
/**
* Creates a new instance of the TemplateStringParser type.
* @param resources The view resources to use when evaluating expressions.
* @param bindingLanguage The BindingLanguage instance.
*/
public constructor(resources: ViewResources, bindingLanguage: BindingLanguage)
{
this.resources = resources;
this.bindingLanguage = bindingLanguage;
}
/**
* Parses the specified text as an interpolation expression.
* @param text The text representing the interpolation expression.
* @returns A TemplateString instance representing the interpolation expression.
*/
public parse(text: string): TemplateString
{
return new TemplateString(text, this.resources, this.bindingLanguage);
}
}
要在视图模型中使用它,只需注入 TemplateStringParser
并使用它创建一个 TemplateString
实例,然后可以根据上下文对象对其进行评估。