123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- <template>
- <view class="k-scroll-view" ref="k-scroll-view" :style="[scrollContainerStyle]" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend" @touchcancel="touchcancel">
- <view v-if="refreshType === 'native' && showPullDown" class="native-refresh-icon" :style="[{ top: `${moveY}px` }]" :class="[{ xuanzhun: doRefreshing }]">
- <text class="my-icons-custom icon-jiantou-refresh" style="color: #52A63A;font-size: 14px;"></text>
- </view>
- <view class="scroll-load-refresh" v-if="refreshType === 'custom' && showPullDown">
- <text class="my-icons-custom icon-jiazai xuanzhun" v-if="refreshText === loadingTip" style="color: #52A63A;font-size: 60rpx;"></text>
- {{ refreshText }}
- </view>
- <view class="go-to-top-icon" v-if="old.scrollTop > 20" @tap="goTop"><text class="my-icons-custom icon-jiantou-up" style="color: #4cd964;font-size: 40rpx;"></text></view>
- <view class="scroll-load-more" v-if="showPullUp">
- <view class="translate-line" v-if="onPullUpText === loadingTip">
- <view class="line"></view>
- <view class="line"></view>
- <view class="line"></view>
- <view class="line"></view>
- <view class="line"></view>
- <view class="line"></view>
- </view>
- {{ onPullUpText }}
- </view>
- <scroll-view
- class="scroll-Y"
- scroll-y="true"
- :style="[scrollContentStyle]"
- :scroll-top="scrollTop"
- :lower-threshold="bottom"
- @scrolltoupper="upper"
- @scrolltolower="lower"
- @scroll="scroll"
- >
- <view class="scroll-content">
- <slot></slot>
- <view class="empty-tips" v-if="showEmpty">{{ emptyTip }}</view>
- </view>
- </scroll-view>
- </view>
- </template>
- <script>
- /**
- * 封装 下拉刷新,上拉加载
- */
- export default {
- name: 'k-scroll-view',
- components: {},
- props: {
- refreshType: {
- type: String,
- default: 'custom'
- },
- refreshTip: {
- type: String,
- default: '正在下拉'
- },
- loadTip: {
- type: String,
- default: '获取更多数据'
- },
- loadingTip: {
- type: String,
- default: '正在加载中...'
- },
- emptyTip: {
- type: String,
- default: '--我是有底线的--'
- },
- touchHeight: {
- type: Number,
- default: 50
- },
- height: Number,
- bottom: {
- // 和底部距离多远,执行触底方法(用来预加载)
- type: Number,
- default: 50
- },
- autoPullUp: {
- // 是否自动上拉
- type: [String, Boolean],
- default: true
- },
- stopPullDown: {
- // 禁用下拉
- type: [String, Boolean],
- default: true
- }
- },
- data() {
- return {
- scrollTop: 0,
- old: {
- scrollTop: 0
- },
- touch_start: {
- x: '',
- y: ''
- }, // 手指起始位置
- touch_end: {
- x: '',
- y: ''
- }, // 手指位置
- touch_direction: '', // 手指移动方向
- isInTop: true, // 是否在顶部
- isInBottom: false, // 是否在底部
- showPullDown: false, // 是否显示下拉刷新
- showPullUp: false, // 是否显示上拉加载
- showEmpty: false, // 显示无数据
- refreshText: '下拉刷新', // 下拉刷新提示文字
- onPullUpText: '上拉加载', // 上拉加载 提示文字
- pullDownCanDo: false, // 是否可以调用刷新
- pullUpCanDo: false, // 是否可以调用加载
- moveY: 0,
- doRefreshing: false, // 开始刷新
- doLoadmore: false, // 开始上拉加载
- isCloseTip: true, // 是否关闭了提示
- hasMove: false
- };
- },
- computed: {
- scrollContainerStyle() {
- return {
- height: `${this.height || this.height_}rpx`
- };
- },
- scrollContentStyle() {
- return {
- // height: `${this.height || this.height_}rpx`
- };
- }
- },
- watch: {},
- created() {
- const that = this;
- uni.getSystemInfo({
- success: function(e) {
- that.height_ = (750 / e.windowWidth) * e.windowHeight;
- }
- });
- },
- mounted() {},
- destroyed() {},
- methods: {
- scroll: function(e) {
- this.touch_direction = '';
- this.pullDownCanDo = false;
- this.pullUpCanDo = false;
- this.hasMove = true;
- this.old.scrollTop = e.detail.scrollTop;
- this.$emit('@onScroll', this.old.scrollTop);
- if (this.old.scrollTop === 0) {
- this.isInTop = true;
- } else {
- this.isInTop = false;
- }
- },
- upper: function(e) {
- // console.log("到达顶部")
- this.isInBottom = false;
- this.isInTop = true;
- },
- lower: function(e) {
- // console.log("到达底部")
- this.isInBottom = true;
- this.isInTop = false;
- // 开启自动上拉
- if (this.autoPullUp && this.autoPullUp !== 'false') {
- this.onPullUp();
- }
- },
- goTop: function(e) {
- // 回到顶部
- this.scrollTop = this.old.scrollTop;
- this.$nextTick(function() {
- this.scrollTop = 0;
- });
- },
- touchstart: function(event) {
- // 手指按下
- // console.log('start');
- this.touch_start.x = event.changedTouches[0].pageX;
- this.touch_start.y = event.changedTouches[0].pageY;
- this.hasMove = false;
- },
- touchmove: function(event) {
- // console.log('move');
- const end_move_page_x = event.changedTouches[0].pageX;
- const end_move_page_y = event.changedTouches[0].pageY;
- const moveX = this.touch_start.x - end_move_page_x;
- const moveY = this.touch_start.y - end_move_page_y;
- if (moveX === 0) {
- // console.log('回到原位置');
- this.stopTips();
- }
- if (moveX > 0) {
- // console.log('向左滑动');
- if (Math.abs(moveX) > Math.abs(moveY)) {
- this.touch_direction = 'left';
- }
- }
- if (moveX < 0) {
- // console.log('向右滑动');
- if (Math.abs(moveX) > Math.abs(moveY)) {
- this.touch_direction = 'right';
- }
- }
- if (moveY === 0) {
- // console.log('回到原位置');
- this.stopTips();
- }
- if (moveY > 0) {
- // console.log('向上滑动');
- if (Math.abs(moveY) > Math.abs(moveX)) {
- this.touch_direction = 'top';
- }
- }
- if (moveY < 0) {
- // console.log('向下滑动');
- if (Math.abs(moveY) > Math.abs(moveX)) {
- this.touch_direction = 'bottom';
- }
- }
- if (this.old.scrollTop === 0) {
- this.isInBottom = true;
- this.isInTop = true;
- }
- this.hasMove = true;
- this.checkTouchY(moveY);
- },
- checkTouchY: function(moveY) {
- // console.log('move_check');
- const hk = this;
- hk.pullDownCanDo = false;
- hk.pullUpCanDo = false;
- hk.showPullUp = false;
- hk.showPullDown = false;
- // hk.showEmpty = false;
- // hk.isCloseTip = false;
- hk.moveY = Math.abs(moveY);
- // 上拉 并且 在底部
- if (hk.touch_direction === 'top' && hk.isInBottom) {
- // console.log("我在底部上拉")
- hk.showPullUp = true; // 显示上拉加载
- hk.onPullUpText = hk.loadTip;
- if (hk.moveY > hk.touchHeight) {
- hk.onPullUpText = '释放加载';
- hk.pullUpCanDo = true; // 执行加载
- }
- }
- // 下拉 并且在 顶部
- else if (hk.touch_direction === 'bottom' && hk.isInTop && hk.stopPullDown) {
- // console.log("我在顶部下拉")
- hk.showPullDown = true; // 显示下拉刷新
- hk.refreshText = hk.refreshTip;
- if (hk.moveY > hk.touchHeight) {
- hk.refreshText = '释放刷新';
- hk.pullDownCanDo = true; // 执行刷新
- hk.moveY = Math.abs(hk.touchHeight);
- }
- }
- },
- touchend: function(event) {
- // console.log("end")
- const hk = this;
- hk.doRefreshing = false;
- hk.doLoadmore = false;
- this.touch_end.x = event.changedTouches[0].pageX;
- this.touch_end.y = event.changedTouches[0].pageY;
- if (!hk.hasMove) {
- const moveX = this.touch_start.x - this.touch_end.x;
- const moveY = this.touch_start.y - this.touch_end.y;
- hk.touch_direction = 'top';
- hk.checkTouchY(hk.touchHeight + 10);
- }
- // console.log("hk.touch_direction", hk.touch_direction)
- // console.log("hk.isInBottom", hk.isInBottom)
- // console.log("hk.isInTop", hk.isInTop)
- // console.log("hk.pullUpCanDo", hk.pullUpCanDo)
- // console.log("hk.pullDownCanDo", hk.pullDownCanDo)
- if (hk.pullUpCanDo) {
- hk.onPullUpText = hk.loadingTip; // 正在加载
- // 调用加载更多
- hk.doLoadmore = true;
- hk.onPullUp();
- } else if (hk.pullDownCanDo) {
- // 执行刷新
- hk.refreshText = hk.loadingTip; // 正在刷新
- // 调用刷新
- hk.doRefreshing = true;
- hk.onPullDown();
- } else {
- hk.stopTips();
- }
- },
- touchcancel: function(event) {
- // console.log('cancel');
- },
- onPullDown: function() {
- // 刷新
- const hk = this;
- this.goTop(); // 回到顶部
- // console.log('下拉刷新');
- hk.$emit('onPullDown', hk.stopTips);
- // 隐藏刷新文字提示
- hk.clearTimer = setTimeout(function() {
- hk.stopTips();
- }, 4000);
- },
- onPullUp: function() {
- // 加载更多
- const hk = this;
- // console.log('上拉加载');
- hk.$emit('onPullUp', hk.stopTips);
- // 隐藏上拉提示
- hk.clearTimer = setTimeout(function() {
- hk.stopTips();
- }, 4000);
- },
- stopTips(config) {
- config = config || {};
- const hk = this;
- hk.isCloseTip = false;
- // 如果提示没关闭,则关闭
- if (!hk.isCloseTip) {
- if (hk.clearTimer) {
- clearTimeout(hk.clearTimer);
- }
- hk.clearTimer = setTimeout(function() {
- hk.showPullDown = false;
- hk.showPullUp = false;
- hk.pullUpCanDo = false;
- hk.pullDownCanDo = false;
- hk.doRefreshing = false;
- if (config.isEnd && config.isEnd !== 'false') {
- hk.showEmpty = true;
- }
- hk.isCloseTip = true;
- if (hk.clearTimer) {
- clearTimeout(hk.clearTimer);
- }
- }, 1000);
- }
- }
- }
- };
- </script>
- <style>
- @font-face {
- font-family: 'my-icons-custom';
- src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAQ8AAsAAAAACLQAAAPwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDHAqEaIN5ATYCJAMQCwoABCAFhG0HTxtyB8gOJRHBwMBgYGNAPNSP/e/svfvNHKg+ncR0lY5HErREJUEpntTym2rTNkeVUHWaM1XIiUWWiA6hdVIRi5xYXX4n74qTE7NX7X+OmS6fz4b51zaX7MAB7Y2TB1R5VXjvQA40APEW2DkEatWJ5wm0m7YE79S+I2eAkxTsC8R1hUwEnFoGOYMLrermkaspngJ7reXxrF4APMn/Pr6CVeFE0VQFLzp9ca8U7PiAfESRhzOJLtZskHg4G7SbqNgEJHF51HEWUiY2IdqdXDtHAK3hTwofkA/UR3RmhkS3omglha3/eIVoFig6EXsoVPkQC2olhWyCj6hBYXRub0U3ngG+m06TggNF6BhH/J0xOHpn/M2ZURsx9lrIcUJ0dLSBHyfHn97/NSE86xIFy3Lqk3yp8mxvaWlibY6fzK4svX89L6bMdK+qzlpfeaa0JruOx3tUn1MbQJb2qyx+qyuqa83eNVfJtvoJKyrNJlxWXpdU78evrE2smQPLLNZqH6LMXHPP90K2rrLe6kuWV9WYhNbNOmA6kDZQiIhK6RlE1Eklmc1UW7lLwFpXRbAOreJvMn/jG9XZW3viGzfV76xZLuhY2OYz2OXU7f7vv1v3Dlfr4LDVzer8q2FBuaAi2Tl/R8GmIJJMMnJTaxcB7IW3tylAEJh16BDTmYhTWYGCD4QGv8M8gjxcwO57B9Y4wGHsA9uzq25kOBz5NBhOgF/ueR/v57PD7KcHrNGm5D5NaD8eXfphfNLI3er5RYQTv2JBen9w9PdHzeSnjylHbCzGcf6OF2/m2R5ojBcIwRm+755X9FD2r9w8biAvf1SwX60f7+ZFLp/PfcjmWcy2+4doNbgNaEw17tQZJLuMParnkDV5KjFBffAHeJ3Zl45eV9y2/G/lJ3hFp/UibxtfxkPhtygUC79uWR50iHTFgSHTNjamcqG8RXqEz/tW2a4dDfT0e3EI1ZBTSmg1VEPRYgqqVovIxG5Ckw6HoFmro9Buw/6bOwygISLbsC4NIPRqhqLbc6h69SET+xyaDPsOzXoDgXZnwuueHZZDge6moYiBUlwcgyskOi0VmRm0KD8FZRFqEd0U5wQS0gZFGF+5bEU3vR9qIX2IE4ZI2SqGoXCK1mnwffAyqFbrcD2tU0IJs0zOMPpNy5dTY1+0TKLTANRJNEiEAUnhxGLgFCR0tKh0NAPt/f4pkEwENRF6pq/DSYJoBorFcSsts0KA3K/QivpeymqDSDKrMBgU76LQdDRw+9AGqcOEDk4/vkkJkmAsI98Q09tkOQ2ipIplp1dp3uExaBfcM6NEjYwmPVcVIi2ji1hKQypyG+Ro2xahd6jisSIFAA==')
- format('woff2');
- }
- .my-icons-custom {
- font-family: 'my-icons-custom' !important;
- font-size: 16px;
- font-style: normal;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- }
- .icon-jiantou-refresh:before {
- content: '\e666';
- }
- .icon-jiantou-up:before {
- content: '\e70a';
- }
- .icon-jiazai:before {
- content: '\e603';
- }
- </style>
- <style lang="scss" scoped>
- @import './animate.scss';
- .image {
- width: 100%;
- height: 100%;
- }
- .k-scroll-view {
- width: 100%;
- position: relative;
- overflow-y: hidden;
- .scroll-Y {
- width: 100%;
- height: 100%;
- }
- .scroll-load-refresh,
- .scroll-load-more {
- text-align: center;
- color: #000;
- font-size: 25rpx;
- position: absolute;
- line-height: 60rpx;
- z-index: 1;
- background-color: rgba($color: #ffffff, $alpha: 0.7);
- border-bottom: 1px solid #eee;
- width: 100%;
- }
- .scroll-load-refresh {
- top: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .scroll-load-more {
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- /deep/ .translate-line {
- height: 0;
- margin-right: 5px;
- }
- }
- .go-to-top-icon {
- position: absolute;
- right: 20rpx;
- bottom: calc(20rpx + 60rpx + 10rpx);
- width: 60rpx;
- height: 60rpx;
- background-color: #eee;
- border-radius: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .native-refresh-icon {
- position: fixed;
- top: 0;
- left: calc(50% - 30rpx);
- width: 60rpx;
- height: 60rpx;
- z-index: 999;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .empty-tips {
- width: 100%;
- line-height: 50rpx;
- text-align: center;
- color: #657575;
- font-size: 30rpx;
- }
- }
- </style>
|