refactor(Rate): refactor with composition api

This commit is contained in:
chenjiahan 2020-08-27 14:20:37 +08:00
parent 5aa092519a
commit 67f418ab07
2 changed files with 76 additions and 86 deletions

View File

@ -2,7 +2,7 @@ import { watch, inject, WatchSource, getCurrentInstance } from 'vue';
import { FIELD_KEY } from '../field'; import { FIELD_KEY } from '../field';
export function useParentField(watchSource: WatchSource) { export function useParentField(watchSource: WatchSource) {
const field = inject(FIELD_KEY) as any; const field = inject(FIELD_KEY, null) as any;
if (field && !field.children) { if (field && !field.children) {
field.children = getCurrentInstance()!.proxy; field.children = getCurrentInstance()!.proxy;

View File

@ -1,10 +1,13 @@
import { computed } from 'vue';
// Utils // Utils
import { createNamespace, addUnit } from '../utils'; import { createNamespace, addUnit } from '../utils';
import { preventDefault } from '../utils/dom/event'; import { preventDefault } from '../utils/dom/event';
// Mixins // Composition
import { TouchMixin } from '../mixins/touch'; import { useRefs } from '../composition/use-refs';
import { FieldMixin } from '../mixins/field'; import { useTouch } from '../composition/use-touch';
import { useParentField } from '../composition/use-parent-field';
// Components // Components
import Icon from '../icon'; import Icon from '../icon';
@ -15,17 +18,13 @@ function getRateStatus(value, index, allowHalf) {
if (value >= index) { if (value >= index) {
return 'full'; return 'full';
} }
if (value + 0.5 >= index && allowHalf) { if (value + 0.5 >= index && allowHalf) {
return 'half'; return 'half';
} }
return 'void'; return 'void';
} }
export default createComponent({ export default createComponent({
mixins: [TouchMixin, FieldMixin],
props: { props: {
size: [Number, String], size: [Number, String],
color: String, color: String,
@ -60,53 +59,51 @@ export default createComponent({
emits: ['change', 'update:modelValue'], emits: ['change', 'update:modelValue'],
created() { setup(props, { emit }) {
this.itemRefs = []; let ranges;
},
computed: { const touch = useTouch();
list() { const [itemRefs, setItemRefs] = useRefs();
const untouchable = () =>
props.readonly || props.disabled || !props.touchable;
const list = computed(() => {
const list = []; const list = [];
for (let i = 1; i <= this.count; i++) { for (let i = 1; i <= props.count; i++) {
list.push(getRateStatus(this.modelValue, i, this.allowHalf)); list.push(getRateStatus(props.modelValue, i, props.allowHalf));
} }
return list; return list;
}, });
sizeWithUnit() { const select = (index) => {
return addUnit(this.size); if (!props.disabled && !props.readonly && index !== props.modelValue) {
}, emit('update:modelValue', index);
emit('change', index);
gutterWithUnit() {
return addUnit(this.gutter);
},
},
mounted() {
this.bindTouchEvent(this.$el);
},
methods: {
select(index) {
if (!this.disabled && !this.readonly && index !== this.modelValue) {
this.$emit('update:modelValue', index);
this.$emit('change', index);
} }
}, };
onTouchStart(event) { const getScoreByPosition = (x) => {
if (this.readonly || this.disabled || !this.touchable) { for (let i = ranges.length - 1; i > 0; i--) {
if (x > ranges[i].left) {
return ranges[i].score;
}
}
return props.allowHalf ? 0.5 : 1;
};
const onTouchStart = (event) => {
if (untouchable()) {
return; return;
} }
this.touchStart(event); touch.start(event);
const rects = this.itemRefs.map((item) => item.getBoundingClientRect()); const rects = itemRefs.value.map((item) => item.getBoundingClientRect());
const ranges = [];
ranges = [];
rects.forEach((rect, index) => { rects.forEach((rect, index) => {
if (this.allowHalf) { if (props.allowHalf) {
ranges.push( ranges.push(
{ score: index + 0.5, left: rect.left }, { score: index + 0.5, left: rect.left },
{ score: index + 1, left: rect.left + rect.width / 2 } { score: index + 1, left: rect.left + rect.width / 2 }
@ -115,108 +112,101 @@ export default createComponent({
ranges.push({ score: index + 1, left: rect.left }); ranges.push({ score: index + 1, left: rect.left });
} }
}); });
};
this.ranges = ranges; const onTouchMove = (event) => {
}, if (untouchable()) {
onTouchMove(event) {
if (this.readonly || this.disabled || !this.touchable) {
return; return;
} }
this.touchMove(event); touch.move(event);
if (this.direction === 'horizontal') {
preventDefault(event);
if (touch.direction.value === 'horizontal') {
const { clientX } = event.touches[0]; const { clientX } = event.touches[0];
this.select(this.getScoreByPosition(clientX)); preventDefault(event);
select(getScoreByPosition(clientX));
} }
}, };
getScoreByPosition(x) { const renderStar = (status, index) => {
for (let 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(status, index) {
const { const {
icon, icon,
size,
color, color,
count, count,
gutter,
voidIcon, voidIcon,
disabled, disabled,
voidColor, voidColor,
allowHalf,
iconPrefix,
disabledColor, disabledColor,
} = this; } = props;
const score = index + 1; const score = index + 1;
const isFull = status === 'full'; const isFull = status === 'full';
const isVoid = status === 'void'; const isVoid = status === 'void';
let style; let style;
if (this.gutterWithUnit && score !== +count) { if (gutter && score !== +count) {
style = { paddingRight: this.gutterWithUnit }; style = {
paddingRight: addUnit(gutter),
};
} }
return ( return (
<div <div
key={index} key={index}
ref={(val) => { ref={setItemRefs(index)}
this.itemRefs[index] = val;
}}
role="radio" role="radio"
style={style} style={style}
class={bem('item')}
tabindex="0" tabindex="0"
aria-setsize={count} aria-setsize={count}
aria-posinset={score} aria-posinset={score}
aria-checked={String(!isVoid)} aria-checked={String(!isVoid)}
class={bem('item')}
> >
<Icon <Icon
size={this.sizeWithUnit} size={size}
name={isFull ? icon : voidIcon} name={isFull ? icon : voidIcon}
class={bem('icon', { disabled, full: isFull })} class={bem('icon', { disabled, full: isFull })}
color={disabled ? disabledColor : isFull ? color : voidColor} color={disabled ? disabledColor : isFull ? color : voidColor}
classPrefix={this.iconPrefix} classPrefix={iconPrefix}
data-score={score} data-score={score}
onClick={() => { onClick={() => {
this.select(score); select(score);
}} }}
/> />
{this.allowHalf && ( {allowHalf && (
<Icon <Icon
size={this.sizeWithUnit} size={size}
name={isVoid ? voidIcon : icon} name={isVoid ? voidIcon : icon}
class={bem('icon', ['half', { disabled, full: !isVoid }])} class={bem('icon', ['half', { disabled, full: !isVoid }])}
color={disabled ? disabledColor : isVoid ? voidColor : color} color={disabled ? disabledColor : isVoid ? voidColor : color}
classPrefix={this.iconPrefix} classPrefix={iconPrefix}
data-score={score - 0.5} data-score={score - 0.5}
onClick={() => { onClick={() => {
this.select(score - 0.5); select(score - 0.5);
}} }}
/> />
)} )}
</div> </div>
); );
}, };
},
render() { useParentField(() => props.modelValue);
return (
return () => (
<div <div
role="radiogroup"
class={bem({ class={bem({
readonly: this.readonly, readonly: props.readonly,
disabled: this.disabled, disabled: props.disabled,
})} })}
tabindex="0" tabindex="0"
role="radiogroup" onTouchstart={onTouchStart}
onTouchmove={onTouchMove}
> >
{this.list.map((status, index) => this.genStar(status, index))} {list.value.map(renderStar)}
</div> </div>
); );
}, },