我需要根据回复动态显示星级。
我可以显示1到5的值,但如果等级为0,则不会显示空星。
如果评级= 0.4,它也会显示1颗星。
我的控制器:
(function() {
'use strict';
angular
var app = angular
.module('app')
app.directive('starRating', function () {
return {
restrict: 'A',
template: '<ul class="rating">' +
'<li ng-repeat="star in stars" ng-class="star" ng-click="toggle($index)">' +
'\u2605' +
'</li>' +
'</ul>',
scope: {
ratingValue: '=',
max: '='
},
link: function (scope, elem, attrs) {
var updateStars = function () {
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
if(i == 0) {
scope.stars = [];
scope.stars.push({
empty: i = 0
});
} else {
scope.stars.push({
filled: i < scope.ratingValue
});
}
}
};
scope.$watch('ratingValue', function (oldVal, newVal) {
if (newVal) {
updateStars();
}
});
}
}
});
app.controller('Controller', Controller);
Controller.$inject = ['UserService', '$location', '$rootScope', '$scope', 'fileUpload', 'FlashService', '$cookieStore', '$timeout', '$window'];
function Controller(UserService, $location, $rootScope, $scope, fileUpload, FlashService, $cookieStore, $timeout, $window) {
$scope.selectTestSubject = function() {
$scope.rating = 0;
console.log(levels.length);
for(var k=0; k<levels.length; k++) {
var respRating = levels[k].rating;
// var respRating = 1.5;
console.log(respRating);
$scope.ratings = [{
current: respRating,
max: 5
}];
if(respRating == 0) {
$scope.defaultRating = true;
} else {
$scope.defaultRating = false;
}
}
}
}
}) ();
我的HTML页面:
<div><span ng-repeat="rating in ratings">
<div star-rating rating-value="rating.current" max="rating.max"></div>
</span>
</div>
答案 0 :(得分:2)
您的解决方案的一个问题是您的$ watch表达式。你有以下地方:
scope.$watch('ratingValue', function (oldVal, newVal) {
if (newVal) {
updateStars();
}
});
oldVal
和newVal
实际上是错误的方式,$ watch函数首先接受新值后跟旧值。其次,条件if (newVal)
对0不起作用,因为0是假值。
相反,你应该:
scope.$watch('ratingValue', function(value, previousValue) {
// Only update the view when the value has changed.
if (value !== previousValue) {
updateStars();
}
});
您的updateStars
函数也始终重新初始化scope.stars
变量并附加到其上。这样做可能会产生一些不必要的副作用,导致视图无法反映模型值。最好初始化数组,然后附加项目(如果它尚不存在)或更新现有值。所以你会有这样的事情:
// Initialise the stars array.
scope.stars = [];
var updateStars = function() {
for (var i = 0; i < scope.max; i++) {
var filled = i < Math.round(scope.ratingValue);
// Check if the item in the stars array exists and
// append it, otherwise update it.
if (scope.stars[i] === undefined) {
scope.stars.push({
filled: filled
});
} else {
scope.stars[i].filled = filled;
}
}
};
由于$ watch表达式仅在值更改时更新星标,因此您现在需要在链接功能首次触发时触发更新。所以这很简单:
// Trigger an update immediately.
updateStars();
您的模板也未正确使用星标上的filled
属性,而应包含相应的ng-class
,如下所示:
<ul class="rating">
<li class="star"
ng-repeat="star in stars"
ng-class="{ filled: star.filled }"
ng-click="toggle($index)">
\u2605
</li>
</ul>
用简单的风格
.star {
cursor: pointer;
color: black;
}
.star.filled {
color: yellow;
}
您还可以通过聆听mouseenter
和mouseleave
效果来改善此评级系统,以便在用户选择新值时星号显示为黄色。这是非常常见的功能。您可以通过一些修改来实现这一目标。
首先,应该更新模板以监听这些事件:
<ul class="rating">
<li class="star"
ng-repeat="star in stars"
ng-class="{ filled: star.filled }"
ng-mouseenter="onMouseEnter($event, $index + 1)"
ng-mouseleave="onMouseLeave($event)"
ng-click="toggle($index)">
\u2605
</li>
</ul>
接下来,我们想对updateStars函数进行一些小调整,以获取一个评级参数:
var updateStars = function(rating /* instead of blank */ ) {
for (var i = 0; i < scope.max; i++) {
var filled = i < Math.round(rating); // instead of scope.ratingValue
// Check if the item in the stars array exists and
// append it, otherwise update it.
if (scope.stars[i] === undefined) {
scope.stars.push({
filled: filled
});
} else {
scope.stars[i].filled = filled;
}
}
};
// Trigger an update immediately.
updateStars(scope.ratingValue /* instead of blank */ );
scope.$watch('ratingValue', function(value, previousValue) {
// Only update the view when the value changed.
if (value !== previousValue) {
updateStars(scope.ratingValue /* instead of blank */ );
}
});
现在我们可以从视图
添加我们的事件回调// Triggered when the cursor enters a star rating (li element).
scope.onMouseEnter = function (event, rating) {
updateStars(rating);
};
// Triggered when the cursor leaves a star rating.
scope.onMouseLeave = function (event) {
updateStars(scope.ratingValue);
};
就是这样! Full demo here.