【发布时间】:2015-02-04 02:39:02
【问题描述】:
我正在研究一个指令,该指令将允许根据该数字的可用空间量以友好的方式显示数字字段,例如,如果您有一个值为 10,000,000,000 的字段,这将如果没有足够的空间容纳 10,000,000,000 的全部值,则显示为 10B(B 表示十亿)。
我希望它可以与引导程序一起使用。我能想到的最好的方法是将元素包装在一个父元素中,该父元素将由引导程序调整大小(然后目标元素会做出相应的反应)。我能够做到这一点,但我想有更好的方法。
这是一个 HTML 示例(指令是“响应编号”属性):
<div class="container-fluid">
<div class="row">
<div class="col-md-4">Some Label: </div>
<div class="col-md-8">
<div responsive-number ng-model="someValue"></div>
</div>
</div>
</div>
该指令在初始渲染时将元素的最大宽度设置为父节点的 innerWidth()。这里的一个限制是你不能在父节点中包含任何其他元素,所以我认为必须有一个更好的,也许更被动的方法来通过响应调整大小的响应数字元素来解决这个问题(我只是在强制 responsive-number 元素保持在父容器的范围内时不确定如何执行此操作)。
以下是基于上述 HTML 为我工作的 javascript。我通过设置文本溢出样式来检测响应数字容器的值太大,以便通过剪辑隐藏溢出 - 这是父容器进入的地方,因为我需要设置最大大小元素到父容器的大小:
可以在此处找到一个 jsfiddle 示例,但为了方便起见,稍作修改以使用 jQuery 事件(但请注意,我知道这是一种不好的做法):http://jsfiddle.net/F52y5/63/
'use strict';
function MyCtrl($scope) {
$scope.someValue = 100000000000000000;
}
app.directive('responsiveNumber', ['$filter', function ($filter) {
return {
require: 'ngModel',
restrict: 'A',
scope: true,
link: function (scope, element, attrs, ctrl) {
var scrollWidth = element[0].scrollWidth;
var parentWidth = getParentWidth();
var displayFriendlyValue = false;
initializeResponsiveNumber();
ctrl.$render();
ctrl.$render = function (isResizeEvent) {
var temp = shouldRenderFriendlyValue();
if(isResizeEvent){
// then the window was resized and the element is already formatted
// so if it fits, then that's all she wrote..
if (displayFriendlyValue == temp) {
return;
}
}
displayFriendlyValue = temp;
var viewValue = getTransformedViewValue(ctrl.$modelValue, displayFriendlyValue);
ctrl.$viewValue = viewValue;
element.html(ctrl.$viewValue);
// after we've formatted the number it may not fit anymore
// so if shouldRenderFriendlyValue() previously returned false
// that means the unformatted number was not overflowing, but
// the formatted number may overflow
if (!displayFriendlyValue) {
// we check shouldRenderFriendlyValue() again
// because sizing can change after we set
// element.html(ctrl.$viewValue);
displayFriendlyValue = shouldRenderFriendlyValue();
if (displayFriendlyValue) {
viewValue = getTransformedViewValue(ctrl.$modelValue, displayFriendlyValue);
ctrl.$viewValue = viewValue;
element.html(ctrl.$viewValue);
return;
}
}
};
function getTransformedViewValue(modelValue, displayFriendlyValue){
var result;
// could add support for specifying native filter types
// (currency, for instance), but not necessary for this example
if(displayFriendlyValue){
result = makeFriendlyNumber(modelValue, 'number');
} else {
result = $filter('number')(modelValue);
}
return result;
}
function cleanNumber(num) {
return (Math.round(num * 10) / 10);
}
function makeFriendlyNumber(num, filter) {
var result;
if (num >= 1000000000) {
result = $filter(filter)(cleanNumber(num / 1000000000)) + 'B';
} else if (num >= 1000000) {
result = $filter(filter)(cleanNumber(num / 1000000)) + 'M';
} else if (num >= 1000) {
result = $filter(filter)(cleanNumber(num / 1000)) + 'K';
} else {
result = $filter(filter)(num);
}
return result.toString().replace(/(\.[\d]*)/, '');
}
function initializeResponsiveNumber() {
element[0].style['overflow'] = 'hidden';
element[0].style['-moz-text-overflow'] = 'clip';
element[0].style['text-overflow'] = 'clip';
updateElementSize(parentWidth);
var debouncedResizeEvent = $scope.$on('debouncedresize', function (event) {
scope.$apply(function () {
var newParentWidth = getParentWidth();
if (newParentWidth == parentWidth) { return; }
parentWidth = newParentWidth;
updateElementSize(parentWidth);
ctrl.$render(true);
});
});
$scope.$on('$destroy', debouncedResizeEvent()};
}
function getParentWidth() {
var innerWidth = angular.element(element[0].parentNode).innerWidth();
return innerWidth;
}
function shouldRenderFriendlyValue() {
scrollWidth = element[0].scrollWidth;
if (element.innerWidth() < scrollWidth) {
return true;
}
return false;
}
function updateElementSize(width) {
element[0].style.width = width + 'px';
}
}
}
}]);
任何建议将不胜感激!
另外值得注意的是,我知道在某些情况下,此函数的渲染次数超出了必要的次数 - 但如果有更好的方法,则优化它是没有意义的。
---------------更新-------------
这里有些混乱,所以我想尝试简化问题陈述:
我如何知道是否有足够的空间来显示完整的值,或者我是否必须缩写它?
我已经展示了一种方法来解决这个问题,但我不相信这是最好的方法。
【问题讨论】:
-
似乎付出了很多努力。我倾向于在所有情况下简单地过滤数字,或者在移动屏幕宽度上这样做。 stackoverflow.com/a/10601315/1264804
-
赞成这个不错的实现......但是你的问题是什么?
-
谢谢!似乎应该有更好的方法来解决这个问题,而不是必须使用父元素?
-
@isherwood:不幸的是,在这种情况下,以标准宽度(例如 762 像素)调整大小并没有增加太多价值 - 而且,这些值可能会根据用户输入而改变,所以它不仅必须这样做调整窗口大小 - 在数字更改后,可能会显示不友好的值,或者可能需要在以前的值较小的地方显示友好的值。我需要尽可能具体地显示数字,但信息量很大,因此有时最好显示友好的值以保持美观。
标签: javascript angularjs css twitter-bootstrap angularjs-directive