You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
5.5 KiB
227 lines
5.5 KiB
// Utils
|
|
import { createNamespace, addUnit } from '../utils';
|
|
import { preventDefault } from '../utils/dom/event'; // Mixins
|
|
|
|
import { TouchMixin } from '../mixins/touch';
|
|
import { FieldMixin } from '../mixins/field'; // Components
|
|
|
|
import Icon from '../icon';
|
|
|
|
var _createNamespace = createNamespace('rate'),
|
|
createComponent = _createNamespace[0],
|
|
bem = _createNamespace[1];
|
|
|
|
function getRateStatus(value, index, allowHalf) {
|
|
if (value >= index) {
|
|
return 'full';
|
|
}
|
|
|
|
if (value + 0.5 >= index && allowHalf) {
|
|
return 'half';
|
|
}
|
|
|
|
return 'void';
|
|
}
|
|
|
|
export default createComponent({
|
|
mixins: [TouchMixin, FieldMixin],
|
|
props: {
|
|
size: [Number, String],
|
|
color: String,
|
|
gutter: [Number, String],
|
|
readonly: Boolean,
|
|
disabled: Boolean,
|
|
allowHalf: Boolean,
|
|
voidColor: String,
|
|
iconPrefix: String,
|
|
disabledColor: String,
|
|
value: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
icon: {
|
|
type: String,
|
|
default: 'star'
|
|
},
|
|
voidIcon: {
|
|
type: String,
|
|
default: 'star-o'
|
|
},
|
|
count: {
|
|
type: [Number, String],
|
|
default: 5
|
|
},
|
|
touchable: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
},
|
|
computed: {
|
|
list: function list() {
|
|
var list = [];
|
|
|
|
for (var i = 1; i <= this.count; i++) {
|
|
list.push(getRateStatus(this.value, i, this.allowHalf));
|
|
}
|
|
|
|
return list;
|
|
},
|
|
sizeWithUnit: function sizeWithUnit() {
|
|
return addUnit(this.size);
|
|
},
|
|
gutterWithUnit: function gutterWithUnit() {
|
|
return addUnit(this.gutter);
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
this.bindTouchEvent(this.$el);
|
|
},
|
|
methods: {
|
|
select: function select(index) {
|
|
if (!this.disabled && !this.readonly && index !== this.value) {
|
|
this.$emit('input', index);
|
|
this.$emit('change', index);
|
|
}
|
|
},
|
|
onTouchStart: function onTouchStart(event) {
|
|
var _this = this;
|
|
|
|
if (this.readonly || this.disabled || !this.touchable) {
|
|
return;
|
|
}
|
|
|
|
this.touchStart(event);
|
|
var rects = this.$refs.items.map(function (item) {
|
|
return item.getBoundingClientRect();
|
|
});
|
|
var ranges = [];
|
|
rects.forEach(function (rect, index) {
|
|
if (_this.allowHalf) {
|
|
ranges.push({
|
|
score: index + 0.5,
|
|
left: rect.left
|
|
}, {
|
|
score: index + 1,
|
|
left: rect.left + rect.width / 2
|
|
});
|
|
} else {
|
|
ranges.push({
|
|
score: index + 1,
|
|
left: rect.left
|
|
});
|
|
}
|
|
});
|
|
this.ranges = ranges;
|
|
},
|
|
onTouchMove: function onTouchMove(event) {
|
|
if (this.readonly || this.disabled || !this.touchable) {
|
|
return;
|
|
}
|
|
|
|
this.touchMove(event);
|
|
|
|
if (this.direction === 'horizontal') {
|
|
preventDefault(event);
|
|
var clientX = event.touches[0].clientX;
|
|
this.select(this.getScoreByPosition(clientX));
|
|
}
|
|
},
|
|
getScoreByPosition: function getScoreByPosition(x) {
|
|
for (var i = this.ranges.length - 1; i > 0; i--) {
|
|
if (x > this.ranges[i].left) {
|
|
return this.ranges[i].score;
|
|
}
|
|
}
|
|
|
|
return this.allowHalf ? 0.5 : 1;
|
|
},
|
|
genStar: function genStar(status, index) {
|
|
var _this2 = this;
|
|
|
|
var h = this.$createElement;
|
|
var icon = this.icon,
|
|
color = this.color,
|
|
count = this.count,
|
|
voidIcon = this.voidIcon,
|
|
disabled = this.disabled,
|
|
voidColor = this.voidColor,
|
|
disabledColor = this.disabledColor;
|
|
var score = index + 1;
|
|
var isFull = status === 'full';
|
|
var isVoid = status === 'void';
|
|
var style;
|
|
|
|
if (this.gutterWithUnit && score !== +count) {
|
|
style = {
|
|
paddingRight: this.gutterWithUnit
|
|
};
|
|
}
|
|
|
|
return h("div", {
|
|
"ref": "items",
|
|
"refInFor": true,
|
|
"key": index,
|
|
"attrs": {
|
|
"role": "radio",
|
|
"tabindex": "0",
|
|
"aria-setsize": count,
|
|
"aria-posinset": score,
|
|
"aria-checked": String(!isVoid)
|
|
},
|
|
"style": style,
|
|
"class": bem('item')
|
|
}, [h(Icon, {
|
|
"attrs": {
|
|
"size": this.sizeWithUnit,
|
|
"name": isFull ? icon : voidIcon,
|
|
"color": disabled ? disabledColor : isFull ? color : voidColor,
|
|
"classPrefix": this.iconPrefix,
|
|
"data-score": score
|
|
},
|
|
"class": bem('icon', {
|
|
disabled: disabled,
|
|
full: isFull
|
|
}),
|
|
"on": {
|
|
"click": function click() {
|
|
_this2.select(score);
|
|
}
|
|
}
|
|
}), this.allowHalf && h(Icon, {
|
|
"attrs": {
|
|
"size": this.sizeWithUnit,
|
|
"name": isVoid ? voidIcon : icon,
|
|
"color": disabled ? disabledColor : isVoid ? voidColor : color,
|
|
"classPrefix": this.iconPrefix,
|
|
"data-score": score - 0.5
|
|
},
|
|
"class": bem('icon', ['half', {
|
|
disabled: disabled,
|
|
full: !isVoid
|
|
}]),
|
|
"on": {
|
|
"click": function click() {
|
|
_this2.select(score - 0.5);
|
|
}
|
|
}
|
|
})]);
|
|
}
|
|
},
|
|
render: function render() {
|
|
var _this3 = this;
|
|
|
|
var h = arguments[0];
|
|
return h("div", {
|
|
"class": bem({
|
|
readonly: this.readonly,
|
|
disabled: this.disabled
|
|
}),
|
|
"attrs": {
|
|
"tabindex": "0",
|
|
"role": "radiogroup"
|
|
}
|
|
}, [this.list.map(function (status, index) {
|
|
return _this3.genStar(status, index);
|
|
})]);
|
|
}
|
|
}); |