|
|
@@ -7,31 +7,56 @@
|
|
|
@touchmove="touchMove"
|
|
|
@touchend="touchEnd"
|
|
|
>
|
|
|
- <view class="pullrefresh-top">
|
|
|
- <template v-if="status == 'loading' && reachTop && distance > 0">
|
|
|
- 加载中...
|
|
|
- </template>
|
|
|
- <template v-if="status == 'pulling' && reachTop && distance > 0">
|
|
|
- 下拉刷新...
|
|
|
- </template>
|
|
|
- <template v-if="status == 'loosing' && reachTop && distance > 0">
|
|
|
- 释放刷新...
|
|
|
- </template>
|
|
|
+ <view
|
|
|
+ class="pullrefresh-top"
|
|
|
+ :class="
|
|
|
+ direction == 'horizontal' ? 'pullrefresh-top-h' : 'pullrefresh-top-v'
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="status == 'loading' && (reachTop || reachLeft) && distance > 0"
|
|
|
+ >{{ loadingText }}</template
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="status == 'pulling' && (reachTop || reachLeft) && distance > 0"
|
|
|
+ >{{ pullingText }}</template
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="status == 'loosing' && (reachTop || reachLeft) && distance > 0"
|
|
|
+ >{{ loosingText }}</template
|
|
|
+ >
|
|
|
</view>
|
|
|
<view class="pullrefresh-content" ref="pull">
|
|
|
<slot></slot>
|
|
|
</view>
|
|
|
|
|
|
- <view class="pullrefresh-bottom" :style="getBottomStyle">
|
|
|
- <template v-if="status == 'loading' && reachBottom && distance < 0">
|
|
|
- 加载中...
|
|
|
- </template>
|
|
|
- <template v-if="status == 'pulling' && reachBottom && distance < 0">
|
|
|
- 下拉刷新...
|
|
|
- </template>
|
|
|
- <template v-if="status == 'loosing' && reachBottom && distance < 0">
|
|
|
- 释放刷新...
|
|
|
- </template>
|
|
|
+ <view
|
|
|
+ class="pullrefresh-bottom"
|
|
|
+ :class="
|
|
|
+ direction == 'horizontal'
|
|
|
+ ? 'pullrefresh-bottom-h'
|
|
|
+ : 'pullrefresh-bottom-v'
|
|
|
+ "
|
|
|
+ :style="getBottomStyle"
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="
|
|
|
+ status == 'loading' && (reachBottom || reachRight) && distance < 0
|
|
|
+ "
|
|
|
+ >{{ loadingText }}</template
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="
|
|
|
+ status == 'pulling' && (reachBottom || reachRight) && distance < 0
|
|
|
+ "
|
|
|
+ >{{ pullingText }}</template
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ v-if="
|
|
|
+ status == 'loosing' && (reachBottom || reachRight) && distance < 0
|
|
|
+ "
|
|
|
+ >{{ loosingText }}</template
|
|
|
+ >
|
|
|
</view>
|
|
|
</view>
|
|
|
</template>
|
|
|
@@ -52,6 +77,28 @@ export default create({
|
|
|
containerId: {
|
|
|
type: String,
|
|
|
default: ''
|
|
|
+ },
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ /** 方向 Horizontal */
|
|
|
+ direction: {
|
|
|
+ type: String,
|
|
|
+ default: 'vertical'
|
|
|
+ },
|
|
|
+
|
|
|
+ pullingText: {
|
|
|
+ type: String,
|
|
|
+ default: '下拉刷新'
|
|
|
+ },
|
|
|
+ loosingText: {
|
|
|
+ type: String,
|
|
|
+ default: '松手释放刷新'
|
|
|
+ },
|
|
|
+ loadingText: {
|
|
|
+ type: String,
|
|
|
+ default: '加载中...'
|
|
|
}
|
|
|
},
|
|
|
components: {},
|
|
|
@@ -60,11 +107,14 @@ export default create({
|
|
|
setup(props, { emit }) {
|
|
|
console.log('componentName', componentName);
|
|
|
|
|
|
- const { containerId, useWindow } = toRefs(props);
|
|
|
+ const { containerId, useWindow, direction, disabled } = toRefs(props);
|
|
|
|
|
|
const reachTop = ref(false);
|
|
|
const reachBottom = ref(false);
|
|
|
|
|
|
+ const reachLeft = ref(false);
|
|
|
+ const reachRight = ref(false);
|
|
|
+
|
|
|
const state = reactive({
|
|
|
status: 'normal',
|
|
|
distance: 0,
|
|
|
@@ -78,10 +128,12 @@ export default create({
|
|
|
|
|
|
const getStyle = computed(() => {
|
|
|
let style: CSSProperties = {};
|
|
|
-
|
|
|
+ const { deltaY, deltaX } = touch;
|
|
|
if (
|
|
|
- (reachTop.value && touch.deltaY.value > 0 && touch.isVertical()) ||
|
|
|
- (reachBottom.value && touch.deltaY.value < 0 && touch.isVertical())
|
|
|
+ direction.value == 'vertical' &&
|
|
|
+ ((reachTop.value && deltaY.value > 0) ||
|
|
|
+ (reachBottom.value && deltaY.value < 0)) &&
|
|
|
+ touch.isVertical()
|
|
|
) {
|
|
|
style = {
|
|
|
transitionDuration: `${state.duration}ms`,
|
|
|
@@ -90,20 +142,53 @@ export default create({
|
|
|
: `translate3d(0,0,0)`
|
|
|
};
|
|
|
}
|
|
|
+ if (
|
|
|
+ direction.value == 'horizontal' &&
|
|
|
+ ((reachLeft.value && deltaX.value > 0) ||
|
|
|
+ (reachRight.value && deltaX.value < 0)) &&
|
|
|
+ touch.isHorizontal()
|
|
|
+ ) {
|
|
|
+ style = {
|
|
|
+ transitionDuration: `${state.duration}ms`,
|
|
|
+ transform: state.distance
|
|
|
+ ? `translate3d(${state.distance}px, 0,0)`
|
|
|
+ : `translate3d(0,0,0)`
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
return style;
|
|
|
});
|
|
|
|
|
|
const getBottomStyle = computed(() => {
|
|
|
let style: CSSProperties = {};
|
|
|
- if (reachBottom.value && touch.deltaY.value < 0 && touch.isVertical()) {
|
|
|
+ if (
|
|
|
+ direction.value == 'vertical' &&
|
|
|
+ reachBottom.value &&
|
|
|
+ touch.deltaY.value < 0 &&
|
|
|
+ touch.isVertical()
|
|
|
+ ) {
|
|
|
const dis = Math.abs(state.distance) < 50 ? -state.distance : 50;
|
|
|
style = {
|
|
|
height: dis + 'px'
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+ if (
|
|
|
+ direction.value == 'horizontal' &&
|
|
|
+ reachRight.value &&
|
|
|
+ touch.deltaX.value < 0 &&
|
|
|
+ touch.isVertical()
|
|
|
+ ) {
|
|
|
+ const dis = Math.abs(state.distance) < 50 ? -state.distance : 50;
|
|
|
+ style = {
|
|
|
+ width: dis + 'px'
|
|
|
+ };
|
|
|
+ }
|
|
|
return style;
|
|
|
});
|
|
|
|
|
|
+ const isTouchable = () => state.status !== 'loading' && !disabled.value;
|
|
|
+
|
|
|
const setStatus = (distance: number, isLoading?: boolean) => {
|
|
|
state.distance = distance;
|
|
|
|
|
|
@@ -157,54 +242,100 @@ export default create({
|
|
|
};
|
|
|
|
|
|
const touchStart = event => {
|
|
|
- /** 判断滚动条是否在顶部 */
|
|
|
- const top = 'scrollTop' in scrollEl ? scrollEl.scrollTop : 0;
|
|
|
- reachTop.value = Math.max(top, 0) == 0 ? true : false;
|
|
|
-
|
|
|
- if (reachTop.value) {
|
|
|
- state.duration = 0;
|
|
|
- touch.start(event);
|
|
|
- }
|
|
|
-
|
|
|
- const { scrollHeight, clientHeight, scrollTop } = scrollEl;
|
|
|
-
|
|
|
- /** 判断滚动条是否在底部*/
|
|
|
- reachBottom.value =
|
|
|
- clientHeight + scrollTop == scrollHeight ? true : false;
|
|
|
-
|
|
|
- if (reachBottom.value) {
|
|
|
- state.duration = 0;
|
|
|
- touch.start(event);
|
|
|
+ if (isTouchable()) {
|
|
|
+ if (direction.value == 'vertical') {
|
|
|
+ /** 判断滚动条是否在顶部 */
|
|
|
+ const top = 'scrollTop' in scrollEl ? scrollEl.scrollTop : 0;
|
|
|
+ reachTop.value = Math.max(top, 0) == 0 ? true : false;
|
|
|
+
|
|
|
+ /** 判断滚动条是否在底部*/
|
|
|
+ const { scrollHeight, clientHeight, scrollTop } = scrollEl;
|
|
|
+ reachBottom.value =
|
|
|
+ clientHeight + scrollTop == scrollHeight ? true : false;
|
|
|
+
|
|
|
+ if (reachTop.value || reachBottom.value) {
|
|
|
+ state.duration = 0;
|
|
|
+ touch.start(event);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const { scrollWidth, clientWidth, scrollLeft } = scrollEl;
|
|
|
+ /** 判断滚动条是否在左边 */
|
|
|
+ const left = 'scrollLeft' in scrollEl ? scrollEl.scrollLeft : 0;
|
|
|
+ reachLeft.value = Math.max(left, 0) == 0 ? true : false;
|
|
|
+
|
|
|
+ /** 判断滚动条是否在右边 */
|
|
|
+ reachRight.value =
|
|
|
+ clientWidth + scrollLeft == scrollWidth ? true : false;
|
|
|
+
|
|
|
+ if (reachLeft.value || reachRight.value) {
|
|
|
+ state.duration = 0;
|
|
|
+ touch.start(event);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const touchMove = event => {
|
|
|
- const { deltaY } = touch;
|
|
|
-
|
|
|
- touch.move(event);
|
|
|
- if (reachTop.value && deltaY.value >= 0 && touch.isVertical()) {
|
|
|
- preventDefault(event);
|
|
|
- setStatus(ease(deltaY.value));
|
|
|
- }
|
|
|
+ if (isTouchable()) {
|
|
|
+ const { deltaY, deltaX } = touch;
|
|
|
+ touch.move(event);
|
|
|
+
|
|
|
+ if (
|
|
|
+ direction.value == 'vertical' &&
|
|
|
+ ((reachBottom.value && deltaY.value < 0) ||
|
|
|
+ (reachTop.value && deltaY.value >= 0)) &&
|
|
|
+ touch.isVertical()
|
|
|
+ ) {
|
|
|
+ preventDefault(event);
|
|
|
+ setStatus(ease(deltaY.value));
|
|
|
+ }
|
|
|
|
|
|
- if (reachBottom.value && deltaY.value < 0 && touch.isVertical()) {
|
|
|
- preventDefault(event);
|
|
|
- setStatus(ease(deltaY.value));
|
|
|
+ if (
|
|
|
+ direction.value == 'horizontal' &&
|
|
|
+ ((reachLeft.value && deltaX.value >= 0) ||
|
|
|
+ (reachRight.value && deltaX.value < 0)) &&
|
|
|
+ touch.isHorizontal()
|
|
|
+ ) {
|
|
|
+ preventDefault(event);
|
|
|
+ setStatus(ease(deltaX.value));
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
const touchEnd = () => {
|
|
|
- if (reachTop.value && touch.deltaY.value > 0) {
|
|
|
- if (state.status === 'loosing') {
|
|
|
- setStatus(50, true);
|
|
|
- emit('refresh', refreshDone);
|
|
|
- } else {
|
|
|
- setStatus(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (reachBottom.value && touch.deltaY.value < 0) {
|
|
|
+ if (isTouchable()) {
|
|
|
+ const { deltaY, deltaX } = touch;
|
|
|
if (state.status === 'loosing') {
|
|
|
- setStatus(-50, true);
|
|
|
+ let dis = 0;
|
|
|
+
|
|
|
+ if (
|
|
|
+ direction.value == 'vertical' &&
|
|
|
+ reachTop.value &&
|
|
|
+ deltaY.value > 0
|
|
|
+ ) {
|
|
|
+ dis = 50;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ direction.value == 'vertical' &&
|
|
|
+ reachBottom.value &&
|
|
|
+ deltaY.value < 0
|
|
|
+ ) {
|
|
|
+ dis = -50;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ direction.value == 'horizontal' &&
|
|
|
+ reachLeft.value &&
|
|
|
+ deltaX.value > 0
|
|
|
+ ) {
|
|
|
+ dis = 50;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ direction.value == 'horizontal' &&
|
|
|
+ reachRight.value &&
|
|
|
+ deltaX.value < 0
|
|
|
+ ) {
|
|
|
+ dis = -50;
|
|
|
+ }
|
|
|
+ setStatus(dis, true);
|
|
|
emit('refresh', refreshDone);
|
|
|
} else {
|
|
|
setStatus(0);
|
|
|
@@ -219,6 +350,8 @@ export default create({
|
|
|
getStyle,
|
|
|
reachBottom,
|
|
|
reachTop,
|
|
|
+ reachRight,
|
|
|
+ reachLeft,
|
|
|
getBottomStyle,
|
|
|
...toRefs(state)
|
|
|
};
|