/**
*
* @authors yutent (yutent.io@gmail.com)
* @date 2020-12-08 11:30:52
* @version v1.0.0
*
*/
import $ from "../utils.js"
export default class Star extends HTMLElement {
static get observedAttributes() {
return ["value","text","size","color","'allow-half'","'show-value'","starSize","disabled"]
}
props = {
value: 0,
text: [],
size: '',
color: '',
'allow-half': false,
'show-value': false,
starSize: 32, // 星星的宽度, 用于实现半星
disabled: false
}
constructor() {
super();
Object.defineProperty(this, 'root', {
value: this.attachShadow({ mode: 'open' }),
writable: true,
enumerable: false,
configurable: true
})
this.root.innerHTML = `
`
this.__BOX__ = this.root.children[1]
this.__STARS__ = Array.from(this.__BOX__.children)
this.__TEXT__ = this.__STARS__.pop()
}
get value() {
return this.props.value
}
set value(val) {
var v = +val
var tmp = val >> 0
if (v === v && v > 0) {
val = v
} else {
val = 0
}
if (val > 5) {
val = 5
}
this.props.value = val
this._updateDraw(-1)
}
/**
* 更新图标渲染
* i: int
* f: float
*/
_updateDraw(i, f = 0) {
var _last = 'star-half'
var { value, tmp = { i: 0, f: 0 } } = this.props
if (i === -1) {
i = Math.floor(value)
f = +(value % 1).toFixed(1)
if (i > 0 && i === value) {
i--
f = 1
}
}
if (!this.props['allow-half']) {
f = f > 0 ? 1 : 0
}
// 减少DOM操作
if (i === tmp.i && f === tmp.f) {
return
}
if (f > 0.5) {
_last = 'star-full'
}
this.__STARS__.forEach((it, k) => {
it.setAttribute('is', k < i ? 'star-full' : 'star')
it.setAttribute('color', k < i ? this.props.color : 'grey')
})
if (f > 0) {
this.__STARS__[i].setAttribute('is', _last)
this.__STARS__[i].setAttribute('color', this.props.color)
}
// 缓存结果
this.props.tmp = { i, f }
if (i === 0 && f === 0) {
this.__TEXT__.textContent = ''
} else {
if (this.props.text.length === 5) {
this.__TEXT__.textContent = this.props.text[i]
} else {
if (this.props['show-value']) {
this.__TEXT__.textContent = i + f
}
}
}
}
connectedCallback() {
$.catch(this.__BOX__, 'mousemove', ev => {
if (this.props.disabled) {
return
}
if (ev.target.tagName === 'WC-ICON') {
let idx = +ev.target.dataset.idx
this._updateDraw(idx, +(ev.offsetX / this.props.starSize).toFixed(1))
}
})
$.catch(this.__BOX__, 'click', ev => {
var { tmp, disabled } = this.props
if (disabled) {
return
}
if (ev.target.tagName === 'WC-ICON') {
this.props.value = tmp.i + tmp.f
this.dispatchEvent(new CustomEvent('input'))
}
})
$.catch(this.__BOX__, 'mouseleave', ev => {
if (this.props.disabled) {
return
}
this._updateDraw(-1)
})
}
attributeChangedCallback(name, old, val) {
if (val === null || old === val) {return}
switch (name) {
case 'size':
this.props.starSize = this.__STARS__[0].clientWidth
break
case 'allow-half':
case 'show-value':
case 'disabled':
this.props[name] = true
break
case 'color':
if (val) {
this.props.color = val
}
break
case 'text':
if (val) {
val = val.split('|')
if (val.length === 5) {
this.props.text = val.map(it => it.trim())
}
}
break
case 'value':
this.value = val
break
}
}
}
if(!customElements.get('wc-star')){
customElements.define('wc-star', Star)
}