123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- <template>
- <div
- class="el-rate"
- @keydown="handleKey"
- role="slider"
- :aria-valuenow="currentValue"
- :aria-valuetext="text"
- aria-valuemin="0"
- :aria-valuemax="max"
- tabindex="0">
- <span
- v-for="(item, key) in max"
- class="el-rate__item"
- @mousemove="setCurrentValue(item, $event)"
- @mouseleave="resetCurrentValue"
- @click="selectValue(item)"
- :style="{ cursor: rateDisabled ? 'auto' : 'pointer' }"
- :key="key">
- <i
- :class="[classes[item - 1], { 'hover': hoverIndex === item }]"
- class="el-rate__icon"
- :style="getIconStyle(item)">
- <i
- v-if="showDecimalIcon(item)"
- :class="decimalIconClass"
- :style="decimalStyle"
- class="el-rate__decimal">
- </i>
- </i>
- </span>
- <span v-if="showText || showScore" class="el-rate__text" :style="{ color: textColor }">{{ text }}</span>
- </div>
- </template>
- <script>
- import { hasClass } from 'element-ui/src/utils/dom';
- import { isObject } from 'element-ui/src/utils/types';
- import Migrating from 'element-ui/src/mixins/migrating';
- export default {
- name: 'ElRate',
- mixins: [Migrating],
- inject: {
- elForm: {
- default: ''
- }
- },
- data() {
- return {
- pointerAtLeftHalf: true,
- currentValue: this.value,
- hoverIndex: -1
- };
- },
- props: {
- value: {
- type: Number,
- default: 0
- },
- lowThreshold: {
- type: Number,
- default: 2
- },
- highThreshold: {
- type: Number,
- default: 4
- },
- max: {
- type: Number,
- default: 5
- },
- colors: {
- type: [Array, Object],
- default() {
- return ['#F7BA2A', '#F7BA2A', '#F7BA2A'];
- }
- },
- voidColor: {
- type: String,
- default: '#C6D1DE'
- },
- disabledVoidColor: {
- type: String,
- default: '#EFF2F7'
- },
- iconClasses: {
- type: [Array, Object],
- default() {
- return ['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on'];
- }
- },
- voidIconClass: {
- type: String,
- default: 'el-icon-star-off'
- },
- disabledVoidIconClass: {
- type: String,
- default: 'el-icon-star-on'
- },
- disabled: {
- type: Boolean,
- default: false
- },
- allowHalf: {
- type: Boolean,
- default: false
- },
- showText: {
- type: Boolean,
- default: false
- },
- showScore: {
- type: Boolean,
- default: false
- },
- textColor: {
- type: String,
- default: '#1f2d3d'
- },
- texts: {
- type: Array,
- default() {
- return ['极差', '失望', '一般', '满意', '惊喜'];
- }
- },
- scoreTemplate: {
- type: String,
- default: '{value}'
- }
- },
- computed: {
- text() {
- let result = '';
- if (this.showScore) {
- result = this.scoreTemplate.replace(/\{\s*value\s*\}/, this.rateDisabled
- ? this.value
- : this.currentValue);
- } else if (this.showText) {
- result = this.texts[Math.ceil(this.currentValue) - 1];
- }
- return result;
- },
- decimalStyle() {
- let width = '';
- if (this.rateDisabled) {
- width = `${ this.valueDecimal }%`;
- } else if (this.allowHalf) {
- width = '50%';
- }
- return {
- color: this.activeColor,
- width
- };
- },
- valueDecimal() {
- return this.value * 100 - Math.floor(this.value) * 100;
- },
- classMap() {
- return Array.isArray(this.iconClasses)
- ? {
- [this.lowThreshold]: this.iconClasses[0],
- [this.highThreshold]: { value: this.iconClasses[1], excluded: true },
- [this.max]: this.iconClasses[2]
- } : this.iconClasses;
- },
- decimalIconClass() {
- return this.getValueFromMap(this.value, this.classMap);
- },
- voidClass() {
- return this.rateDisabled ? this.disabledVoidIconClass : this.voidIconClass;
- },
- activeClass() {
- return this.getValueFromMap(this.currentValue, this.classMap);
- },
- colorMap() {
- return Array.isArray(this.colors)
- ? {
- [this.lowThreshold]: this.colors[0],
- [this.highThreshold]: { value: this.colors[1], excluded: true },
- [this.max]: this.colors[2]
- } : this.colors;
- },
- activeColor() {
- return this.getValueFromMap(this.currentValue, this.colorMap);
- },
- classes() {
- let result = [];
- let i = 0;
- let threshold = this.currentValue;
- if (this.allowHalf && this.currentValue !== Math.floor(this.currentValue)) {
- threshold--;
- }
- for (; i < threshold; i++) {
- result.push(this.activeClass);
- }
- for (; i < this.max; i++) {
- result.push(this.voidClass);
- }
- return result;
- },
- rateDisabled() {
- return this.disabled || (this.elForm || {}).disabled;
- }
- },
- watch: {
- value(val) {
- this.currentValue = val;
- this.pointerAtLeftHalf = this.value !== Math.floor(this.value);
- }
- },
- methods: {
- getMigratingConfig() {
- return {
- props: {
- 'text-template': 'text-template is renamed to score-template.'
- }
- };
- },
- getValueFromMap(value, map) {
- const matchedKeys = Object.keys(map)
- .filter(key => {
- const val = map[key];
- const excluded = isObject(val) ? val.excluded : false;
- return excluded ? value < key : value <= key;
- })
- .sort((a, b) => a - b);
- const matchedValue = map[matchedKeys[0]];
- return isObject(matchedValue) ? matchedValue.value : (matchedValue || '');
- },
- showDecimalIcon(item) {
- let showWhenDisabled = this.rateDisabled && this.valueDecimal > 0 && item - 1 < this.value && item > this.value;
- /* istanbul ignore next */
- let showWhenAllowHalf = this.allowHalf &&
- this.pointerAtLeftHalf &&
- item - 0.5 <= this.currentValue &&
- item > this.currentValue;
- return showWhenDisabled || showWhenAllowHalf;
- },
- getIconStyle(item) {
- const voidColor = this.rateDisabled ? this.disabledVoidColor : this.voidColor;
- return {
- color: item <= this.currentValue ? this.activeColor : voidColor
- };
- },
- selectValue(value) {
- if (this.rateDisabled) {
- return;
- }
- if (this.allowHalf && this.pointerAtLeftHalf) {
- this.$emit('input', this.currentValue);
- this.$emit('change', this.currentValue);
- } else {
- this.$emit('input', value);
- this.$emit('change', value);
- }
- },
- handleKey(e) {
- if (this.rateDisabled) {
- return;
- }
- let currentValue = this.currentValue;
- const keyCode = e.keyCode;
- if (keyCode === 38 || keyCode === 39) { // left / down
- if (this.allowHalf) {
- currentValue += 0.5;
- } else {
- currentValue += 1;
- }
- e.stopPropagation();
- e.preventDefault();
- } else if (keyCode === 37 || keyCode === 40) {
- if (this.allowHalf) {
- currentValue -= 0.5;
- } else {
- currentValue -= 1;
- }
- e.stopPropagation();
- e.preventDefault();
- }
- currentValue = currentValue < 0 ? 0 : currentValue;
- currentValue = currentValue > this.max ? this.max : currentValue;
- this.$emit('input', currentValue);
- this.$emit('change', currentValue);
- },
- setCurrentValue(value, event) {
- if (this.rateDisabled) {
- return;
- }
- /* istanbul ignore if */
- if (this.allowHalf) {
- let target = event.target;
- if (hasClass(target, 'el-rate__item')) {
- target = target.querySelector('.el-rate__icon');
- }
- if (hasClass(target, 'el-rate__decimal')) {
- target = target.parentNode;
- }
- this.pointerAtLeftHalf = event.offsetX * 2 <= target.clientWidth;
- this.currentValue = this.pointerAtLeftHalf ? value - 0.5 : value;
- } else {
- this.currentValue = value;
- }
- this.hoverIndex = value;
- },
- resetCurrentValue() {
- if (this.rateDisabled) {
- return;
- }
- if (this.allowHalf) {
- this.pointerAtLeftHalf = this.value !== Math.floor(this.value);
- }
- this.currentValue = this.value;
- this.hoverIndex = -1;
- }
- },
- created() {
- if (!this.value) {
- this.$emit('input', 0);
- }
- }
- };
- </script>
|