我写了一个非常简单的小部件/片段。悬停时五颗星(使用font-awesome),用填充星替换空星。在鼠标输出时返回默认值。如果有一个默认值的星形,并点击更改默认值取决于点击的星(例如点击第四个星会将值更改为4,依此类推。真的很简单。我不能为生活我使用角度js复制它......
我知道如果我理解正确,我需要使用指令和转换。我有很多麻烦甚至变量没有。基于默认值的填充星和空星...
如果有人能指导我,我会很感激..这是代码。
Html东西
<div class="ratingList" rating-widget rate='{{ rating }}' increment="increment()">
<span>Hate it</span>
<span class="star"><i class="fa fa-star-o fa-lg"></i></span>
<span class="star"><i class="fa fa-star-o fa-lg"></i></span>
<span class="star"><i class="fa fa-star-o fa-lg"></i></span>
<span class="star"><i class="fa fa-star-o fa-lg"></i></span>
<span class="star"><i class="fa fa-star-o fa-lg"></i></span>
<span>love it</span>
非常基本的控制器
bmApp.controller('MainController', ['$scope', function($scope){
$scope.rating = 3;
$scope.increment = function(){
$scope.rating = $scope.rating + 1;
}
}]);
罪魁祸首指令
bmApp.directive('ratingWidget', function(){
return{
restrict: 'A',
replace:true,
transclude:true,
template: '<div><button ng-click="increment()">Click</button><div class="rating"></div></div>',
controller:['$scope', '$element', '$transclude', function($scope, $element, $transclude){
$transclude(function(clone){
var stars = clone.filter('.star');
var filledStar = $('<span class="star"><i class="fa fa-star fa-lg"></i></span>');
var container = $element.find('.rating');
angular.forEach(stars, function(val, key){
var star = $(val);
if(key<$scope.rate)
{
//console.log(key);
container.append(filledStar);
//star.replaceWith(filledStar);
//angular.element(star.children()[0]).removeClass('fa-star-o').addClass('fa-star')
}else{
//console.log(key);
container.append(star);
}
});
});
}],
scope:{
rate:'@',
increment:'&'
}
}
});
我一开始就陷入困境,无法根据默认值显示填充的星星...附加结果导致3星......
答案 0 :(得分:2)
有几种不同的方法可以处理这种功能。
我已更新您的示例以显示使用隔离范围和转换(对于increment()
按钮)。
我们还将明星标记捆绑到ratingWidget
指令中,使其成为模块化的,并将其保留为更多的独立组件。
您可以看到,由于ng-repeat
和ng-class
指令,如果我们不想,我们不必直接使用HTML元素,Angular通过数据绑定处理繁重的工作。
这是一个掠夺者:http://plnkr.co/edit/hd5DLOpRC3R9EFy316Gl?p=preview
(如果你看一下Plunker上的历史,你会看到我是如何使用jQuery直接操作元素/类的)
<强> HTML:
<div ng-app="bmApp">
<div ng-controller="MainController">
<div rating-widget rate="rating" max-rating="maxRating">
<!--
This is the content that will be transcluded.
Transclusion means that this content will linked with
the parent scope instead of being linked into the
scope of the `ratingWidget`.
i.e. the `increment()` function is defined in `MainController`
not in the `ratingWidget`.
-->
<button ng-click="increment()">Click</button>
</div>
</div>
</div>
<强> JavaScript的:
var bmApp = angular.module('bmApp', []);
bmApp.controller('MainController', ['$scope',
function($scope) {
$scope.rating = 3;
$scope.maxRating = 6;
$scope.increment = function() {
if ($scope.rating < $scope.maxRating){
$scope.rating += 1;
}
}
}]);
bmApp.directive('ratingWidget', function() {
return {
restrict: 'A',
transclude: true,
scope: {
rate: '=',
maxRating: '='
},
link: function(scope, element, attr){
var classes = {
empty: 'fa-star-o',
full: 'fa-star'
};
scope.stars = [];
scope.$watch('maxRating', function(maxRating){
maxRating = maxRating || 5;
scope.stars.length = maxRating;
for (var i = 0, len = scope.stars.length; i < len; i++){
if (!scope.stars[i]){
scope.stars[i] = {
cssClass: classes.empty
};
}
}
updateRating(scope.rate);
});
scope.$watch('rate', function(newRating){
updateRating(newRating);
});
scope.selectRating = function(index){
// The $index is zero-index but the ratings
// start at one, so add 1.
scope.rate = index + 1;
}
function updateRating(rating){
rating = rating || 0;
for (var i = 0, len = scope.stars.length; i < len; i++){
var star = scope.stars[i];
if (i < rating){
star.cssClass = classes.full;
} else {
star.cssClass = classes.empty;
}
}
}
},
template: '<div>' +
'<div class="ratingList">' +
'<span>Hate it</span>' +
'<span class="stars">' +
'<span class="star" ng-click="selectRating($index)" ng-repeat="star in stars track by $index"><i class="fa fa-lg" ng-class="star.cssClass"></i></span>' +
'</span>' +
'<span>love it</span>' +
'</div>' +
'<div ng-transclude></div' +
'</div>'
}
})
修改
@担堂
是的,如果您在指令之外但在MainController
内有按钮,它将按预期工作,您不需要转换。
但关键是按钮位于指令内并调用MainController
上定义的方法。为此,我们需要转换内容以便绑定到父作用域。
这是一个显示此示例的plunker:http://plnkr.co/edit/x9xZwve9VkwbTGKUGjZJ?p=preview
<强> HTML:
<div ng-controller="MainCtrl">
<div>I am: {{name}}</div>
<div widget>
<!--
Without transclusion this will say 'widget', with transclusion this will say 'controller'.
Transclusion lets us control the scope to which these expressions are bound.
-->
<div>I am: {{name}}</div>
</div>
</div>
<强> JavaScript的:
testApp.controller('MainCtrl', ['$scope', function($scope){
$scope.name = 'controller';
}]);
testApp.directive('widget', function(){
return {
scope: true,
transclude: true,
link: function(scope, element, attr){
scope.name = 'widget'
},
template: '<div>' +
'<div>I am: {{name}}</div>' +
'<div ng-transclude></div>' +
'</div>'
}
});
我会说Angular中的transclude
就像JavaScript中的闭包 - 它允许您控制变量和表达式绑定的范围。
以上示例的粗略JavaScript模拟显示了两个概念之间的一些相似之处:
var name = 'controller';
var printCallback = function(){
console.log('name=' + name);
}
function Widget(printCallback){
var name = 'widget';
this.printName = function(){
console.log('name=' + name);
printCallback();
}
}
var widget = new Widget(printCallback);
widget.printName();
// Prints:
// name=widget
// name=controller
答案 1 :(得分:0)
评级系统定制级别和易于安装,我发现最好:https://rating-widget.com/get/rating/