UNPKG

@minix-iot/ui

Version:

基于Vue的移动端轻量级UI组件库

196 lines (194 loc) 5.05 kB
import { Namespace } from '../../utils/namespace' import Icon from '../icon/icon.jsx' const namespace = Namespace.Create('rate') export default { name: namespace.name, components: { Icon }, props: { value: { type: Number, default: 0 }, count: { type: Number, default: 5 }, size: { type: String | Number, default: 'middle' }, gutter: { type: Number, default: 0 }, color: { type: String, default: '#c7c7cc' }, activeColor: { type: String, default: '#FF9500' }, icon: { type: String, default: 'star-line' }, activeIcon: { type: String, default: 'star' }, disabled: { type: Boolean, default: false }, readonly: { type: Boolean, default: false }, touchable: { type: Boolean, default: false }, allowHalf: { type: Boolean, default: false } }, model: { prop: 'value', event: 'change' }, data() { return { rectScoreMap: [] }; }, computed: { cls() { return namespace.derive({ disabled: this.disabled }); }, itemCls() { return namespace.derive('item', [this.size]); }, halfItemCls(){ return namespace.derive('item-half') }, iconSize() { if (Number.isNaN(parseInt(this.size))) { let res = 16; switch (this.size) { case 'small': res = 16; break; case 'middle': res = 28; break; case 'large': res = 32; break; } return res; } else { return this.size; } }, itemMetaList() { const res = []; const value = this.value > this.count ? this.value % this.count : this.value; for (let i = 0; i < this.count; i++) { res.push(this.getMetaByIndex(i + 1, value)); } return res; } }, methods: { getMetaByIndex(index, value) { const meta = { type: this.icon, color: this.color, isHalf: false }; if (value >= index) { meta.type = this.activeIcon; meta.color = this.activeColor; return meta; } if (value + 0.5 >= index && this.allowHalf) { meta.isHalf = true; } return meta; }, mapScoreWithRange() { const res = []; for (let i = 0; i < this.itemMetaList.length; i++) { const rect = this.$refs[`item_${i}`].getBoundingClientRect(); if (this.allowHalf) { res.push({ left: rect.left, score: i + 0.5 }, { left: rect.left + rect.width / 2, score: i + 1 }); } else { res.push({ left: rect.left, score: i + 1 }); } } this.rectScoreMap = res; }, getScoreByPosition(left) { for (let index = this.rectScoreMap.length - 1; index > 0; index--) { const item = this.rectScoreMap[index]; if (item.left <= left) { return item.score; } } return this.allowHalf ? 0.5 : 1; }, onTouchStart(e) { if (this.readonly || !this.touchable || this.disabled) { return; } this.mapScoreWithRange(); }, onTouchMove(e) { if (this.readonly || !this.touchable || this.disabled) { return; } const { clientX } = e.touches[0]; const score = this.getScoreByPosition(clientX); this.emitChange(score); }, onClick(e, i) { if (this.readonly || this.disabled) { return; } let res = i; if (this.allowHalf) { const target = e.currentTarget; const rect = target.getBoundingClientRect(); const left = rect.left + rect.width / 2; res += e.clientX <= left ? 0.5 : 1; } else { res += 1; } this.emitChange(res); }, emitChange(value) { this.$emit('change', value); } }, render(){ const renderItems = ()=> this.itemMetaList.map((v,i)=>( <div ref={`item_${i}`} class={this.itemCls} onclick={e => this.onClick(e, i)}> <Icon name={v.type} color={v.color} size={this.iconSize} /> { v.isHalf &&( <div class={this.halfItemCls}> <Icon name={this.activeIcon} color={this.activeColor} size={this.iconSize} /> </div> ) } </div> )) return ( <div class={this.cls} onTouchstart={this.onTouchStart} onTouchmove={this.onTouchMove}> {renderItems()} </div> ) } };