问题描述
我需要根据回复动态显示星级.
I need to display star rating dynamically based on response.
我能够显示从1到5的值,但是如果等级为0,则不会显示空星.
I am able to display values from 1 to 5 but if rating is 0 then no empty stars are displaying.
如果等级= 0.4,也将显示1星填充.
If rating = 0.4 also it's showing 1 star filled.
我的控制器:
(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>
推荐答案
解决方案的一个问题是$ watch表达式.您在以下位置:
One problem with your solution is your $watch expression. Where you have the following:
scope.$watch('ratingValue', function (oldVal, newVal) {
if (newVal) {
updateStars();
}
});
oldVal
和 newVal
实际上是错误的方法,$ watch函数首先采用新值,然后采用旧值.其次,条件 if(newVal)
不适用于0,因为0是一个假值.
oldVal
and newVal
are actually the wrong way around, the $watch function first takes in the new value followed by the old value. Secondly, the condition if (newVal)
doesn't work for 0, because 0 is a falsey value.
相反,您应该具有:
scope.$watch('ratingValue', function(value, previousValue) {
// Only update the view when the value has changed.
if (value !== previousValue) {
updateStars();
}
});
您的 updateStars
函数还将始终重新初始化 scope.stars
变量并将其追加到变量中.这样做可能会产生一些有害的副作用,并导致视图无法反映模型值.最好初始化数组,然后附加尚不存在的项或更新现有值.所以你会得到这样的东西:
Your updateStars
function also always reinitialises the scope.stars
variable and appends onto it. Doing this can have some unwanted side effects and results in the view not reflecting the model value. It's best to initialise the array, then append the item if it doesn't yet exist or update the existing value. So you'll have something like this:
// 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表达式仅在值更改时更新星号,因此您现在需要在链接函数第一次触发时触发更新.所以这很简单:
Since the $watch expression only updates the stars when the value has changed, you'll now need to trigger the update the first time your link function fires. So this is simply:
// Trigger an update immediately.
updateStars();
您的模板还没有正确利用星星上的 filled
属性,而是应包含相应的 ng-class
,如下所示:
Your template also does not correctly utilise the filled
property on the star, it should instead contain the appropriate ng-class
like so:
<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
效果来改进此评级系统,以便在用户选择新值时,星星显示为黄色.这是非常常见的功能.您可以通过进行一些修改来实现此目的.
You can also improve this rating system by listening to mouseenter
and mouseleave
effects, so that the stars appear yellow when the user is selecting a new value. This is pretty common functionality. You can achieve this by making a few modifications.
首先,应更新模板以侦听以下事件:
To begin with, the template should be updated to listen for these events:
<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函数进行一些小的调整以引入一个评分参数:
Next, we want to make a small adjustment to the updateStars function to take in a rating parameter:
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 */ );
}
});
现在,我们可以从视图中添加事件回调,
Now we can add in our event callbacks from the view,
// 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);
};
就是这样!此处是完整演示.
这篇关于如何根据响应动态显示星级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!