@mypui/myp-ui
Version:
第一个高效且强悍的nvue开源组件库。做最好、最顺手的nvue组件库
272 lines (263 loc) • 9.02 kB
JavaScript
// #ifndef APP-NVUE
import {getTouchPoint} from '../utils/element.js'
// #endif
export default {
data() {
return {
// #ifdef APP-NVUE
platform: '',
// #endif
// #ifndef APP-NVUE
mypScrollable: true,
mypDownHeight: 0,
mypStartPoint: null,
mypLastPoint: null,
mypTheScrollHeight: 0, // scroll content height
mypTheScrollTop: 0, // 记录滚动条的位置,并不是用来重置scrolltop
mypStartTop: 0, // 记录开始时滚动条的位置
mypInTouchend: false,
mypPreScrollY: 0,
// 节流设置
mypFps: 40, // 1s内屏幕刷新的频数
mypMoveTime: 0,
mypMoveTimeDiff: 0,
mypScrollTopDeviation: 100, // scroll-view滚动到顶部时,此时的scroll-top不一定为0, 此值用于控制最大的误差
mypIsMoveDown: false,
mypDownMoveType: 0,
mypIsDownReset: false, // 下拉刷新,是否显示重置的过渡动画
// #endif
mypIsDownLoading: false, // 是否正在下拉刷新中
mypIsUpLoading: false, // 是否正在上提加载
// down
mypDown: {
use: true,
offset: uni.upx2px(140),
inRate: 0.8, // 下拉的距离小于offset时,改变下拉区域高度比例;0-1,越小,越难拉
outRate: 0.2 // 下拉的距离大于offset时,改变下拉区域高度比例;0-1,越小,越难拉
},
// up
mypUp: {
use: true,
offset: 80
},
mypHasMore: true,
// u need to manage the page-state yourself, we do not manage the page-state for u
mypCurrentPage: 0, // start with 0. if > 0, it means data inited
mypPrePage: 0
}
},
// #ifndef APP-NVUE
computed: {
mypMrScrollContentStyle() {
let _style = 'position: relative;'
_style += this.mypIsDownReset ? 'transition-property: transform; transition-duration: 300ms;' : ''
_style += this.mypDownHeight > 0 ? `transform: translateY(${this.mypDownHeight}px);` : ''
return _style
},
mypMrRefreshStyle() {
return 'position: absolute; transform: translateY(-100%); left:0;'
},
mypCouldUnLash() {
return this.mypDownHeight >= (this.mypDown.offset || 80)
},
mypDownRate() {
return this.mypDownHeight / (this.mypDown.offset || 80)
}
},
// #endif
methods: {
// #ifndef APP-NVUE
// 手指开始触摸屏幕
mypTouchstartEvent(e) {
this.mypStartPoint = getTouchPoint(e)
this.mypStartTop = this.mypTheScrollTop || 0
this.mypLastPoint = this.mypStartPoint
this.mypInTouchend = false
},
// 手指在屏幕上滑动
// 注意:是手指位置的变化触发的。在scroll中,手指拖动scroll滚动,其实手指位置不变,scroll的滚动是不会触发touchmove的
mypTouchmoveEvent(e) {
if (!this.mypDown.use) return;
if (!this.mypStartPoint) return;
// 限制/节流,可以使用时间,也可以使用高度
// 小于节流时间,则不处理
const t = new Date().getTime();
if (this.mypMoveTime && t - this.mypMoveTime < this.mypMoveTimeDiff) {
return;
} else {
this.mypMoveTime = t
this.mypMoveTimeDiff = 1000 / this.mypFps
}
const scrollTop = this.mypTheScrollTop
const currentPoint = getTouchPoint(e)
const moveY = currentPoint.y - this.mypStartPoint.y
// (向下拉&&在顶部) scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove
// scroll-view滚动到顶部时,scrollTop不一定为0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等
if (moveY > 0 && (scrollTop <= 0 || (scrollTop <= this.mypScrollTopDeviation && scrollTop === this.mypStartTop))) {
// 是否可以下拉
if (!this.mypInTouchend && !this.mypIsDownLoading && !this.mypIsUpLoading) {
let diff = currentPoint.y - this.mypLastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上)
// 下拉距离 < 指定距离
if (this.mypDownHeight < this.mypDown.offset) {
if (this.mypDownMoveType !== 1) {
this.mypDownMoveType = 1; // 加入标记,保证只执行一次
this.mypDownInOffset() // 进入指定距离范围内那一刻的回调,只执行一次
this.mypIsMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
}
this.mypDownHeight += diff * this.mypDown.inRate; // 越往下,高度变化越小
// 下拉距离 >= 指定距离
} else {
if (this.mypDownMoveType !== 2) {
this.mypDownMoveType = 2; // 加入标记,保证只执行一次
this.mypDownOutOffset(); // 下拉超过指定距离那一刻的回调,只执行一次
this.mypIsMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来
}
if (diff > 0) { // 向下拉
this.mypDownHeight += Math.round(diff * this.mypDown.outRate); // 越往下,高度变化越小
} else { // 向上收
this.mypDownHeight += diff; // 向上收回高度,则向上滑多少收多少高度
}
}
const rate = this.mypDownHeight / this.mypDown.offset; // 下拉区域当前高度与指定距离的比值
this.mypOnDownMoving(rate, this.mypDownHeight) // 下拉过程中的回调,一直在执行
}
}
this.mypLastPoint = currentPoint
},
// 手指移开屏幕
mypTouchendEvent(e) {
// 如果下拉区域高度已改变,则需重置回来
if (this.mypIsMoveDown) {
if (this.mypDownHeight >= this.mypDown.offset) {
// 符合触发刷新的条件
this.mypTriggerDownScroll()
} else {
// 不符合的话 则重置
this.mypDownHeight = 0;
this.mypEndDownScroll()
}
this.mypDownMoveType = 0;
this.mypIsMoveDown = false;
} else if (this.mypTheScrollTop === this.mypStartTop) { // 到顶/左/右/底的滑动事件
const isScrollUp = getTouchPoint(e).y - this.mypStartPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉
// 上滑 && 检查并触发上拉
isScrollUp && this.mypTriggerUpScroll();
}
},
// scrollview滚动事件
mypScroll(e) {
this.$emit('scroll', e)
this.mypTheScrollTop = e.detail.scrollTop
this.mypTheScrollHeight = e.detail.scrollHeight
// 向上滑还是向下滑动
const isScrollUp = e.detail.scrollTop - this.mypPreScrollY > 0;
this.mypPreScrollY = e.detail.scrollTop;
// 上滑 && 检查并触发上拉
isScrollUp && this.mypTriggerUpScroll();
if (this.mypCurrentView) {
this.mypCurrentView = null
}
},
// 进入下拉区域的那一刻
mypDownInOffset() {
this.mypScrollable = false
this.mypIsDownReset = false
this.mypIsDownLoading = false
},
// 超出下拉区域的那一刻
mypDownOutOffset() {
this.mypScrollable = false
this.mypIsDownReset = false
this.mypIsDownLoading = false
},
// 正在下拉的回调
mypOnDownMoving(rate, downHeight) {
},
mypRefresh() {
this.mypPrePage = this.mypCurrentPage
this.mypCurrentPage = 1
this.mypGetContentList('refresh')
},
mypLoad() {
this.mypPrePage = this.mypCurrentPage
this.mypCurrentPage += 1
this.mypGetContentList('load')
},
mypReload() {
this.mypPrePage = this.mypCurrentPage
this.mypCurrentPage = 1
this.mypGetContentList('load')
},
mypInitContentList() {
this.mypPrePage = 0
this.mypCurrentPage = 1
this.mypGetContentList('refresh')
},
mypGetContentList(type='refresh') {
if (type === 'refresh') {
this.$emit('down')
} else {
this.$emit('up')
}
},
// 刷新
mypTriggerDownScroll() {
this.mypScrollable = true
this.mypIsDownReset = true
this.mypIsDownLoading = true
this.mypDownHeight = this.mypDown.offset
this.mypRefresh()
},
mypEndDownScroll() {
this.mypScrollable = true
this.mypIsDownReset = true
this.mypIsDownLoading = false
this.mypDownHeight = 0
},
// 加载更多
mypTriggerUpScroll() {
if (this.mypIsDownLoading || this.mypIsUpLoading || !this.mypHasMore || !this.mypUp.use) return;
let canUp = false
// we should check if reached bottom
if (this.mypGetScrollBottom() <= this.mypUp.offset) { // 到底部
canUp = true; // 标记可上拉
}
if (!canUp) return;
this.mypIsUpLoading = true
this.mypLoad()
},
mypEndUpScroll() {
this.mypIsUpLoading = false
},
mypEndSuccess(hasMore=true) {
this.mypHasMore = hasMore
if (this.mypIsDownLoading) {
this.mypEndDownScroll()
}
if (this.mypIsUpLoading) {
this.mypEndUpScroll()
}
},
// 下拉刷新/上提加载,失败之后使用
mypEndError() {
// reback the current page
this.mypCurrentPage = this.mypPrePage
if (this.mypIsDownLoading) {
this.mypEndDownScroll()
}
if (this.mypIsUpLoading) {
this.mypEndUpScroll()
}
},
mypGetScrollBottom() {
// important!
// if u want to use this mixin, u must supply a mypScrollHeight in your props or computed or data
let contentHeight = this.mypScrollHeight
if (this.mypTheScrollHeight > 0) {
contentHeight = this.mypTheScrollHeight
}
return contentHeight - this.mypTheScrollTop - this.mypScrollHeight
}
// #endif
}
}