【发布时间】:2012-11-14 17:01:25
【问题描述】:
我对 IE8 有一个奇怪的问题,如果我尝试通过 AngularJS 的双向数据绑定在模板中呈现 $scope 变量,它不会用正确的值替换 {{child.name}}。这肯定与以下过滤器的低效率有关:
filter('truncate', function() {
return function(name) {
// It's just easier to use jQuery here
var windowWidth = $(window).width(),
nameElement = $('a:contains("' + name + '")'),
truncPnt = Math.floor(name.length * 0.9);
while (nameElement.width() > windowWidth * 0.75 && truncPnt > 6) {
truncPnt = Math.floor(truncPnt * 0.9);
name = name.substring(0, truncPnt);
nameElement.text(name + ' ...');
}
return name;
}
});
然后我将此过滤器与ng-repeat 一起使用:
<a class="entity-name" href="{{child.url}}" title="{{child.name}}" ng-cloak>{{child.name|truncate}}</a>
总体目标是根据屏幕宽度将传入过滤器的变量截断,用“...”替换任何截断的字符。我相当有信心这个过滤器是原因,因为我有一个类似的函数在$(window) 处理程序的.resize() 上调用,如果我要使用 IE8,并调整浏览器窗口的大小,它会导致 @987654328 @ 渲染为正确的值,但前提是我调整浏览器的大小。
更新:
所以我已经摆脱了上面的过滤器,并用一个非常相似的指令代替了它。这是我第一次尝试创建自定义指令,所以我相当肯定它可以做得更好,减去我目前似乎无法解决的明显缺陷。指令如下:
.directive('truncate', function() {
return {
restrict: 'A',
replace: true,
template: '<a class="entity-name" href="{{child.url}}" title="{{child.name}}">{{child.display}}</a>',
link: function(scope, element, attr) {
var widthThreshold = $(element[0]).parent().parent().width() * 0.85;
scope.$watch('child', function(val) {
var elementWidth = $(element[0]).width(),
characterCount = scope.child.name.length;
while ($(element[0]).width() > widthThreshold || characterCount > 5) {
characterCount--;
scope.child.display = scope.child.name.substring(0, characterCount) + ' ...';
}
});
}
}
});
我将部分替换为简单:
<a truncate="child"></a>
这与过滤器的区别如下(减去明显的过滤器与指令):
- 将
windowWidth替换为widthThreshold,通过将jQuery 的.parent()链接两次来识别值(本质上,当获取父(x2) 元素而不是窗口的宽度时,它的值更准确)。 - 向
child添加了一个名为display的附加密钥。这将是用于显示的child.name的截断版本,而不是使用 jQuery 的.text()并仅使用截断的child.name进行渲染。 -
truncPnt变为characterCount(尽量记住不要缩写变量)
现在的问题是 jQuery 冻结了浏览器,直到我终止了 javascript(如果出现提示)。 Firefox 可能会显示它,Chrome 还没有挂起,虽然我还没有在 IE 中进行测试,但我想比前者更糟糕。
可以做些什么来正确地获取两个父元素上方的值,并截断child.display 使其不会包裹/延伸到父 div 之外?
更新 2:
我决定放弃主要基于 DOM 的计算的想法,转而使用数学,考虑父 div 的宽度、字体大小和天知道的比例。我认真地插入了一个公式,直到我得到了无论字体大小都始终给出相似结果的东西。媒体查询确实会影响相关字符串的字体大小 CSS,因此我需要考虑这一点,否则不同字体大小的截断字符串的长度会有一些巨大差异:
.directive('truncate', function() {
return {
restrict: 'A',
replace: true,
// {{child.display}} will be a truncated copy of child.name
template: '<a class="entity-name" href="{{child.url}}" title="{{child.name}}">{{child.display}}</a>',
link: function(scope, element, attr) {
var widthThreshold = $(element).parent().parent().width() * 0.85,
// get the font-size without the 'px' at the end, what with media queries effecting font
fontSize = $(element).css('font-size').substring(0, $(element).css('font-size').lastIndexOf('px')),
// ... Don't ask...
sizeRatio = 29760/20621,
characterCount = Math.floor((widthThreshold / fontSize) * sizeRatio);
scope.$watch('child', function(val) {
// Truncate it and trim any possible trailing white-space
var truncatedName = scope.child.name.substring(0, characterCount).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
// Make sure characterCount isn't > the current length when accounting for the '...'
if (characterCount < scope.child.name.length + 3) {
scope.child.display = truncatedName + '...';
}
});
}
}
});
有趣的是,我相信我又回到了 Brandon Tilley 关于修改 DOM 与修改范围内的属性的评论。现在我已将其更改为修改属性,它可能会更好地用于过滤器?是否应该在过滤器和指令中处理此类操作的决定因素通常是什么?
【问题讨论】:
-
由于您直接操作 DOM (
nameElement.text) 而实际上并没有返回要在文本中使用的新值,我相信这应该是一个指令。 -
是的,它看起来确实很老套。我不熟悉 AngularJS 中的指令。我去研究一下。
-
"// ... 不要问... sizeRatio = 29760/20621," .. 哈哈!
标签: javascript jquery angularjs