完成评分组件

master
yutent 2023-03-30 19:04:30 +08:00
parent 4107ef484c
commit 48c9b0d9bd
5 changed files with 208 additions and 11 deletions

View File

@ -30,7 +30,7 @@
- [x] `wc-passwd`表单组件-文本输入框 - [x] `wc-passwd`表单组件-文本输入框
- [x] `wc-textarea`表单组件-多行文本输入框 - [x] `wc-textarea`表单组件-多行文本输入框
- [x] `wc-number`表单组件-步进数字输入 - [x] `wc-number`表单组件-步进数字输入
- [ ] `wc-star`表单组件-评分 - [x] `wc-star`表单组件-评分
- [x] `wc-radio`表单组件-单选框 - [x] `wc-radio`表单组件-单选框
- [ ] `wc-select`表单组件-下拉选择 - [ ] `wc-select`表单组件-下拉选择
- [ ] `wc-cascadar`表单组件-多级联动 - [ ] `wc-cascadar`表单组件-多级联动

View File

@ -111,11 +111,6 @@ class Button extends Component {
w: 192px, w: 192px,
h: 52px, h: 52px,
f: 16px f: 16px
),
xxxxl: (
w: 212px,
h: 64px,
f: 18px
) )
); );

204
src/form/star.js Normal file
View File

@ -0,0 +1,204 @@
/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/03/21 16:14:10
*/
import { nextTick, css, html, Component, classMap } from '@bd/core'
import '../icon/index.js'
class Star extends Component {
static props = {
value: 0,
text: [],
size: 'l',
colors: [],
'allow-half': false,
'show-value': false,
disabled: false,
clearable: false
}
static styles = [
css`
:host {
display: flex;
font-size: 14px;
--size: 32px;
cursor: pointer;
user-select: none;
}
label {
display: flex;
align-items: center;
line-height: 1;
color: let(--color-grey-1);
cursor: inherit;
wc-icon {
margin: 0 3px;
transition: transform 0.15s linear, color 0.15s linear;
&[name='star'] {
color: let(--color-plain-3);
}
&[name='star-full'],
&[name='star-half'] {
color: let(--color-teal-1);
}
&:hover {
transform: scale(1.05);
}
}
span {
padding: 2px 8px 0;
margin: 0 6px;
}
}
`,
// 尺寸
css`
@use 'sass:map';
$sizes: (
s: (
w: 52px,
h: 20px,
f: 12px
),
m: (
w: 72px,
h: 24px,
f: 12px
),
l: (
w: 108px,
h: 32px,
f: 14px
)
);
@loop $s, $v in $sizes {
:host([size='#{$s}']) {
--size: #{map.get($v, 'h')};
font-size: map.get($v, 'f');
}
}
`
]
#width = 32
#value = { i: 0, f: 0 }
#stars = []
/**
* 更新图标渲染
* i: int
* f: float
*/
#updateDraw(i, f = 0) {
let _last = 'star-half'
let value = this.value
let tmp = this.#value
if (i === -1) {
i = Math.floor(value)
f = +(value % 1).toFixed(1)
if (i > 0 && i === value) {
i--
f = 1
}
} else {
f = f < 0.5 ? 0.5 : 1
}
if (!this['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.name = k < i ? 'star-full' : 'star'
it.style.color = k < i ? this.color || 'var(--color-teal-1)' : ''
})
if (f > 0) {
this.#stars[i].name = _last
this.#stars[i].style.color = this.color || 'var(--color-teal-1)'
}
// 缓存结果
this.#value = { i, f }
}
handleMove(ev) {
if (this.disabled) {
return
}
if (ev.target.tagName === 'WC-ICON') {
let idx = +ev.target.dataset.idx
this.#updateDraw(idx, +(ev.offsetX / this.#width).toFixed(1))
}
}
handleLeave() {
if (this.disabled) {
return
}
this.#updateDraw(-1)
}
handleClick(ev) {
let tmp = this.#value
if (this.disabled) {
return
}
if (ev.target.tagName === 'WC-ICON') {
if (this.clearable && this.value === tmp.i + tmp.f) {
tmp.i = 0
tmp.f = 0
this.value = 0
this.#stars.forEach(it => ((it.name = 'star'), (it.style.color = '')))
} else {
this.value = tmp.i + tmp.f
}
this.$emit('change', { value: this.value })
}
}
mounted() {
this.#stars = [...this.$refs.box.children]
this.#width = this.#stars[0].clientWidth
}
render() {
return html`
<label
ref="box"
@mousemove=${this.handleMove}
@mouseleave=${this.handleLeave}
@click=${this.handleClick}
>
<wc-icon data-idx="0" name="star"></wc-icon>
<wc-icon data-idx="1" name="star"></wc-icon>
<wc-icon data-idx="2" name="star"></wc-icon>
<wc-icon data-idx="3" name="star"></wc-icon>
<wc-icon data-idx="4" name="star"></wc-icon>
<span class="text">${this['show-value'] ? this.value : ''}</span>
</label>
`
}
}
Star.reg('star')

View File

@ -57,8 +57,7 @@ class Icon extends Component {
'l': 32px, 'l': 32px,
'xl': 36px, 'xl': 36px,
'xxl': 44px, 'xxl': 44px,
'xxxl': 52px, 'xxxl': 52px
'xxxxl': 64px
); );
@loop $k, $v in $gaps { @loop $k, $v in $gaps {

View File

@ -13,15 +13,14 @@
- `type=help` 灰色 - `type=help` 灰色
3. 尺寸, 主要指 高度 3. 尺寸, 主要指 高度
> 需要注意的是, 这里的高度, 仅为组件本身应该占的高度, 而非"可视内容"的真实高度, 比如 开按钮, 实际上就可以不需要那么大。 > 需要注意的是, 这里的高度, 仅为组件本身应该占的高度, 而非"可视内容"的真实高度, 比如 开按钮, 实际上就可以不需要那么大。
- `size=s` 小号, 20px - `size=s` 小号, 20px
- `size=m` 中号, 24px - `size=m` 中号, 24px
- `size=l` 大号, 32px (默认值) - `size=l` 大号, 32px (默认值)
- `size=xl` 加大号, 36px - `size=xl` 加大号, 36px
- `size=xxl` 加加大号, 44px - `size=xxl` 加加大号, 44px
- `size=xxxl` 加加加加大号, 52px - `size=xxxl` 加加加大号, 52px
- `size=xxxxl` 特大号, 64px
4. 自带点击事件的组件, 统一增加"节流/防抖"逻辑 4. 自带点击事件的组件, 统一增加"节流/防抖"逻辑
> 统一为增加 `lazy="1000"` 属性实现 > 统一为增加 `lazy="1000"` 属性实现