diff --git a/src/pull-refresh/index.js b/src/pull-refresh/index.js index f498925b4..acf092897 100644 --- a/src/pull-refresh/index.js +++ b/src/pull-refresh/index.js @@ -1,10 +1,13 @@ +import { ref, watch, reactive, nextTick } from 'vue'; + // Utils import { createNamespace } from '../utils'; +import { getScrollTop } from '../utils/dom/scroll'; import { preventDefault } from '../utils/dom/event'; -import { getScrollTop, getScroller } from '../utils/dom/scroll'; -// Mixins -import { TouchMixin } from '../mixins/touch'; +// Composition +import { useTouch } from '../composition/use-touch'; +import { useScroller } from '../composition/use-scroller'; // Components import Loading from '../loading'; @@ -15,8 +18,6 @@ const DEFAULT_HEAD_HEIGHT = 50; const TEXT_STATUS = ['pulling', 'loosing', 'success']; export default createComponent({ - mixins: [TouchMixin], - props: { disabled: Boolean, successText: String, @@ -43,104 +44,36 @@ export default createComponent({ emits: ['refresh', 'update:modelValue'], - data() { - return { + setup(props, { emit, slots }) { + let reachTop; + + const rootRef = ref(); + const scroller = useScroller(rootRef); + + const state = reactive({ status: 'normal', distance: 0, duration: 0, - }; - }, + }); - computed: { - touchable() { - return ( - this.status !== 'loading' && this.status !== 'success' && !this.disabled - ); - }, + const touch = useTouch(); + const { deltaY, direction } = touch; - headStyle() { - if (this.headHeight !== DEFAULT_HEAD_HEIGHT) { + const getHeadStyle = () => { + if (props.headHeight !== DEFAULT_HEAD_HEIGHT) { return { - height: `${this.headHeight}px`, + height: `${props.headHeight}px`, }; } - }, - }, + }; - watch: { - modelValue(loading) { - this.duration = this.animationDuration; + const isTouchable = () => + state.status !== 'loading' && + state.status !== 'success' && + !props.disabled; - if (loading) { - this.setStatus(+this.headHeight, true); - } else if ( - this.$slots.success ? this.$slots.success() : this.successText - ) { - this.showSuccessTip(); - } else { - this.setStatus(0, false); - } - }, - }, - - mounted() { - this.bindTouchEvent(this.$refs.track); - this.scrollEl = getScroller(this.$el); - }, - - methods: { - checkPullStart(event) { - this.ceiling = getScrollTop(this.scrollEl) === 0; - - if (this.ceiling) { - this.duration = 0; - this.touchStart(event); - } - }, - - onTouchStart(event) { - if (this.touchable) { - this.checkPullStart(event); - } - }, - - onTouchMove(event) { - if (!this.touchable) { - return; - } - - if (!this.ceiling) { - this.checkPullStart(event); - } - - this.touchMove(event); - - if (this.ceiling && this.deltaY >= 0 && this.direction === 'vertical') { - preventDefault(event); - this.setStatus(this.ease(this.deltaY)); - } - }, - - onTouchEnd() { - if (this.touchable && this.ceiling && this.deltaY) { - this.duration = this.animationDuration; - - if (this.status === 'loosing') { - this.setStatus(+this.headHeight, true); - this.$emit('update:modelValue', true); - - // ensure value change can be watched - this.$nextTick(() => { - this.$emit('refresh'); - }); - } else { - this.setStatus(0); - } - } - }, - - ease(distance) { - const headHeight = +this.headHeight; + const ease = (distance) => { + const headHeight = +props.headHeight; if (distance > headHeight) { if (distance < headHeight * 2) { @@ -151,34 +84,31 @@ export default createComponent({ } return Math.round(distance); - }, + }; + + const setStatus = (distance, isLoading) => { + state.distance = distance; - setStatus(distance, isLoading) { - let status; if (isLoading) { - status = 'loading'; + state.status = 'loading'; } else if (distance === 0) { - status = 'normal'; + state.status = 'normal'; + } else if (distance < props.headHeight) { + state.status = 'pulling'; } else { - status = distance < this.headHeight ? 'pulling' : 'loosing'; + state.status = 'loosing'; } + }; - this.distance = distance; + const renderStatus = () => { + const { status, distance } = state; - if (status !== this.status) { - this.status = status; - } - }, - - genStatus() { - const { status, distance } = this; - - if (this.$slots[status]) { - return this.$slots[status]({ distance }); + if (slots[status]) { + return slots[status]({ distance }); } const nodes = []; - const text = (status !== 'normal' && this[`${status}Text`]) || t(status); + const text = (status !== 'normal' && props[`${status}Text`]) || t(status); if (TEXT_STATUS.indexOf(status) !== -1) { nodes.push(