我正在AngularJS中处理一个"collapseText"指令。它的功能是显示最多"maxLength"个字符和一个"Read More"选项,如果文本太大,该选项将加载其余文本。
我希望我的指令能够屏蔽文本,包括表达式。
理想情况下,我希望它看起来像这样:
<collapse-text max-length="10">This text will be collapsed</collapse-text>
<collapse-text max-length="10">{{foo}}</collapse-text>
我使用的模板是:
<span>{{lessText}}</span>
<span ng-if="overflow">
<span ng-if="!readMore" style="cursor:pointer" ng-click="toggleReadMore()">...(read more)</span>
<span ng-if="readMore">{{moreText}}</span>
</span>
我的指令是这样的:
'use strict'
angular.module('myModule')
.directive('collapseText', function($window){
return{
restrict: 'E',
scope: true,
transclude: true,
controller : function($scope){
$scope.toggleReadMore = function(){
$scope.readMore = true;
}
},
link: function(scope, element, attrs, ctrl, transclude){
scope.maxLength = attrs.maxLength;
/* 1. Evaluate transcluded element */
/* 2. Check transcluded element's length */
/* 3. Set lessText, moreText, readMore and overflow */
/* 4. Evaluate this directive's template */
console.log(transclude(scope.$parent, function(compiled){
scope.lessText = compiled.text().substring(0, scope.maxLength);
scope.moreText = compiled.text().substring(0, scope.maxLength);
scope.readMore = false;
scope.overflow = scope.moreText ? true : false;
return compiled.text();
}).text());
},
templateUrl: "templates/collapse-text-template.html"
}
});
完成步骤1-4的正确方法是什么?我看到的两个症状是:
- SOLVED:在溢出和readMore变量更新后,ng-if语句不会重新求值,因此,这些文本字段永远不会出现在DOM中。
- 我通过将ng-if语句分别更改为"overflow===true"、"readMore===false"one_answers"readMore===true"来修复未重新求值的问题。我仍然希望能澄清一下为什么它不能简单地使用。主要的问题是,关于排除文本评估,仍然存在
- PENDING:{{foo}}将被打印为"{{foo}}",而不是"foo包含的文本"
提前感谢您的帮助!
在指令的link()
函数中,您必须等待{{foo}}
被求值并可以使用。这可以通过使用$timeout()
在浏览器的事件循环中调度新任务来实现。我不确定这是否是最干净的解决方案,但至少它有效。
以下是您使用$timeout()
的代码和一些小的改进:
<div ng-app="myModule" ng-controller="MyController">
<collapse-text max-length="10">This text will be collapsed</collapse-text>
<collapse-text max-length="10">{{foo}}</collapse-text>
</div>
template.html
<span ng-if="!readMore">{{lessText}}</span>
<span ng-if="overflow">
<span ng-if="!readMore && overflow" style="cursor: pointer;" ng-click="toggleReadMore()">...(read more)</span>
<span ng-if="readMore">{{moreText}}</span>
</span>
脚本
angular.module('myModule', []).controller('MyController', function($scope){
$scope.foo = 'This text will also be collapsed';
});
angular.module('myModule').directive('collapseText', function($timeout){
return {
restrict: 'E',
scope: true,
transclude: true,
controller: function($scope){
$scope.toggleReadMore = function(){
$scope.readMore = true;
};
},
link: function(scope, element, attrs, ctrl, transclude){
var maxLength = +attrs.maxLength;
var compiled = transclude(scope.$parent);
$timeout(function(){
scope.lessText = compiled.text().substring(0, maxLength);
scope.moreText = compiled.text();
scope.readMore = false;
scope.overflow = scope.moreText.length > maxLength;
});
},
templateUrl: "template.html"
}
});
请注意,此实现不会对$scope.foo
的更新做出反应(即,指令不会看到更新和重新呈现)。如果需要,我建议您将内容传递给属性中的指令,并实现一个观察程序,而不是使用transclusion。例如:
angular.module('myModule').directive('collapseText', function(){
return {
restrict: 'E',
scope: {
myContent: '=',
// ...
},
link: function(scope){
scope.$watch('myContent', function(newValue){
if (newValue !== undefined) {
doSomethingWith(newValue);
}
});
},
templateUrl: "template.html"
}
});
正如Aletheios所建议的那样,我找到了一种方法,那就是在transclude文本上实现一个监视和一个手动transclude函数,该函数只需将原始输入存储在本地范围中。按照它的实现方式,它将在"lessText"字段中显示原始输入,稍后将由执行其转换的父级进行处理。此transclusion将触发collapseText指令中的监视。
我能想到一些可能发生的问题,尽管我不完全确定,因为我对AngularJS:还很陌生
-
如果超过"maxLength"显示长度的文本被屏蔽,并且需要进一步处理,它会起作用吗?示例:
<collapse-text max-length="10" {{myLongVariableName.anotherLongVariableName}}</collapse-text>
-
此代码根本不允许使用带有任何标记的文本。示例:
<collapse-text max-length="20"><b>I am bold</b></collapse-text>
- 即使它确实允许带标记的文本,当将标记拆分为lessText和moreText时,也有可能破坏标记
解决方案
最初的测试表明,它可以很好地处理明文和AngularJS表达式。
使用.html
这里需要注意的一点是,我打算在另一个指令中使用此代码,因此{{parent.foo}}
也应该工作。
<div ng-app="myModule" ng-controller="MyController">
<collapse-text max-length="10">This text will be collapsed</collapse-text>
<collapse-text max-length="10">{{foo}}</collapse-text>
</div>
template.html
<span ng-if="readMore === false">{{lessText}}</span>
<span ng-if="overflow === true">
<span ng-if="readMore === false" style="cursor:pointer" ng-click="toggleReadMore()">...(read more)</span>
<span ng-if="readMore === true">{{moreText}}</span>
</span>
脚本
angular.module("myModule")
.controller('MyController', function($scope){
$scope.foo = 'This text will also be collapsed';
})
.directive('collapseText', function($window){
return{
restrict: 'E',
scope: true,
transclude: true,
controller : function($scope){
$scope.readMore = false;
$scope.toggleReadMore = function(){
$scope.readMore = true;
}
$scope.$watch(
function(){
return $scope.transcluded;
},
function(newValue){
if($scope.transcluded){
$scope.lessText = $scope.transcluded.text().substring(0, $scope.maxLength);
$scope.moreText = $scope.transcluded.text();
$scope.readMore = false || $scope.readMore; //If it was arleady true, do not collapse it again.
$scope.overflow = $scope.moreText ? true : false;
}
}
);
},
link: function(scope, element, attrs, ctrl, transclude){
scope.maxLength = attrs.maxLength;
transclude(scope.$parent, function(transcluded){
scope.transcluded = transcluded;
});
},
templateUrl: "template.html"
}
});
在实现类似内容时,我将非常感谢有关代码和"最佳实践"的进一步反馈。