Angularjs源码分析:$interpolate
一、首先抛出两个问题问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成 二、$interpolate的功能$interpolate是一个angular的内部服务,专门给$compile(等把$compile所依赖的服务讲完,我们就会分析$compile的代码了)调用的,而他的作业也比较简单:就是重字符中绑定的数据给解析出来。其中,它本身只完成获取数据表达式,表达式的解析将交给$parse服务来完成。 三、源代码1.$InterpolateProvider提供修改绑定数据时用的插入标记(interpolation markup)的能力var startSymbol = '{{';
var endSymbol = '}}';
this.startSymbol = function(value) {
if (value) {
startSymbol = value;
return this;
} else {
return startSymbol;
}
};
this.endSymbol = function(value) {
if (value) {
endSymbol = value;
return this;//如果设置成功,返回对象的引用,提供优雅的链式书写能力
} else {
return endSymbol;
}
};
解决第一个问题,我们可以通过在模块的配置代码中写入 2.插入标记被用来表示了绑定数据的开始和结束,那么,我们怎么来表示他们本身呢。请看下面的代码,初次看的时候,这里的代码有些难懂。 var escapedStartRegexp = new RegExp(startSymbol.replace(/./g,escape),'g'),//startSymbol.replace(/./g,escape)会给startSymbol插入三个反斜杠
escapedEndRegexp = new RegExp(endSymbol.replace(/./g,'g');
function escape(ch) {
return '\' + ch;//因为转义的原因,ch前面的字符将是三个反斜杠符号
}
function unescapeText(text) {
return text.replace(escapedStartRegexp,startSymbol).
replace(escapedEndRegexp,endSymbol);
}
假设插入标记就是默认的 3.从字符串中解出表达式function $interpolate(text,mustHaveExpression,trustedContext,allOrNothing) {
allOrNothing = !!allOrNothing;
var startIndex,endIndex,index = 0,expressions = [],parseFns = [],textLength = text.length,exp,concat = [],expressionPositions = [];
while (index < textLength) {
if (((startIndex = text.indexOf(startSymbol,index)) != -1) &&
((endIndex = text.indexOf(endSymbol,startIndex + startSymbolLength)) != -1)) {
if (index !== startIndex) {
concat.push(unescapeText(text.substring(index,startIndex)));
}
exp = text.substring(startIndex + startSymbolLength,endIndex);
expressions.push(exp);
parseFns.push($parse(exp,parseStringifyInterceptor));
index = endIndex + endSymbolLength;
expressionPositions.push(concat.length);
concat.push('');
} else {
// we did not find an interpolation,so we have to add the remainder to the separators array
if (index !== textLength) {
concat.push(unescapeText(text.substring(index)));
}
break;
}
}
...
从上面的代码实现来看,作者还是没有采用效率比较的低的正则表达式来完成表达式的识别。上面的代码完成的功能是将字符串分组(压入concat数组),分组的边界时表达式插入符,表达式本身用空格占位,表达式本则压入另一个数据(parseFns),并且记录下表达式在concat的位置。这里看到表达式的解析依然是调用的$parse服务。 4.$interpolate最终返回的是什么?if (trustedContext && concat.length > 1) {
$interpolateMinErr.throwNoconcat(text);
}
if (!mustHaveExpression || expressions.length) {
var compute = function(values) { //计算表达式值,并且拼接为字符串
for (var i = 0,ii = expressions.length; i < ii; i++) {
if (allOrNothing && isUndefined(values[i])) return;
concat[expressionPositions[i]] = values[i];
}
return concat.join('');
};
var getValue = function(value) { //获取值
return trustedContext ?
$sce.getTrusted(trustedContext,value) : //利用$sce进行检查
$sce.valueOf(value);
};
return extend(function interpolationFn(context) {
var i = 0;
var ii = expressions.length;
var values = new Array(ii);
try {
for (; i < ii; i++) {
values[i] = parseFns[i](context);
}
return compute(values);
} catch (err) {
$exceptionHandler($interpolateMinErr.interr(text,err));
}
},{
// all of these properties are undocumented for now
exp: text,//just for compatibility with regular watchers created via $watch
expressions: expressions,$$watchDelegate: function(scope,listener) { //监听的代理,通过Scope.$watchGroup对text中的所有表达式进行监听
var lastValue;
return scope.$watchGroup(parseFns,function interpolateFnWatcher(values,oldValues) {
var currValue = compute(values);
if (isFunction(listener)) {
listener.call(this,currValue,values !== oldValues ? lastValue : currValue,scope);
}
lastValue = currValue;
});
}
});
}
function parseStringifyInterceptor(value) {
try {
value = getValue(value);
return allOrNothing && !isDefined(value) ? value : stringify(value);
} catch (err) {
$exceptionHandler($interpolateMinErr.interr(text,err));
}
}
}
$interpolate将返回一个函数,这个函数能够获取到text被解析后的值。这个函数并且绑定了exp,expressions和$$watchDelegate三个属性。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
