master
ihzero 2024-12-02 22:23:49 +08:00
parent b55bb1e863
commit fcc4e21c36
107 changed files with 3659 additions and 3659 deletions

View File

@ -1,2 +1,2 @@
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><script>var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel="stylesheet" href="/static/index.97465e7b.css"></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.ab256238.js"></script><script src="/static/js/index.f6a118ab.js"></script></body></html> document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel="stylesheet" href="/static/index.97465e7b.css"></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.959091ef.js"></script><script src="/static/js/index.fdf17756.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,19 @@
.mescroll-body { .mescroll-body {
position: relative; /* 下拉刷新区域相对自身定位 */ position: relative; /* 下拉刷新区域相对自身定位 */
height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/ height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/
overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */ overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */
box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */
} }
/* 使sticky生效: 父元素不能overflow:hidden或者overflow:auto属性 */ /* 使sticky生效: 父元素不能overflow:hidden或者overflow:auto属性 */
.mescroll-body.mescorll-sticky{ .mescroll-body.mescorll-sticky{
overflow: unset !important overflow: unset !important
} }
/* 适配 iPhoneX */ /* 适配 iPhoneX */
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { @supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
.mescroll-safearea { .mescroll-safearea {
padding-bottom: constant(safe-area-inset-bottom); padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
} }
} }

View File

@ -1,400 +1,400 @@
<template> <template>
<view <view
class="mescroll-body mescroll-render-touch" class="mescroll-body mescroll-render-touch"
:class="{'mescorll-sticky': sticky}" :class="{'mescorll-sticky': sticky}"
:style="{'minHeight':minHeight, 'padding-top': padTop, 'padding-bottom': padBottom}" :style="{'minHeight':minHeight, 'padding-top': padTop, 'padding-bottom': padBottom}"
@touchstart="wxsBiz.touchstartEvent" @touchstart="wxsBiz.touchstartEvent"
@touchmove="wxsBiz.touchmoveEvent" @touchmove="wxsBiz.touchmoveEvent"
@touchend="wxsBiz.touchendEvent" @touchend="wxsBiz.touchendEvent"
@touchcancel="wxsBiz.touchendEvent" @touchcancel="wxsBiz.touchendEvent"
:change:prop="wxsBiz.propObserver" :change:prop="wxsBiz.propObserver"
:prop="wxsProp" :prop="wxsProp"
> >
<!-- 状态栏 --> <!-- 状态栏 -->
<view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view> <view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view>
<view class="mescroll-body-content mescroll-wxs-content" :style="{ transform: translateY, transition: transition }" :change:prop="wxsBiz.callObserver" :prop="callProp"> <view class="mescroll-body-content mescroll-wxs-content" :style="{ transform: translateY, transition: transition }" :change:prop="wxsBiz.callObserver" :prop="callProp">
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)--> <!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> --> <!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
<view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}"> <view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}">
<view class="downwarp-content"> <view class="downwarp-content">
<view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view> <view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view>
<view class="downwarp-tip">{{downText}}</view> <view class="downwarp-tip">{{downText}}</view>
</view> </view>
</view> </view>
<!-- 列表内容 --> <!-- 列表内容 -->
<slot></slot> <slot></slot>
<!-- 空布局 --> <!-- 空布局 -->
<mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty>
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)--> <!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> --> <!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
<view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}"> <view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}">
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) --> <!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
<view v-show="upLoadType===1"> <view v-show="upLoadType===1">
<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view> <view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view>
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view> <view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
</view> </view>
<!-- 无数据 --> <!-- 无数据 -->
<view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view> <view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
</view> </view>
</view> </view>
<!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) --> <!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) -->
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view> <view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view>
<!-- #endif --> <!-- #endif -->
<!-- 适配iPhoneX --> <!-- 适配iPhoneX -->
<view v-if="safearea" class="mescroll-safearea"></view> <view v-if="safearea" class="mescroll-safearea"></view>
<!-- 回到顶部按钮 (fixed元素需写在transform外面,防止降级为absolute)--> <!-- 回到顶部按钮 (fixed元素需写在transform外面,防止降级为absolute)-->
<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top> <mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 --> <!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
<!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 --> <!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 -->
<view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view> <view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view>
<!-- #endif --> <!-- #endif -->
</view> </view>
</template> </template>
<!-- 微信小程序, QQ小程序, app, h5使用wxs --> <!-- 微信小程序, QQ小程序, app, h5使用wxs -->
<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 --> <!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
<script src="../mescroll-uni/wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script> <script src="../mescroll-uni/wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script>
<!-- #endif --> <!-- #endif -->
<!-- app, h5使用renderjs --> <!-- app, h5使用renderjs -->
<!-- #ifdef APP-PLUS || H5 --> <!-- #ifdef APP-PLUS || H5 -->
<script module="renderBiz" lang="renderjs"> <script module="renderBiz" lang="renderjs">
import renderBiz from "../mescroll-uni/wxs/renderjs.js"; import renderBiz from "../mescroll-uni/wxs/renderjs.js";
export default { export default {
mixins: [renderBiz] mixins: [renderBiz]
} }
</script> </script>
<!-- #endif --> <!-- #endif -->
<script> <script>
// mescroll-uni.js, // mescroll-uni.js,
import MeScroll from "../mescroll-uni/mescroll-uni.js"; import MeScroll from "../mescroll-uni/mescroll-uni.js";
// //
import GlobalOption from "../mescroll-uni/mescroll-uni-option.js"; import GlobalOption from "../mescroll-uni/mescroll-uni-option.js";
// //
import mescrollI18n from '../mescroll-uni/mescroll-i18n.js'; import mescrollI18n from '../mescroll-uni/mescroll-i18n.js';
// //
import MescrollTop from "../mescroll-uni/components/mescroll-top.vue"; import MescrollTop from "../mescroll-uni/components/mescroll-top.vue";
// wxs(renderjs)mixins // wxs(renderjs)mixins
import WxsMixin from "../mescroll-uni/wxs/mixins.js"; import WxsMixin from "../mescroll-uni/wxs/mixins.js";
/** /**
* mescroll-body 基于page滚动的下拉刷新和上拉加载组件, 支持嵌套原生组件, 性能好 * mescroll-body 基于page滚动的下拉刷新和上拉加载组件, 支持嵌套原生组件, 性能好
* @property {Object} down 下拉刷新的参数配置 * @property {Object} down 下拉刷新的参数配置
* @property {Object} up 上拉加载的参数配置 * @property {Object} up 上拉加载的参数配置
* @property {Object} i18n 国际化的参数配置 * @property {Object} i18n 国际化的参数配置
* @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight) * @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
* @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变) * @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变)
* @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight) * @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
* @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用) * @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
* @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true * @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true
* @property {String, Number} height 指定mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉 * @property {String, Number} height 指定mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
* @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效) * @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效)
* @property {Boolean} sticky 是否支持sticky,默认false; 当值配置true时,需避免在mescroll-body标签前面加非定位的元素,否则下拉区域无法隐藏 * @property {Boolean} sticky 是否支持sticky,默认false; 当值配置true时,需避免在mescroll-body标签前面加非定位的元素,否则下拉区域无法隐藏
* @event {Function} init 初始化完成的回调 * @event {Function} init 初始化完成的回调
* @event {Function} down 下拉刷新的回调 * @event {Function} down 下拉刷新的回调
* @event {Function} up 上拉加载的回调 * @event {Function} up 上拉加载的回调
* @event {Function} emptyclick 点击empty配置的btnText按钮回调 * @event {Function} emptyclick 点击empty配置的btnText按钮回调
* @event {Function} topclick 点击回到顶部的按钮回调 * @event {Function} topclick 点击回到顶部的按钮回调
* @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效) * @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效)
* @example <mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-body> * @example <mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-body>
*/ */
export default { export default {
name: 'mescroll-body', name: 'mescroll-body',
mixins: [WxsMixin], mixins: [WxsMixin],
components: { components: {
MescrollTop MescrollTop
}, },
props: { props: {
down: Object, down: Object,
up: Object, up: Object,
i18n: Object, i18n: Object,
top: [String, Number], top: [String, Number],
topbar: [Boolean, String], topbar: [Boolean, String],
bottom: [String, Number], bottom: [String, Number],
safearea: Boolean, safearea: Boolean,
height: [String, Number], height: [String, Number],
bottombar:{ bottombar:{
type: Boolean, type: Boolean,
default: true default: true
}, },
sticky: Boolean sticky: Boolean
}, },
data() { data() {
return { return {
mescroll: {optDown:{},optUp:{}}, // mescroll mescroll: {optDown:{},optUp:{}}, // mescroll
downHight: 0, //: downHight: 0, //:
downRate: 0, // (inOffset: rate<1; outOffset: rate>=1) downRate: 0, // (inOffset: rate<1; outOffset: rate>=1)
downLoadType: 0, // : 0(loading), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll) downLoadType: 0, // : 0(loading), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll)
upLoadType: 0, // 0loading1loading2,END3,END upLoadType: 0, // 0loading1loading2,END3,END
isShowEmpty: false, // isShowEmpty: false, //
isShowToTop: false, // isShowToTop: false, //
windowHeight: 0, // 使 windowHeight: 0, // 使
windowBottom: 0, // 使 windowBottom: 0, // 使
statusBarHeight: 0 // statusBarHeight: 0 //
}; };
}, },
computed: { computed: {
// mescroll,windowHeight,使 // mescroll,windowHeight,使
minHeight(){ minHeight(){
return this.toPx(this.height || '100%') + 'px' return this.toPx(this.height || '100%') + 'px'
}, },
// (px) // (px)
numTop() { numTop() {
return this.toPx(this.top) return this.toPx(this.top)
}, },
padTop() { padTop() {
return this.numTop + 'px'; return this.numTop + 'px';
}, },
// (px) // (px)
numBottom() { numBottom() {
return this.toPx(this.bottom); return this.toPx(this.bottom);
}, },
padBottom() { padBottom() {
return this.numBottom + 'px'; return this.numBottom + 'px';
}, },
// //
isDownReset() { isDownReset() {
return this.downLoadType === 3 || this.downLoadType === 4; return this.downLoadType === 3 || this.downLoadType === 4;
}, },
// //
transition() { transition() {
return this.isDownReset ? 'transform 300ms' : ''; return this.isDownReset ? 'transform 300ms' : '';
}, },
translateY() { translateY() {
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform使fixed,fixedmescroll return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform使fixed,fixedmescroll
}, },
// //
isDownLoading(){ isDownLoading(){
return this.downLoadType === 3 return this.downLoadType === 3
}, },
// //
downRotate(){ downRotate(){
return 'rotate(' + 360 * this.downRate + 'deg)' return 'rotate(' + 360 * this.downRate + 'deg)'
}, },
// //
downText(){ downText(){
if(!this.mescroll) return ""; // if(!this.mescroll) return ""; //
switch (this.downLoadType){ switch (this.downLoadType){
case 1: return this.mescroll.optDown.textInOffset; case 1: return this.mescroll.optDown.textInOffset;
case 2: return this.mescroll.optDown.textOutOffset; case 2: return this.mescroll.optDown.textOutOffset;
case 3: return this.mescroll.optDown.textLoading; case 3: return this.mescroll.optDown.textLoading;
case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset; case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset;
default: return this.mescroll.optDown.textInOffset; default: return this.mescroll.optDown.textInOffset;
} }
} }
}, },
methods: { methods: {
//number,rpx,upx,px,% --> px //number,rpx,upx,px,% --> px
toPx(num) { toPx(num) {
if (typeof num === 'string') { if (typeof num === 'string') {
if (num.indexOf('px') !== -1) { if (num.indexOf('px') !== -1) {
if (num.indexOf('rpx') !== -1) { if (num.indexOf('rpx') !== -1) {
// "10rpx" // "10rpx"
num = num.replace('rpx', ''); num = num.replace('rpx', '');
} else if (num.indexOf('upx') !== -1) { } else if (num.indexOf('upx') !== -1) {
// "10upx" // "10upx"
num = num.replace('upx', ''); num = num.replace('upx', '');
} else { } else {
// "10px" // "10px"
return Number(num.replace('px', '')); return Number(num.replace('px', ''));
} }
} else if (num.indexOf('%') !== -1) { } else if (num.indexOf('%') !== -1) {
// ,windowHeight,"10%"windowHeight10% // ,windowHeight,"10%"windowHeight10%
let rate = Number(num.replace('%', '')) / 100; let rate = Number(num.replace('%', '')) / 100;
return this.windowHeight * rate; return this.windowHeight * rate;
} }
} }
return num ? uni.upx2px(Number(num)) : 0; return num ? uni.upx2px(Number(num)) : 0;
}, },
// //
emptyClick() { emptyClick() {
this.$emit('emptyclick', this.mescroll); this.$emit('emptyclick', this.mescroll);
}, },
// //
toTopClick() { toTopClick() {
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); //
this.$emit('topclick', this.mescroll); // this.$emit('topclick', this.mescroll); //
} }
}, },
// 使createdmescroll; mountedcssH5 // 使createdmescroll; mountedcssH5
created() { created() {
let vm = this; let vm = this;
let diyOption = { let diyOption = {
// //
down: { down: {
inOffset() { inOffset() {
vm.downLoadType = 1; // offset (mescroll,) vm.downLoadType = 1; // offset (mescroll,)
}, },
outOffset() { outOffset() {
vm.downLoadType = 2; // offset (mescroll,) vm.downLoadType = 2; // offset (mescroll,)
}, },
onMoving(mescroll, rate, downHight) { onMoving(mescroll, rate, downHight) {
// ,; // ,;
vm.downHight = downHight; // (mescroll,) vm.downHight = downHight; // (mescroll,)
vm.downRate = rate; // (inOffset: rate<1; outOffset: rate>=1) vm.downRate = rate; // (inOffset: rate<1; outOffset: rate>=1)
}, },
showLoading(mescroll, downHight) { showLoading(mescroll, downHight) {
vm.downLoadType = 3; // (mescroll,) vm.downLoadType = 3; // (mescroll,)
vm.downHight = downHight; // (mescroll,) vm.downHight = downHight; // (mescroll,)
}, },
beforeEndDownScroll(mescroll){ beforeEndDownScroll(mescroll){
vm.downLoadType = 4; vm.downLoadType = 4;
return mescroll.optDown.beforeEndDelay // return mescroll.optDown.beforeEndDelay //
}, },
endDownScroll() { endDownScroll() {
vm.downLoadType = 4; // (mescroll,) vm.downLoadType = 4; // (mescroll,)
vm.downHight = 0; // (mescroll,) vm.downHight = 0; // (mescroll,)
if(vm.downResetTimer) {clearTimeout(vm.downResetTimer); vm.downResetTimer = null} // if(vm.downResetTimer) {clearTimeout(vm.downResetTimer); vm.downResetTimer = null} //
vm.downResetTimer = setTimeout(()=>{ // ,0,inOffsettextInOffset vm.downResetTimer = setTimeout(()=>{ // ,0,inOffsettextInOffset
if(vm.downLoadType === 4) vm.downLoadType = 0 if(vm.downLoadType === 4) vm.downLoadType = 0
},300) },300)
}, },
// //
callback: function(mescroll) { callback: function(mescroll) {
vm.$emit('down', mescroll); vm.$emit('down', mescroll);
} }
}, },
// //
up: { up: {
// //
showLoading() { showLoading() {
vm.upLoadType = 1; vm.upLoadType = 1;
}, },
// //
showNoMore() { showNoMore() {
vm.upLoadType = 2; vm.upLoadType = 2;
}, },
// //
hideUpScroll(mescroll) { hideUpScroll(mescroll) {
vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3; vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3;
}, },
// //
empty: { empty: {
onShow(isShow) { onShow(isShow) {
// //
vm.isShowEmpty = isShow; vm.isShowEmpty = isShow;
} }
}, },
// //
toTop: { toTop: {
onShow(isShow) { onShow(isShow) {
// //
vm.isShowToTop = isShow; vm.isShowToTop = isShow;
} }
}, },
// //
callback: function(mescroll) { callback: function(mescroll) {
vm.$emit('up', mescroll); vm.$emit('up', mescroll);
} }
} }
}; };
let i18nType = mescrollI18n.getType() // let i18nType = mescrollI18n.getType() //
let i18nOption = {type: i18nType} // let i18nOption = {type: i18nType} //
MeScroll.extend(i18nOption, vm.i18n) // MeScroll.extend(i18nOption, vm.i18n) //
MeScroll.extend(i18nOption, GlobalOption.i18n) // MeScroll.extend(i18nOption, GlobalOption.i18n) //
MeScroll.extend(diyOption, i18nOption[i18nType]); // MeScroll.extend(diyOption, i18nOption[i18nType]); //
MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); // MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); //
let myOption = JSON.parse(JSON.stringify({down: vm.down,up: vm.up})); // ,props let myOption = JSON.parse(JSON.stringify({down: vm.down,up: vm.up})); // ,props
MeScroll.extend(myOption, diyOption); // MeScroll.extend(myOption, diyOption); //
// MeScroll // MeScroll
vm.mescroll = new MeScroll(myOption, true); // true,body vm.mescroll = new MeScroll(myOption, true); // true,body
// //
vm.mescroll.i18n = i18nOption; vm.mescroll.i18n = i18nOption;
// initmescroll // initmescroll
vm.$emit('init', vm.mescroll); vm.$emit('init', vm.mescroll);
// //
const sys = uni.getSystemInfoSync(); const sys = uni.getSystemInfoSync();
if (sys.windowHeight) vm.windowHeight = sys.windowHeight; if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
if (sys.windowBottom) vm.windowBottom = sys.windowBottom; if (sys.windowBottom) vm.windowBottom = sys.windowBottom;
if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight; if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
// 使downbottomOffset // 使downbottomOffset
vm.mescroll.setBodyHeight(sys.windowHeight); vm.mescroll.setBodyHeight(sys.windowHeight);
// 使pagescroll,scrollTo // 使pagescroll,scrollTo
vm.mescroll.resetScrollTo((y, t) => { vm.mescroll.resetScrollTo((y, t) => {
if(typeof y === 'string'){ if(typeof y === 'string'){
// view (ycss) // view (ycss)
setTimeout(()=>{ // view; 使$nextTick setTimeout(()=>{ // view; 使$nextTick
let selector; let selector;
if(y.indexOf('#')==-1 && y.indexOf('.')==-1){ if(y.indexOf('#')==-1 && y.indexOf('.')==-1){
selector = '#'+y // #. id selector = '#'+y // #. id
}else{ }else{
selector = y selector = y
// #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK // #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK
if(y.indexOf('>>>')!=-1){ // () if(y.indexOf('>>>')!=-1){ // ()
selector = y.split('>>>')[1].trim() selector = y.split('>>>')[1].trim()
} }
// #endif // #endif
} }
uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){ uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){
if (rect) { if (rect) {
let top = rect.top let top = rect.top
top += vm.mescroll.getScrollTop() top += vm.mescroll.getScrollTop()
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: top, scrollTop: top,
duration: t duration: t
}) })
} else{ } else{
console.error(selector + ' does not exist'); console.error(selector + ' does not exist');
} }
}).exec() }).exec()
},30) },30)
} else{ } else{
// (y) // (y)
uni.pageScrollTo({ uni.pageScrollTo({
scrollTop: y, scrollTop: y,
duration: t duration: t
}) })
} }
}); });
// up.toTop.safearea,vuesafearea // up.toTop.safearea,vuesafearea
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else { if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
vm.mescroll.optUp.toTop.safearea = vm.safearea; vm.mescroll.optUp.toTop.safearea = vm.safearea;
} }
// //
uni.$on("setMescrollGlobalOption", options=>{ uni.$on("setMescrollGlobalOption", options=>{
if(!options) return; if(!options) return;
let i18nType = options.i18n ? options.i18n.type : null let i18nType = options.i18n ? options.i18n.type : null
if(i18nType && vm.mescroll.i18n.type != i18nType){ if(i18nType && vm.mescroll.i18n.type != i18nType){
vm.mescroll.i18n.type = i18nType vm.mescroll.i18n.type = i18nType
mescrollI18n.setType(i18nType) mescrollI18n.setType(i18nType)
MeScroll.extend(options, vm.mescroll.i18n[i18nType]) MeScroll.extend(options, vm.mescroll.i18n[i18nType])
} }
if(options.down){ if(options.down){
let down = MeScroll.extend({}, options.down) let down = MeScroll.extend({}, options.down)
vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown) vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown)
} }
if(options.up){ if(options.up){
let up = MeScroll.extend({}, options.up) let up = MeScroll.extend({}, options.up)
vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp) vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp)
} }
}) })
}, },
destroyed() { destroyed() {
// //
uni.$off("setMescrollGlobalOption") uni.$off("setMescrollGlobalOption")
} }
}; };
</script> </script>
<style> <style>
@import "../mescroll-body/mescroll-body.css"; @import "../mescroll-body/mescroll-body.css";
@import "../mescroll-uni/components/mescroll-down.css"; @import "../mescroll-uni/components/mescroll-down.css";
@import "../mescroll-uni/components/mescroll-up.css"; @import "../mescroll-uni/components/mescroll-up.css";
</style> </style>

View File

@ -1,116 +1,116 @@
<!--空布局: <!--空布局:
遵循easycom规范, 可作为独立的组件, 不使用mescroll的页面也能使用: 遵循easycom规范, 可作为独立的组件, 不使用mescroll的页面也能使用:
<mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty> <mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty>
--> -->
<template> <template>
<view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }"> <view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }">
<view> <image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" /> </view> <view> <image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" /> </view>
<view v-if="tip" class="empty-tip">{{ tip }}</view> <view v-if="tip" class="empty-tip">{{ tip }}</view>
<view v-if="btnText" class="empty-btn" @click="emptyClick">{{ btnText }}</view> <view v-if="btnText" class="empty-btn" @click="emptyClick">{{ btnText }}</view>
</view> </view>
</template> </template>
<script> <script>
// //
import GlobalOption from '../mescroll-uni/mescroll-uni-option.js'; import GlobalOption from '../mescroll-uni/mescroll-uni-option.js';
// //
import mescrollI18n from '../mescroll-uni/mescroll-i18n.js'; import mescrollI18n from '../mescroll-uni/mescroll-i18n.js';
export default { export default {
props: { props: {
// empty: GlobalOption.up.empty // empty: GlobalOption.up.empty
option: { option: {
type: Object, type: Object,
default() { default() {
return {}; return {};
} }
} }
}, },
// 使computed,option // 使computed,option
computed: { computed: {
// //
icon() { icon() {
if (this.option.icon != null) { // 使, if (this.option.icon != null) { // 使,
return this.option.icon return this.option.icon
} else{ } else{
let i18nType = mescrollI18n.getType() // let i18nType = mescrollI18n.getType() //
if (this.option.i18n) { if (this.option.i18n) {
return this.option.i18n[i18nType].icon return this.option.i18n[i18nType].icon
} else{ } else{
return GlobalOption.i18n[i18nType].up.empty.icon || GlobalOption.up.empty.icon return GlobalOption.i18n[i18nType].up.empty.icon || GlobalOption.up.empty.icon
} }
} }
}, },
// //
tip() { tip() {
if (this.option.tip != null) { // if (this.option.tip != null) { //
return this.option.tip return this.option.tip
} else{ } else{
let i18nType = mescrollI18n.getType() // let i18nType = mescrollI18n.getType() //
if (this.option.i18n) { if (this.option.i18n) {
return this.option.i18n[i18nType].tip return this.option.i18n[i18nType].tip
} else{ } else{
return GlobalOption.i18n[i18nType].up.empty.tip || GlobalOption.up.empty.tip return GlobalOption.i18n[i18nType].up.empty.tip || GlobalOption.up.empty.tip
} }
} }
}, },
// //
btnText() { btnText() {
if (this.option.i18n) { if (this.option.i18n) {
let i18nType = mescrollI18n.getType() // let i18nType = mescrollI18n.getType() //
return this.option.i18n[i18nType].btnText return this.option.i18n[i18nType].btnText
} else{ } else{
return this.option.btnText return this.option.btnText
} }
} }
}, },
methods: { methods: {
// //
emptyClick() { emptyClick() {
this.$emit('emptyclick'); this.$emit('emptyclick');
} }
} }
}; };
</script> </script>
<style> <style>
/* 无任何数据的空布局 */ /* 无任何数据的空布局 */
.mescroll-empty { .mescroll-empty {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 100rpx 50rpx; padding: 100rpx 50rpx;
text-align: center; text-align: center;
} }
.mescroll-empty.empty-fixed { .mescroll-empty.empty-fixed {
z-index: 99; z-index: 99;
position: absolute; /*transform会使fixed失效,最终会降级为absolute */ position: absolute; /*transform会使fixed失效,最终会降级为absolute */
top: 100rpx; top: 100rpx;
left: 0; left: 0;
} }
.mescroll-empty .empty-icon { .mescroll-empty .empty-icon {
width: 280rpx; width: 280rpx;
height: 280rpx; height: 280rpx;
} }
.mescroll-empty .empty-tip { .mescroll-empty .empty-tip {
margin-top: 20rpx; margin-top: 20rpx;
font-size: 24rpx; font-size: 24rpx;
color: gray; color: gray;
} }
.mescroll-empty .empty-btn { .mescroll-empty .empty-btn {
display: inline-block; display: inline-block;
margin-top: 40rpx; margin-top: 40rpx;
min-width: 200rpx; min-width: 200rpx;
padding: 18rpx; padding: 18rpx;
font-size: 28rpx; font-size: 28rpx;
border: 1rpx solid #e04b28; border: 1rpx solid #e04b28;
border-radius: 60rpx; border-radius: 60rpx;
color: #e04b28; color: #e04b28;
} }
.mescroll-empty .empty-btn:active { .mescroll-empty .empty-btn:active {
opacity: 0.75; opacity: 0.75;
} }
</style> </style>

View File

@ -1,55 +1,55 @@
/* 下拉刷新区域 */ /* 下拉刷新区域 */
.mescroll-downwarp { .mescroll-downwarp {
position: absolute; position: absolute;
top: -100%; top: -100%;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
text-align: center; text-align: center;
} }
/* 下拉刷新--内容区,定位于区域底部 */ /* 下拉刷新--内容区,定位于区域底部 */
.mescroll-downwarp .downwarp-content { .mescroll-downwarp .downwarp-content {
position: absolute; position: absolute;
left: 0; left: 0;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
min-height: 60rpx; min-height: 60rpx;
padding: 20rpx 0; padding: 20rpx 0;
text-align: center; text-align: center;
} }
/* 下拉刷新--提示文本 */ /* 下拉刷新--提示文本 */
.mescroll-downwarp .downwarp-tip { .mescroll-downwarp .downwarp-tip {
display: inline-block; display: inline-block;
font-size: 28rpx; font-size: 28rpx;
vertical-align: middle; vertical-align: middle;
margin-left: 16rpx; margin-left: 16rpx;
/* color: gray; 已在style设置color,此处删去*/ /* color: gray; 已在style设置color,此处删去*/
} }
/* 下拉刷新--旋转进度条 */ /* 下拉刷新--旋转进度条 */
.mescroll-downwarp .downwarp-progress { .mescroll-downwarp .downwarp-progress {
display: inline-block; display: inline-block;
width: 32rpx; width: 32rpx;
height: 32rpx; height: 32rpx;
border-radius: 50%; border-radius: 50%;
border: 2rpx solid gray; border: 2rpx solid gray;
border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
vertical-align: middle; vertical-align: middle;
} }
/* 旋转动画 */ /* 旋转动画 */
.mescroll-downwarp .mescroll-rotate { .mescroll-downwarp .mescroll-rotate {
animation: mescrollDownRotate 0.6s linear infinite; animation: mescrollDownRotate 0.6s linear infinite;
} }
@keyframes mescrollDownRotate { @keyframes mescrollDownRotate {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }

View File

@ -1,47 +1,47 @@
<!-- 下拉刷新区域 --> <!-- 下拉刷新区域 -->
<template> <template>
<view v-if="mOption.use" class="mescroll-downwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}"> <view v-if="mOption.use" class="mescroll-downwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}">
<view class="downwarp-content"> <view class="downwarp-content">
<view class="downwarp-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mOption.textColor, 'transform':downRotate}"></view> <view class="downwarp-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mOption.textColor, 'transform':downRotate}"></view>
<view class="downwarp-tip">{{downText}}</view> <view class="downwarp-tip">{{downText}}</view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
option: Object , // down option: Object , // down
type: Number, // inOffset1 outOffset2 showLoading3 endDownScroll4 type: Number, // inOffset1 outOffset2 showLoading3 endDownScroll4
rate: Number // (inOffset: rate<1; outOffset: rate>=1) rate: Number // (inOffset: rate<1; outOffset: rate>=1)
}, },
computed: { computed: {
// ,propdefault // ,propdefault
mOption(){ mOption(){
return this.option || {} return this.option || {}
}, },
// //
isDownLoading(){ isDownLoading(){
return this.type === 3 return this.type === 3
}, },
// //
downRotate(){ downRotate(){
return 'rotate(' + 360 * this.rate + 'deg)' return 'rotate(' + 360 * this.rate + 'deg)'
}, },
// //
downText(){ downText(){
switch (this.type){ switch (this.type){
case 1: return this.mOption.textInOffset; case 1: return this.mOption.textInOffset;
case 2: return this.mOption.textOutOffset; case 2: return this.mOption.textOutOffset;
case 3: return this.mOption.textLoading; case 3: return this.mOption.textLoading;
case 4: return this.mOption.textLoading; case 4: return this.mOption.textLoading;
default: return this.mOption.textInOffset; default: return this.mOption.textInOffset;
} }
} }
} }
}; };
</script> </script>
<style> <style>
@import "./mescroll-down.css"; @import "./mescroll-down.css";
</style> </style>

View File

@ -1,99 +1,99 @@
<!-- 回到顶部的按钮 --> <!-- 回到顶部的按钮 -->
<template> <template>
<image <image
v-if="option.src" v-if="option.src"
class="mescroll-totop" class="mescroll-totop"
:class="[isShow ? 'mescroll-totop-in' : 'mescroll-totop-out', {'mescroll-totop-safearea': option.safearea}]" :class="[isShow ? 'mescroll-totop-in' : 'mescroll-totop-out', {'mescroll-totop-safearea': option.safearea}]"
:style="{'z-index':option.zIndex, 'left': left, 'right': right, 'bottom':addUnit(option.bottom), 'width':addUnit(option.width), 'border-radius':addUnit(option.radius)}" :style="{'z-index':option.zIndex, 'left': left, 'right': right, 'bottom':addUnit(option.bottom), 'width':addUnit(option.width), 'border-radius':addUnit(option.radius)}"
:src="option.src" :src="option.src"
mode="widthFix" mode="widthFix"
@click="toTopClick" @click="toTopClick"
/> />
</template> </template>
<script> <script>
export default { export default {
props: { props: {
// up.toTop // up.toTop
option: { option: {
type: Object, type: Object,
default(){ default(){
return {} return {}
} }
}, },
// //
value: false, // vue2 value: false, // vue2
modelValue: false // vue3 modelValue: false // vue3
}, },
computed: { computed: {
// //
left(){ left(){
return this.option.left ? this.addUnit(this.option.left) : 'auto'; return this.option.left ? this.addUnit(this.option.left) : 'auto';
}, },
// () // ()
right() { right() {
return this.option.left ? 'auto' : this.addUnit(this.option.right); return this.option.left ? 'auto' : this.addUnit(this.option.right);
}, },
// //
isShow(){ isShow(){
// #ifdef VUE3 // #ifdef VUE3
return this.modelValue return this.modelValue
// #endif // #endif
// #ifdef VUE2 // #ifdef VUE2
return this.value return this.value
// #endif // #endif
} }
}, },
methods: { methods: {
addUnit(num){ addUnit(num){
if(!num) return 0; if(!num) return 0;
if(typeof num === 'number') return num + 'rpx'; if(typeof num === 'number') return num + 'rpx';
return num return num
}, },
toTopClick() { toTopClick() {
// #ifdef VUE3 // #ifdef VUE3
this.$emit("update:modelValue", false); // 使v-model vue3 this.$emit("update:modelValue", false); // 使v-model vue3
// #endif // #endif
// #ifdef VUE2 // #ifdef VUE2
this.$emit('input', false); // 使v-model vue2 this.$emit('input', false); // 使v-model vue2
// #endif // #endif
this.$emit('click'); // this.$emit('click'); //
} }
} }
}; };
</script> </script>
<style> <style>
/* 回到顶部的按钮 */ /* 回到顶部的按钮 */
.mescroll-totop { .mescroll-totop {
z-index: 9990; z-index: 9990;
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */ position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
right: 20rpx; right: 20rpx;
bottom: 120rpx; bottom: 120rpx;
width: 72rpx; width: 72rpx;
height: auto; height: auto;
border-radius: 50%; border-radius: 50%;
opacity: 0; opacity: 0;
transition: opacity 0.5s; /* 过渡 */ transition: opacity 0.5s; /* 过渡 */
margin-bottom: var(--window-bottom); /* css变量 */ margin-bottom: var(--window-bottom); /* css变量 */
} }
/* 适配 iPhoneX */ /* 适配 iPhoneX */
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { @supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
.mescroll-totop-safearea { .mescroll-totop-safearea {
margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */ margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom)); margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
} }
} }
/* 显示 -- 淡入 */ /* 显示 -- 淡入 */
.mescroll-totop-in { .mescroll-totop-in {
opacity: 1; opacity: 1;
} }
/* 隐藏 -- 淡出且不接收事件*/ /* 隐藏 -- 淡出且不接收事件*/
.mescroll-totop-out { .mescroll-totop-out {
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
} }
</style> </style>

View File

@ -1,47 +1,47 @@
/* 上拉加载区域 */ /* 上拉加载区域 */
.mescroll-upwarp { .mescroll-upwarp {
box-sizing: border-box; box-sizing: border-box;
min-height: 110rpx; min-height: 110rpx;
padding: 30rpx 0; padding: 30rpx 0;
text-align: center; text-align: center;
clear: both; clear: both;
} }
/*提示文本 */ /*提示文本 */
.mescroll-upwarp .upwarp-tip, .mescroll-upwarp .upwarp-tip,
.mescroll-upwarp .upwarp-nodata { .mescroll-upwarp .upwarp-nodata {
display: inline-block; display: inline-block;
font-size: 28rpx; font-size: 28rpx;
vertical-align: middle; vertical-align: middle;
/* color: gray; 已在style设置color,此处删去*/ /* color: gray; 已在style设置color,此处删去*/
} }
.mescroll-upwarp .upwarp-tip { .mescroll-upwarp .upwarp-tip {
margin-left: 16rpx; margin-left: 16rpx;
} }
/*旋转进度条 */ /*旋转进度条 */
.mescroll-upwarp .upwarp-progress { .mescroll-upwarp .upwarp-progress {
display: inline-block; display: inline-block;
width: 32rpx; width: 32rpx;
height: 32rpx; height: 32rpx;
border-radius: 50%; border-radius: 50%;
border: 2rpx solid gray; border: 2rpx solid gray;
border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
vertical-align: middle; vertical-align: middle;
} }
/* 旋转动画 */ /* 旋转动画 */
.mescroll-upwarp .mescroll-rotate { .mescroll-upwarp .mescroll-rotate {
animation: mescrollUpRotate 0.6s linear infinite; animation: mescrollUpRotate 0.6s linear infinite;
} }
@keyframes mescrollUpRotate { @keyframes mescrollUpRotate {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }

View File

@ -1,39 +1,39 @@
<!-- 上拉加载区域 --> <!-- 上拉加载区域 -->
<template> <template>
<view class="mescroll-upwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}"> <view class="mescroll-upwarp" :style="{'background-color':mOption.bgColor,'color':mOption.textColor}">
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) --> <!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
<view v-show="isUpLoading"> <view v-show="isUpLoading">
<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mOption.textColor}"></view> <view class="upwarp-progress mescroll-rotate" :style="{'border-color':mOption.textColor}"></view>
<view class="upwarp-tip">{{ mOption.textLoading }}</view> <view class="upwarp-tip">{{ mOption.textLoading }}</view>
</view> </view>
<!-- 无数据 --> <!-- 无数据 -->
<view v-if="isUpNoMore" class="upwarp-nodata">{{ mOption.textNoMore }}</view> <view v-if="isUpNoMore" class="upwarp-nodata">{{ mOption.textNoMore }}</view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
option: Object, // up option: Object, // up
type: Number // 0loading1loading2 type: Number // 0loading1loading2
}, },
computed: { computed: {
// ,propdefault // ,propdefault
mOption() { mOption() {
return this.option || {}; return this.option || {};
}, },
// //
isUpLoading() { isUpLoading() {
return this.type === 1; return this.type === 1;
}, },
// //
isUpNoMore() { isUpNoMore() {
return this.type === 2; return this.type === 2;
} }
} }
}; };
</script> </script>
<style> <style>
@import './mescroll-up.css'; @import './mescroll-up.css';
</style> </style>

View File

@ -1,15 +1,15 @@
// 国际化工具类 // 国际化工具类
const mescrollI18n = { const mescrollI18n = {
// 默认语言 // 默认语言
def: "zh", def: "zh",
// 获取当前语言类型 // 获取当前语言类型
getType(){ getType(){
return uni.getStorageSync("mescroll-i18n") || this.def return uni.getStorageSync("mescroll-i18n") || this.def
}, },
// 设置当前语言类型 // 设置当前语言类型
setType(type){ setType(type){
uni.setStorageSync("mescroll-i18n", type) uni.setStorageSync("mescroll-i18n", type)
} }
} }
export default mescrollI18n export default mescrollI18n

View File

@ -1,46 +1,46 @@
// mescroll-body 和 mescroll-uni 通用 // mescroll-body 和 mescroll-uni 通用
const MescrollMixin = { const MescrollMixin = {
data() { data() {
return { return {
mescroll: null //mescroll实例对象 mescroll: null //mescroll实例对象
} }
}, },
// 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) // 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
onPullDownRefresh(){ onPullDownRefresh(){
this.mescroll && this.mescroll.onPullDownRefresh(); this.mescroll && this.mescroll.onPullDownRefresh();
}, },
// 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) // 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
onPageScroll(e) { onPageScroll(e) {
this.mescroll && this.mescroll.onPageScroll(e); this.mescroll && this.mescroll.onPageScroll(e);
}, },
// 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) // 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
onReachBottom() { onReachBottom() {
this.mescroll && this.mescroll.onReachBottom(); this.mescroll && this.mescroll.onReachBottom();
}, },
methods: { methods: {
// mescroll组件初始化的回调,可获取到mescroll对象 // mescroll组件初始化的回调,可获取到mescroll对象
mescrollInit(mescroll) { mescrollInit(mescroll) {
this.mescroll = mescroll; this.mescroll = mescroll;
}, },
// 下拉刷新的回调 (mixin默认resetUpScroll) // 下拉刷新的回调 (mixin默认resetUpScroll)
downCallback() { downCallback() {
if(this.mescroll.optUp.use){ if(this.mescroll.optUp.use){
this.mescroll.resetUpScroll() this.mescroll.resetUpScroll()
}else{ }else{
setTimeout(()=>{ setTimeout(()=>{
this.mescroll.endSuccess(); this.mescroll.endSuccess();
}, 500) }, 500)
} }
}, },
// 上拉加载的回调 // 上拉加载的回调
upCallback() { upCallback() {
// mixin默认延时500自动结束加载 // mixin默认延时500自动结束加载
setTimeout(()=>{ setTimeout(()=>{
this.mescroll.endErr(); this.mescroll.endErr();
}, 500) }, 500)
} }
} }
} }
export default MescrollMixin; export default MescrollMixin;

View File

@ -1,64 +1,64 @@
// 全局配置 // 全局配置
// mescroll-body 和 mescroll-uni 通用 // mescroll-body 和 mescroll-uni 通用
const GlobalOption = { const GlobalOption = {
down: { down: {
// 其他down的配置参数也可以写,这里只展示了常用的配置: // 其他down的配置参数也可以写,这里只展示了常用的配置:
offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调
native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
}, },
up: { up: {
// 其他up的配置参数也可以写,这里只展示了常用的配置: // 其他up的配置参数也可以写,这里只展示了常用的配置:
offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance )
toTop: { toTop: {
// 回到顶部按钮,需配置src才显示 // 回到顶部按钮,需配置src才显示
src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png )
offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px
right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx)
}, },
empty: { empty: {
use: true, // 是否显示空布局 use: true, // 是否显示空布局
icon: "https://www.mescroll.com/img/mescroll-empty.png" // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) icon: "https://www.mescroll.com/img/mescroll-empty.png" // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png )
} }
}, },
// 国际化配置 // 国际化配置
i18n: { i18n: {
// 中文 // 中文
zh: { zh: {
down: { down: {
textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本
textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本
textLoading: '加载中 ...', // 加载中的提示文本 textLoading: '加载中 ...', // 加载中的提示文本
textSuccess: '加载成功', // 加载成功的文本 textSuccess: '加载成功', // 加载成功的文本
textErr: '加载失败', // 加载失败的文本 textErr: '加载失败', // 加载失败的文本
}, },
up: { up: {
textLoading: '加载中 ...', // 加载中的提示文本 textLoading: '加载中 ...', // 加载中的提示文本
textNoMore: '没有更多数据', // 没有更多数据的提示文本 textNoMore: '没有更多数据', // 没有更多数据的提示文本
empty: { empty: {
tip: '~ 空空如也 ~' // 空提示 tip: '~ 空空如也 ~' // 空提示
} }
} }
}, },
// 英文 // 英文
en: { en: {
down: { down: {
textInOffset: 'drop down refresh', textInOffset: 'drop down refresh',
textOutOffset: 'release updates', textOutOffset: 'release updates',
textLoading: 'loading ...', textLoading: 'loading ...',
textSuccess: 'loaded successfully', textSuccess: 'loaded successfully',
textErr: 'loading failed' textErr: 'loading failed'
}, },
up: { up: {
textLoading: 'loading ...', textLoading: 'loading ...',
textNoMore: '-- END --', textNoMore: '-- END --',
empty: { empty: {
tip: '~ absolutely empty ~' tip: '~ absolutely empty ~'
} }
} }
} }
} }
} }
export default GlobalOption export default GlobalOption

View File

@ -1,36 +1,36 @@
.mescroll-uni-warp{ .mescroll-uni-warp{
height: 100%; height: 100%;
} }
.mescroll-uni-content{ .mescroll-uni-content{
height: 100%; height: 100%;
} }
.mescroll-uni { .mescroll-uni {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 200rpx; min-height: 200rpx;
overflow-y: auto; overflow-y: auto;
box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */
} }
/* 定位的方式固定高度 */ /* 定位的方式固定高度 */
.mescroll-uni-fixed{ .mescroll-uni-fixed{
z-index: 1; z-index: 1;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
width: auto; /* 使right生效 */ width: auto; /* 使right生效 */
height: auto; /* 使bottom生效 */ height: auto; /* 使bottom生效 */
} }
/* 适配 iPhoneX */ /* 适配 iPhoneX */
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { @supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
.mescroll-safearea { .mescroll-safearea {
padding-bottom: constant(safe-area-inset-bottom); padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
} }
} }

View File

@ -1,480 +1,480 @@
<template> <template>
<view class="mescroll-uni-warp"> <view class="mescroll-uni-warp">
<scroll-view :id="viewId" class="mescroll-uni" :class="{'mescroll-uni-fixed':isFixed}" :style="{'height':scrollHeight,'padding-top':padTop,'padding-bottom':padBottom,'top':fixedTop,'bottom':fixedBottom}" :scroll-top="scrollTop" :scroll-with-animation="scrollAnim" @scroll="scroll" :scroll-y='scrollable' :enable-back-to-top="true" :throttle="false"> <scroll-view :id="viewId" class="mescroll-uni" :class="{'mescroll-uni-fixed':isFixed}" :style="{'height':scrollHeight,'padding-top':padTop,'padding-bottom':padBottom,'top':fixedTop,'bottom':fixedBottom}" :scroll-top="scrollTop" :scroll-with-animation="scrollAnim" @scroll="scroll" :scroll-y='scrollable' :enable-back-to-top="true" :throttle="false">
<view class="mescroll-uni-content mescroll-render-touch" <view class="mescroll-uni-content mescroll-render-touch"
@touchstart="wxsBiz.touchstartEvent" @touchstart="wxsBiz.touchstartEvent"
@touchmove="wxsBiz.touchmoveEvent" @touchmove="wxsBiz.touchmoveEvent"
@touchend="wxsBiz.touchendEvent" @touchend="wxsBiz.touchendEvent"
@touchcancel="wxsBiz.touchendEvent" @touchcancel="wxsBiz.touchendEvent"
:change:prop="wxsBiz.propObserver" :change:prop="wxsBiz.propObserver"
:prop="wxsProp"> :prop="wxsProp">
<!-- 状态栏 --> <!-- 状态栏 -->
<view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view> <view v-if="topbar&&statusBarHeight" class="mescroll-topbar" :style="{height: statusBarHeight+'px', background: topbar}"></view>
<view class="mescroll-wxs-content" :style="{'transform': translateY, 'transition': transition}" :change:prop="wxsBiz.callObserver" :prop="callProp"> <view class="mescroll-wxs-content" :style="{'transform': translateY, 'transition': transition}" :change:prop="wxsBiz.callObserver" :prop="callProp">
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)--> <!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> --> <!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
<view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}"> <view v-if="mescroll.optDown.use" class="mescroll-downwarp" :style="{'background':mescroll.optDown.bgColor,'color':mescroll.optDown.textColor}">
<view class="downwarp-content"> <view class="downwarp-content">
<view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view> <view class="downwarp-progress mescroll-wxs-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'border-color':mescroll.optDown.textColor, 'transform': downRotate}"></view>
<view class="downwarp-tip">{{downText}}</view> <view class="downwarp-tip">{{downText}}</view>
</view> </view>
</view> </view>
<!-- 列表内容 --> <!-- 列表内容 -->
<slot></slot> <slot></slot>
<!-- 空布局 --> <!-- 空布局 -->
<mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty>
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)--> <!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> --> <!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
<view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}"> <view v-if="mescroll.optUp.use && !isDownLoading && upLoadType!==3" class="mescroll-upwarp" :style="{'background':mescroll.optUp.bgColor,'color':mescroll.optUp.textColor}">
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) --> <!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
<view v-show="upLoadType===1"> <view v-show="upLoadType===1">
<view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view> <view class="upwarp-progress mescroll-rotate" :style="{'border-color':mescroll.optUp.textColor}"></view>
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view> <view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
</view> </view>
<!-- 无数据 --> <!-- 无数据 -->
<view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view> <view v-if="upLoadType===2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
</view> </view>
</view> </view>
<!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) --> <!-- 底部是否偏移TabBar的高度(默认仅在H5端的tab页生效) -->
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view> <view v-if="bottombar && windowBottom>0" class="mescroll-bottombar" :style="{height: windowBottom+'px'}"></view>
<!-- #endif --> <!-- #endif -->
<!-- 适配iPhoneX --> <!-- 适配iPhoneX -->
<view v-if="safearea" class="mescroll-safearea"></view> <view v-if="safearea" class="mescroll-safearea"></view>
</view> </view>
</scroll-view> </scroll-view>
<!-- 回到顶部按钮 (fixed元素,需写在scroll-view外面,防止滚动的时候抖动)--> <!-- 回到顶部按钮 (fixed元素,需写在scroll-view外面,防止滚动的时候抖动)-->
<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top> <mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 --> <!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
<!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 --> <!-- renderjs的数据载体,不可写在mescroll-downwarp内部,避免use为false时,载体丢失,无法更新数据 -->
<view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view> <view :change:prop="renderBiz.propObserver" :prop="wxsProp"></view>
<!-- #endif --> <!-- #endif -->
</view> </view>
</template> </template>
<!-- 微信小程序, QQ小程序, app, h5使用wxs --> <!-- 微信小程序, QQ小程序, app, h5使用wxs -->
<!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 --> <!-- #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 -->
<script src="./wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script> <script src="./wxs/wxs.wxs" module="wxsBiz" lang="wxs"></script>
<!-- #endif --> <!-- #endif -->
<!-- app, h5使用renderjs --> <!-- app, h5使用renderjs -->
<!-- #ifdef APP-PLUS || H5 --> <!-- #ifdef APP-PLUS || H5 -->
<script module="renderBiz" lang="renderjs"> <script module="renderBiz" lang="renderjs">
import renderBiz from './wxs/renderjs.js'; import renderBiz from './wxs/renderjs.js';
export default { export default {
mixins:[renderBiz] mixins:[renderBiz]
} }
</script> </script>
<!-- #endif --> <!-- #endif -->
<script> <script>
// mescroll-uni.js, // mescroll-uni.js,
import MeScroll from './mescroll-uni.js'; import MeScroll from './mescroll-uni.js';
// //
import GlobalOption from './mescroll-uni-option.js'; import GlobalOption from './mescroll-uni-option.js';
// //
import mescrollI18n from './mescroll-i18n.js'; import mescrollI18n from './mescroll-i18n.js';
// //
import MescrollTop from './components/mescroll-top.vue'; import MescrollTop from './components/mescroll-top.vue';
// wxs(renderjs)mixins // wxs(renderjs)mixins
import WxsMixin from './wxs/mixins.js'; import WxsMixin from './wxs/mixins.js';
/** /**
* mescroll-uni 嵌在页面某个区域的下拉刷新和上拉加载组件, 如嵌在弹窗,浮层,swiper中... * mescroll-uni 嵌在页面某个区域的下拉刷新和上拉加载组件, 如嵌在弹窗,浮层,swiper中...
* @property {Object} down 下拉刷新的参数配置 * @property {Object} down 下拉刷新的参数配置
* @property {Object} up 上拉加载的参数配置 * @property {Object} up 上拉加载的参数配置
* @property {Object} i18n 国际化的参数配置 * @property {Object} i18n 国际化的参数配置
* @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight) * @property {String, Number} top 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
* @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变) * @property {Boolean, String} topbar 偏移量top是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可留出状态栏的占位, 支持传入字符串背景,如色值,背景图,渐变)
* @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight) * @property {String, Number} bottom 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
* @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用) * @property {Boolean} safearea 偏移量bottom是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
* @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true * @property {Boolean} fixed 是否通过fixed固定mescroll的高度, 默认true
* @property {String, Number} height 指定mescroll的高度, 此项有值,则不使用fixed. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight) * @property {String, Number} height 指定mescroll的高度, 此项有值,则不使用fixed. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
* @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效) * @property {Boolean} bottombar 底部是否偏移TabBar的高度 (仅在H5端的tab页生效)
* @property {Boolean} disableScroll 是否禁止滚动, 默认false * @property {Boolean} disableScroll 是否禁止滚动, 默认false
* @event {Function} init 初始化完成的回调 * @event {Function} init 初始化完成的回调
* @event {Function} down 下拉刷新的回调 * @event {Function} down 下拉刷新的回调
* @event {Function} up 上拉加载的回调 * @event {Function} up 上拉加载的回调
* @event {Function} emptyclick 点击empty配置的btnText按钮回调 * @event {Function} emptyclick 点击empty配置的btnText按钮回调
* @event {Function} topclick 点击回到顶部的按钮回调 * @event {Function} topclick 点击回到顶部的按钮回调
* @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效) * @event {Function} scroll 滚动监听 (需在 up 配置 onScroll:true 才生效)
* @example <mescroll-uni @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-uni> * @example <mescroll-uni @init="mescrollInit" @down="downCallback" @up="upCallback"> ... </mescroll-uni>
*/ */
export default { export default {
name: 'mescroll-uni', name: 'mescroll-uni',
mixins: [WxsMixin], mixins: [WxsMixin],
components: { components: {
MescrollTop MescrollTop
}, },
props: { props: {
down: Object, down: Object,
up: Object, up: Object,
i18n: Object, i18n: Object,
top: [String, Number], top: [String, Number],
topbar: [Boolean, String], topbar: [Boolean, String],
bottom: [String, Number], bottom: [String, Number],
safearea: Boolean, safearea: Boolean,
fixed: { fixed: {
type: Boolean, type: Boolean,
default: true default: true
}, },
height: [String, Number], height: [String, Number],
bottombar:{ bottombar:{
type: Boolean, type: Boolean,
default: true default: true
}, },
disableScroll: Boolean disableScroll: Boolean
}, },
data() { data() {
return { return {
mescroll: {optDown:{},optUp:{}}, // mescroll mescroll: {optDown:{},optUp:{}}, // mescroll
viewId: 'id_' + Math.random().toString(36).substr(2,16), // mescrollid(,) viewId: 'id_' + Math.random().toString(36).substr(2,16), // mescrollid(,)
downHight: 0, //: downHight: 0, //:
downRate: 0, // (inOffset: rate<1; outOffset: rate>=1) downRate: 0, // (inOffset: rate<1; outOffset: rate>=1)
downLoadType: 0, // : 0(loading), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll) downLoadType: 0, // : 0(loading), 1(inOffset), 2(outOffset), 3(showLoading), 4(endDownScroll)
upLoadType: 0, // : 0(loading), 1loading, 2,END, 3(,END) upLoadType: 0, // : 0(loading), 1loading, 2,END, 3(,END)
isShowEmpty: false, // isShowEmpty: false, //
isShowToTop: false, // isShowToTop: false, //
scrollTop: 0, // scrollTop: 0, //
scrollAnim: false, // scrollAnim: false, //
windowTop: 0, // 使 windowTop: 0, // 使
windowBottom: 0, // 使 windowBottom: 0, // 使
windowHeight: 0, // 使 windowHeight: 0, // 使
statusBarHeight: 0 // statusBarHeight: 0 //
} }
}, },
watch: { watch: {
height() { height() {
// //
this.setClientHeight() this.setClientHeight()
} }
}, },
computed: { computed: {
// 使fixed (height,使) // 使fixed (height,使)
isFixed(){ isFixed(){
return !this.height && this.fixed return !this.height && this.fixed
}, },
// mescroll // mescroll
scrollHeight(){ scrollHeight(){
if (this.isFixed) { if (this.isFixed) {
return "auto" return "auto"
} else if(this.height){ } else if(this.height){
return this.toPx(this.height) + 'px' return this.toPx(this.height) + 'px'
}else{ }else{
return "100%" return "100%"
} }
}, },
// (px) // (px)
numTop() { numTop() {
return this.toPx(this.top) return this.toPx(this.top)
}, },
fixedTop() { fixedTop() {
return this.isFixed ? (this.numTop + this.windowTop) + 'px' : 0 return this.isFixed ? (this.numTop + this.windowTop) + 'px' : 0
}, },
padTop() { padTop() {
return !this.isFixed ? this.numTop + 'px' : 0 return !this.isFixed ? this.numTop + 'px' : 0
}, },
// (px) // (px)
numBottom() { numBottom() {
return this.toPx(this.bottom) return this.toPx(this.bottom)
}, },
fixedBottom() { fixedBottom() {
return this.isFixed ? (this.numBottom + this.windowBottom) + 'px' : 0 return this.isFixed ? (this.numBottom + this.windowBottom) + 'px' : 0
}, },
padBottom() { padBottom() {
return !this.isFixed ? this.numBottom + 'px' : 0 return !this.isFixed ? this.numBottom + 'px' : 0
}, },
// //
isDownReset(){ isDownReset(){
return this.downLoadType===3 || this.downLoadType===4 return this.downLoadType===3 || this.downLoadType===4
}, },
// //
transition() { transition() {
return this.isDownReset ? 'transform 300ms' : ''; return this.isDownReset ? 'transform 300ms' : '';
}, },
translateY() { translateY() {
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform使fixed,fixedmescroll return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform使fixed,fixedmescroll
}, },
// //
scrollable(){ scrollable(){
if(this.disableScroll) return false if(this.disableScroll) return false
return this.downLoadType===0 || this.isDownReset return this.downLoadType===0 || this.isDownReset
}, },
// //
isDownLoading(){ isDownLoading(){
return this.downLoadType === 3 return this.downLoadType === 3
}, },
// //
downRotate(){ downRotate(){
return 'rotate(' + 360 * this.downRate + 'deg)' return 'rotate(' + 360 * this.downRate + 'deg)'
}, },
// //
downText(){ downText(){
if(!this.mescroll) return ""; // if(!this.mescroll) return ""; //
switch (this.downLoadType){ switch (this.downLoadType){
case 1: return this.mescroll.optDown.textInOffset; case 1: return this.mescroll.optDown.textInOffset;
case 2: return this.mescroll.optDown.textOutOffset; case 2: return this.mescroll.optDown.textOutOffset;
case 3: return this.mescroll.optDown.textLoading; case 3: return this.mescroll.optDown.textLoading;
case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset; case 4: return this.mescroll.isDownEndSuccess ? this.mescroll.optDown.textSuccess : this.mescroll.isDownEndSuccess==false ? this.mescroll.optDown.textErr : this.mescroll.optDown.textInOffset;
default: return this.mescroll.optDown.textInOffset; default: return this.mescroll.optDown.textInOffset;
} }
} }
}, },
methods: { methods: {
//number,rpx,upx,px,% --> px //number,rpx,upx,px,% --> px
toPx(num){ toPx(num){
if(typeof num === "string"){ if(typeof num === "string"){
if (num.indexOf('px') !== -1) { if (num.indexOf('px') !== -1) {
if(num.indexOf('rpx') !== -1) { // "10rpx" if(num.indexOf('rpx') !== -1) { // "10rpx"
num = num.replace('rpx', ''); num = num.replace('rpx', '');
} else if(num.indexOf('upx') !== -1) { // "10upx" } else if(num.indexOf('upx') !== -1) { // "10upx"
num = num.replace('upx', ''); num = num.replace('upx', '');
} else { // "10px" } else { // "10px"
return Number(num.replace('px', '')) return Number(num.replace('px', ''))
} }
}else if (num.indexOf('%') !== -1){ }else if (num.indexOf('%') !== -1){
// ,windowHeight,"10%"windowHeight10% // ,windowHeight,"10%"windowHeight10%
let rate = Number(num.replace("%","")) / 100 let rate = Number(num.replace("%","")) / 100
return this.windowHeight * rate return this.windowHeight * rate
} }
} }
return num ? uni.upx2px(Number(num)) : 0 return num ? uni.upx2px(Number(num)) : 0
}, },
//, //,
scroll(e) { scroll(e) {
this.mescroll.scroll(e.detail, () => { this.mescroll.scroll(e.detail, () => {
this.$emit('scroll', this.mescroll) // this.mescroll.scrollTop; this.mescroll.isScrollUp this.$emit('scroll', this.mescroll) // this.mescroll.scrollTop; this.mescroll.isScrollUp
}) })
}, },
// //
emptyClick() { emptyClick() {
this.$emit('emptyclick', this.mescroll) this.$emit('emptyclick', this.mescroll)
}, },
// //
toTopClick() { toTopClick() {
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); //
this.$emit('topclick', this.mescroll); // this.$emit('topclick', this.mescroll); //
}, },
// (使,) // (使,)
setClientHeight() { setClientHeight() {
if (!this.isExec) { if (!this.isExec) {
this.isExec = true; // this.isExec = true; //
this.$nextTick(() => { // dom this.$nextTick(() => { // dom
this.getClientInfo(data=>{ this.getClientInfo(data=>{
this.isExec = false; this.isExec = false;
if (data) { if (data) {
this.mescroll.setClientHeight(data.height); this.mescroll.setClientHeight(data.height);
} else if (this.clientNum != 3) { // ,dom,,3 } else if (this.clientNum != 3) { // ,dom,,3
this.clientNum = this.clientNum == null ? 1 : this.clientNum + 1; this.clientNum = this.clientNum == null ? 1 : this.clientNum + 1;
setTimeout(() => { setTimeout(() => {
this.setClientHeight() this.setClientHeight()
}, this.clientNum * 100) }, this.clientNum * 100)
} }
}) })
}) })
} }
}, },
// //
getClientInfo(success){ getClientInfo(success){
let query = uni.createSelectorQuery().in(this); let query = uni.createSelectorQuery().in(this);
let view = query.select('#' + this.viewId); let view = query.select('#' + this.viewId);
view.boundingClientRect(data => { view.boundingClientRect(data => {
success(data) success(data)
}).exec(); }).exec();
} }
}, },
// 使createdmescroll; mountedcssH5 // 使createdmescroll; mountedcssH5
created() { created() {
let vm = this; let vm = this;
let diyOption = { let diyOption = {
// //
down: { down: {
inOffset() { inOffset() {
vm.downLoadType = 1; // offset (mescroll,) vm.downLoadType = 1; // offset (mescroll,)
}, },
outOffset() { outOffset() {
vm.downLoadType = 2; // offset (mescroll,) vm.downLoadType = 2; // offset (mescroll,)
}, },
onMoving(mescroll, rate, downHight) { onMoving(mescroll, rate, downHight) {
// ,; // ,;
vm.downHight = downHight; // (mescroll,) vm.downHight = downHight; // (mescroll,)
vm.downRate = rate; // (inOffset: rate<1; outOffset: rate>=1) vm.downRate = rate; // (inOffset: rate<1; outOffset: rate>=1)
}, },
showLoading(mescroll, downHight) { showLoading(mescroll, downHight) {
vm.downLoadType = 3; // (mescroll,) vm.downLoadType = 3; // (mescroll,)
vm.downHight = downHight; // (mescroll,) vm.downHight = downHight; // (mescroll,)
}, },
beforeEndDownScroll(mescroll){ beforeEndDownScroll(mescroll){
vm.downLoadType = 4; vm.downLoadType = 4;
return mescroll.optDown.beforeEndDelay // return mescroll.optDown.beforeEndDelay //
}, },
endDownScroll() { endDownScroll() {
vm.downLoadType = 4; // (mescroll,) vm.downLoadType = 4; // (mescroll,)
vm.downHight = 0; // (mescroll,) vm.downHight = 0; // (mescroll,)
vm.downResetTimer && clearTimeout(vm.downResetTimer) vm.downResetTimer && clearTimeout(vm.downResetTimer)
vm.downResetTimer = setTimeout(()=>{ // ,0,便this.transition,iOS vm.downResetTimer = setTimeout(()=>{ // ,0,便this.transition,iOS
if(vm.downLoadType===4) vm.downLoadType = 0 if(vm.downLoadType===4) vm.downLoadType = 0
},300) },300)
}, },
// //
callback: function(mescroll) { callback: function(mescroll) {
vm.$emit('down', mescroll) vm.$emit('down', mescroll)
} }
}, },
// //
up: { up: {
// //
showLoading() { showLoading() {
vm.upLoadType = 1; vm.upLoadType = 1;
}, },
// //
showNoMore() { showNoMore() {
vm.upLoadType = 2; vm.upLoadType = 2;
}, },
// //
hideUpScroll(mescroll) { hideUpScroll(mescroll) {
vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3; vm.upLoadType = mescroll.optUp.hasNext ? 0 : 3;
}, },
// //
empty: { empty: {
onShow(isShow) { // onShow(isShow) { //
vm.isShowEmpty = isShow; vm.isShowEmpty = isShow;
} }
}, },
// //
toTop: { toTop: {
onShow(isShow) { // onShow(isShow) { //
vm.isShowToTop = isShow; vm.isShowToTop = isShow;
} }
}, },
// //
callback: function(mescroll) { callback: function(mescroll) {
vm.$emit('up', mescroll); vm.$emit('up', mescroll);
// (mescroll) // (mescroll)
vm.setClientHeight() vm.setClientHeight()
} }
} }
} }
let i18nType = mescrollI18n.getType() // let i18nType = mescrollI18n.getType() //
let i18nOption = {type: i18nType} // let i18nOption = {type: i18nType} //
MeScroll.extend(i18nOption, vm.i18n) // MeScroll.extend(i18nOption, vm.i18n) //
MeScroll.extend(i18nOption, GlobalOption.i18n) // MeScroll.extend(i18nOption, GlobalOption.i18n) //
MeScroll.extend(diyOption, i18nOption[i18nType]); // MeScroll.extend(diyOption, i18nOption[i18nType]); //
MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); // MeScroll.extend(diyOption, {down:GlobalOption.down, up:GlobalOption.up}); //
let myOption = JSON.parse(JSON.stringify({'down': vm.down,'up': vm.up})) // ,props let myOption = JSON.parse(JSON.stringify({'down': vm.down,'up': vm.up})) // ,props
MeScroll.extend(myOption, diyOption); // MeScroll.extend(myOption, diyOption); //
// MeScroll // MeScroll
vm.mescroll = new MeScroll(myOption); vm.mescroll = new MeScroll(myOption);
vm.mescroll.viewId = vm.viewId; // id vm.mescroll.viewId = vm.viewId; // id
vm.mescroll.i18n = i18nOption; // vm.mescroll.i18n = i18nOption; //
// initmescroll // initmescroll
vm.$emit('init', vm.mescroll); vm.$emit('init', vm.mescroll);
// //
const sys = uni.getSystemInfoSync(); const sys = uni.getSystemInfoSync();
if(sys.windowTop) vm.windowTop = sys.windowTop; if(sys.windowTop) vm.windowTop = sys.windowTop;
if(sys.windowBottom) vm.windowBottom = sys.windowBottom; if(sys.windowBottom) vm.windowBottom = sys.windowBottom;
if(sys.windowHeight) vm.windowHeight = sys.windowHeight; if(sys.windowHeight) vm.windowHeight = sys.windowHeight;
if(sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight; if(sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
// 使downbottomOffset // 使downbottomOffset
vm.mescroll.setBodyHeight(sys.windowHeight); vm.mescroll.setBodyHeight(sys.windowHeight);
// 使scrollview,scrollTo // 使scrollview,scrollTo
vm.mescroll.resetScrollTo((y, t) => { vm.mescroll.resetScrollTo((y, t) => {
vm.scrollAnim = (t !== 0); // t0,使 vm.scrollAnim = (t !== 0); // t0,使
if(typeof y === 'string'){ if(typeof y === 'string'){
// slotscroll-into-view, 使 // slotscroll-into-view, 使
vm.getClientInfo(function(rect){ vm.getClientInfo(function(rect){
let mescrollTop = rect.top // mescroll let mescrollTop = rect.top // mescroll
let selector; let selector;
if(y.indexOf('#')==-1 && y.indexOf('.')==-1){ if(y.indexOf('#')==-1 && y.indexOf('.')==-1){
selector = '#'+y // #. id selector = '#'+y // #. id
}else{ }else{
selector = y selector = y
// #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK // #ifdef APP-PLUS || H5 || MP-ALIPAY || MP-DINGTALK
if(y.indexOf('>>>')!=-1){ // () if(y.indexOf('>>>')!=-1){ // ()
selector = y.split('>>>')[1].trim() selector = y.split('>>>')[1].trim()
} }
// #endif // #endif
} }
uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){ uni.createSelectorQuery().select(selector).boundingClientRect(function(rect){
if (rect) { if (rect) {
let curY = vm.mescroll.getScrollTop() let curY = vm.mescroll.getScrollTop()
let top = rect.top - mescrollTop let top = rect.top - mescrollTop
top += curY top += curY
if(!vm.isFixed) top -= vm.numTop if(!vm.isFixed) top -= vm.numTop
vm.scrollTop = curY; vm.scrollTop = curY;
vm.$nextTick(function() { vm.$nextTick(function() {
vm.scrollTop = top vm.scrollTop = top
}) })
} else{ } else{
console.error(selector + ' does not exist'); console.error(selector + ' does not exist');
} }
}).exec() }).exec()
}) })
return; return;
} }
let curY = vm.mescroll.getScrollTop() let curY = vm.mescroll.getScrollTop()
if (t === 0 || t === 300) { // t使300,使 if (t === 0 || t === 300) { // t使300,使
vm.scrollTop = curY; vm.scrollTop = curY;
vm.$nextTick(function() { vm.$nextTick(function() {
vm.scrollTop = y vm.scrollTop = y
}) })
} else { } else {
vm.mescroll.getStep(curY, y, step => { // t vm.mescroll.getStep(curY, y, step => { // t
vm.scrollTop = step vm.scrollTop = step
}, t) }, t)
} }
}) })
// up.toTop.safearea,vuesafearea // up.toTop.safearea,vuesafearea
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else { if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
vm.mescroll.optUp.toTop.safearea = vm.safearea; vm.mescroll.optUp.toTop.safearea = vm.safearea;
} }
// //
uni.$on("setMescrollGlobalOption", options=>{ uni.$on("setMescrollGlobalOption", options=>{
if(!options) return; if(!options) return;
let i18nType = options.i18n ? options.i18n.type : null let i18nType = options.i18n ? options.i18n.type : null
if(i18nType && vm.mescroll.i18n.type != i18nType){ if(i18nType && vm.mescroll.i18n.type != i18nType){
vm.mescroll.i18n.type = i18nType vm.mescroll.i18n.type = i18nType
mescrollI18n.setType(i18nType) mescrollI18n.setType(i18nType)
MeScroll.extend(options, vm.mescroll.i18n[i18nType]) MeScroll.extend(options, vm.mescroll.i18n[i18nType])
} }
if(options.down){ if(options.down){
let down = MeScroll.extend({}, options.down) let down = MeScroll.extend({}, options.down)
vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown) vm.mescroll.optDown = MeScroll.extend(down, vm.mescroll.optDown)
} }
if(options.up){ if(options.up){
let up = MeScroll.extend({}, options.up) let up = MeScroll.extend({}, options.up)
vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp) vm.mescroll.optUp = MeScroll.extend(up, vm.mescroll.optUp)
} }
}) })
}, },
mounted() { mounted() {
// //
this.setClientHeight() this.setClientHeight()
}, },
destroyed() { destroyed() {
// //
uni.$off("setMescrollGlobalOption") uni.$off("setMescrollGlobalOption")
} }
} }
</script> </script>
<style> <style>
@import "./mescroll-uni.css"; @import "./mescroll-uni.css";
@import "./components/mescroll-down.css"; @import "./components/mescroll-down.css";
@import './components/mescroll-up.css'; @import './components/mescroll-up.css';
</style> </style>

View File

@ -1,47 +1,47 @@
/** /**
* mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期 * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期
*/ */
const MescrollCompMixin = { const MescrollCompMixin = {
// 因为子组件无onPageScroll和onReachBottom的页面生命周期需在页面传递进到子组件 (一级) // 因为子组件无onPageScroll和onReachBottom的页面生命周期需在页面传递进到子组件 (一级)
onPageScroll(e) { onPageScroll(e) {
this.handlePageScroll(e) this.handlePageScroll(e)
}, },
onReachBottom() { onReachBottom() {
this.handleReachBottom() this.handleReachBottom()
}, },
// 当down的native: true时, 还需传递此方法进到子组件 // 当down的native: true时, 还需传递此方法进到子组件
onPullDownRefresh(){ onPullDownRefresh(){
this.handlePullDownRefresh() this.handlePullDownRefresh()
}, },
data() { data() {
return { return {
mescroll: { // mescroll-body写在子子子...组件的情况 (多级) mescroll: { // mescroll-body写在子子子...组件的情况 (多级)
onPageScroll: e=>{ onPageScroll: e=>{
this.handlePageScroll(e) this.handlePageScroll(e)
}, },
onReachBottom: ()=>{ onReachBottom: ()=>{
this.handleReachBottom() this.handleReachBottom()
}, },
onPullDownRefresh: ()=>{ onPullDownRefresh: ()=>{
this.handlePullDownRefresh() this.handlePullDownRefresh()
} }
} }
} }
}, },
methods:{ methods:{
handlePageScroll(e){ handlePageScroll(e){
let item = this.$refs["mescrollItem"]; let item = this.$refs["mescrollItem"];
if(item && item.mescroll) item.mescroll.onPageScroll(e); if(item && item.mescroll) item.mescroll.onPageScroll(e);
}, },
handleReachBottom(){ handleReachBottom(){
let item = this.$refs["mescrollItem"]; let item = this.$refs["mescrollItem"];
if(item && item.mescroll) item.mescroll.onReachBottom(); if(item && item.mescroll) item.mescroll.onReachBottom();
}, },
handlePullDownRefresh(){ handlePullDownRefresh(){
let item = this.$refs["mescrollItem"]; let item = this.$refs["mescrollItem"];
if(item && item.mescroll) item.mescroll.onPullDownRefresh(); if(item && item.mescroll) item.mescroll.onPullDownRefresh();
} }
} }
} }
export default MescrollCompMixin; export default MescrollCompMixin;

View File

@ -1,57 +1,57 @@
/** /**
* mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例) * mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例)
*/ */
const MescrollMoreItemMixin = { const MescrollMoreItemMixin = {
// 支付宝小程序不支持props的mixin,需写在具体的页面中 // 支付宝小程序不支持props的mixin,需写在具体的页面中
// #ifndef MP-ALIPAY || MP-DINGTALK // #ifndef MP-ALIPAY || MP-DINGTALK
props:{ props:{
i: Number, // 每个tab页的专属下标 i: Number, // 每个tab页的专属下标
index: { // 当前tab的下标 index: { // 当前tab的下标
type: Number, type: Number,
default(){ default(){
return 0 return 0
} }
} }
}, },
// #endif // #endif
data() { data() {
return { return {
downOption:{ downOption:{
auto:false // 不自动加载 auto:false // 不自动加载
}, },
upOption:{ upOption:{
auto:false // 不自动加载 auto:false // 不自动加载
}, },
isInit: false // 当前tab是否已初始化 isInit: false // 当前tab是否已初始化
} }
}, },
watch:{ watch:{
// 监听下标的变化 // 监听下标的变化
index(val){ index(val){
if (this.i === val && !this.isInit) this.mescrollTrigger() if (this.i === val && !this.isInit) this.mescrollTrigger()
} }
}, },
methods: { methods: {
// mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit) // mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit)
mescrollInit(mescroll) { mescrollInit(mescroll) {
this.mescroll = mescroll; this.mescroll = mescroll;
// 自动加载当前tab的数据 // 自动加载当前tab的数据
if(this.i === this.index){ if(this.i === this.index){
this.mescrollTrigger() this.mescrollTrigger()
} }
}, },
// 主动触发加载 // 主动触发加载
mescrollTrigger(){ mescrollTrigger(){
this.isInit = true; // 标记为true this.isInit = true; // 标记为true
if (this.mescroll) { if (this.mescroll) {
if (this.mescroll.optDown.use) { if (this.mescroll.optDown.use) {
this.mescroll.triggerDownScroll(); this.mescroll.triggerDownScroll();
} else{ } else{
this.mescroll.triggerUpScroll(); this.mescroll.triggerUpScroll();
} }
} }
} }
} }
} }
export default MescrollMoreItemMixin; export default MescrollMoreItemMixin;

View File

@ -1,77 +1,77 @@
/** /**
* mescroll-body写在子组件时, 需通过mescroll的mixins补充子组件缺少的生命周期 * mescroll-body写在子组件时, 需通过mescroll的mixins补充子组件缺少的生命周期
*/ */
const MescrollMoreMixin = { const MescrollMoreMixin = {
data() { data() {
return { return {
tabIndex: 0, // 当前tab下标 tabIndex: 0, // 当前tab下标
mescroll: { // mescroll-body写在子子子...组件的情况 (多级) mescroll: { // mescroll-body写在子子子...组件的情况 (多级)
onPageScroll: e=>{ onPageScroll: e=>{
this.handlePageScroll(e) this.handlePageScroll(e)
}, },
onReachBottom: ()=>{ onReachBottom: ()=>{
this.handleReachBottom() this.handleReachBottom()
}, },
onPullDownRefresh: ()=>{ onPullDownRefresh: ()=>{
this.handlePullDownRefresh() this.handlePullDownRefresh()
} }
} }
} }
}, },
// 因为子组件无onPageScroll和onReachBottom的页面生命周期需在页面传递进到子组件 // 因为子组件无onPageScroll和onReachBottom的页面生命周期需在页面传递进到子组件
onPageScroll(e) { onPageScroll(e) {
this.handlePageScroll(e) this.handlePageScroll(e)
}, },
onReachBottom() { onReachBottom() {
this.handleReachBottom() this.handleReachBottom()
}, },
// 当down的native: true时, 还需传递此方法进到子组件 // 当down的native: true时, 还需传递此方法进到子组件
onPullDownRefresh(){ onPullDownRefresh(){
this.handlePullDownRefresh() this.handlePullDownRefresh()
}, },
methods:{ methods:{
handlePageScroll(e){ handlePageScroll(e){
let mescroll = this.getMescroll(this.tabIndex); let mescroll = this.getMescroll(this.tabIndex);
mescroll && mescroll.onPageScroll(e); mescroll && mescroll.onPageScroll(e);
}, },
handleReachBottom(){ handleReachBottom(){
let mescroll = this.getMescroll(this.tabIndex); let mescroll = this.getMescroll(this.tabIndex);
mescroll && mescroll.onReachBottom(); mescroll && mescroll.onReachBottom();
}, },
handlePullDownRefresh(){ handlePullDownRefresh(){
let mescroll = this.getMescroll(this.tabIndex); let mescroll = this.getMescroll(this.tabIndex);
mescroll && mescroll.onPullDownRefresh(); mescroll && mescroll.onPullDownRefresh();
}, },
// 根据下标获取对应子组件的mescroll // 根据下标获取对应子组件的mescroll
getMescroll(i){ getMescroll(i){
if(!this.mescrollItems) this.mescrollItems = []; if(!this.mescrollItems) this.mescrollItems = [];
if(!this.mescrollItems[i]) { if(!this.mescrollItems[i]) {
// v-for中的refs // v-for中的refs
let vForItem = this.$refs["mescrollItem"]; let vForItem = this.$refs["mescrollItem"];
if(vForItem){ if(vForItem){
this.mescrollItems[i] = vForItem[i] this.mescrollItems[i] = vForItem[i]
}else{ }else{
// 普通的refs,不可重复 // 普通的refs,不可重复
this.mescrollItems[i] = this.$refs["mescrollItem"+i]; this.mescrollItems[i] = this.$refs["mescrollItem"+i];
} }
} }
let item = this.mescrollItems[i] let item = this.mescrollItems[i]
return item ? item.mescroll : null return item ? item.mescroll : null
}, },
// 切换tab,恢复滚动条位置 // 切换tab,恢复滚动条位置
tabChange(i){ tabChange(i){
let mescroll = this.getMescroll(i); let mescroll = this.getMescroll(i);
if(mescroll){ if(mescroll){
// 恢复上次滚动条的位置 // 恢复上次滚动条的位置
let y = mescroll.getScrollTop() let y = mescroll.getScrollTop()
mescroll.scrollTo(y, 0) mescroll.scrollTo(y, 0)
// 再次恢复上次滚动条的位置, 确保元素已渲染 // 再次恢复上次滚动条的位置, 确保元素已渲染
setTimeout(()=>{ setTimeout(()=>{
mescroll.scrollTo(y, 0) mescroll.scrollTo(y, 0)
},30) },30)
} }
} }
} }
} }
export default MescrollMoreMixin; export default MescrollMoreMixin;

View File

@ -1,109 +1,109 @@
// 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信 // 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信
const WxsMixin = { const WxsMixin = {
data() { data() {
return { return {
// 传入wxs视图层的数据 (响应式) // 传入wxs视图层的数据 (响应式)
wxsProp: { wxsProp: {
optDown:{}, // 下拉刷新的配置 optDown:{}, // 下拉刷新的配置
scrollTop:0, // 滚动条的距离 scrollTop:0, // 滚动条的距离
bodyHeight:0, // body的高度 bodyHeight:0, // body的高度
isDownScrolling:false, // 是否正在下拉刷新中 isDownScrolling:false, // 是否正在下拉刷新中
isUpScrolling:false, // 是否正在上拉加载中 isUpScrolling:false, // 是否正在上拉加载中
isScrollBody:true, // 是否为mescroll-body滚动 isScrollBody:true, // 是否为mescroll-body滚动
isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新 isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新
t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer)
}, },
// 标记调用wxs视图层的方法 // 标记调用wxs视图层的方法
callProp: { callProp: {
callType: '', // 方法名 callType: '', // 方法名
t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer)
}, },
// 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs) // 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs)
// #ifndef MP-WEIXIN || MP-QQ || APP-PLUS || H5 // #ifndef MP-WEIXIN || MP-QQ || APP-PLUS || H5
wxsBiz: { wxsBiz: {
//注册列表touchstart事件,用于下拉刷新 //注册列表touchstart事件,用于下拉刷新
touchstartEvent: e=> { touchstartEvent: e=> {
this.mescroll.touchstartEvent(e); this.mescroll.touchstartEvent(e);
}, },
//注册列表touchmove事件,用于下拉刷新 //注册列表touchmove事件,用于下拉刷新
touchmoveEvent: e=> { touchmoveEvent: e=> {
this.mescroll.touchmoveEvent(e); this.mescroll.touchmoveEvent(e);
}, },
//注册列表touchend事件,用于下拉刷新 //注册列表touchend事件,用于下拉刷新
touchendEvent: e=> { touchendEvent: e=> {
this.mescroll.touchendEvent(e); this.mescroll.touchendEvent(e);
}, },
propObserver(){}, // 抹平wxs的写法 propObserver(){}, // 抹平wxs的写法
callObserver(){} // 抹平wxs的写法 callObserver(){} // 抹平wxs的写法
}, },
// #endif // #endif
// 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js) // 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js)
// #ifndef APP-PLUS || H5 // #ifndef APP-PLUS || H5
renderBiz: { renderBiz: {
propObserver(){} // 抹平renderjs的写法 propObserver(){} // 抹平renderjs的写法
} }
// #endif // #endif
} }
}, },
methods: { methods: {
// wxs视图层调用逻辑层的回调 // wxs视图层调用逻辑层的回调
wxsCall(msg){ wxsCall(msg){
if(msg.type === 'setWxsProp'){ if(msg.type === 'setWxsProp'){
// 更新wxsProp数据 (值改变才触发更新) // 更新wxsProp数据 (值改变才触发更新)
this.wxsProp = { this.wxsProp = {
optDown: this.mescroll.optDown, optDown: this.mescroll.optDown,
scrollTop: this.mescroll.getScrollTop(), scrollTop: this.mescroll.getScrollTop(),
bodyHeight: this.mescroll.getBodyHeight(), bodyHeight: this.mescroll.getBodyHeight(),
isDownScrolling: this.mescroll.isDownScrolling, isDownScrolling: this.mescroll.isDownScrolling,
isUpScrolling: this.mescroll.isUpScrolling, isUpScrolling: this.mescroll.isUpScrolling,
isUpBoth: this.mescroll.optUp.isBoth, isUpBoth: this.mescroll.optUp.isBoth,
isScrollBody:this.mescroll.isScrollBody, isScrollBody:this.mescroll.isScrollBody,
t: Date.now() t: Date.now()
} }
}else if(msg.type === 'setLoadType'){ }else if(msg.type === 'setLoadType'){
// 设置inOffset,outOffset的状态 // 设置inOffset,outOffset的状态
this.downLoadType = msg.downLoadType this.downLoadType = msg.downLoadType
// 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中 // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中
this.$set(this.mescroll, 'downLoadType', this.downLoadType) this.$set(this.mescroll, 'downLoadType', this.downLoadType)
// 重置是否加载成功的状态 // 重置是否加载成功的状态
this.$set(this.mescroll, 'isDownEndSuccess', null) this.$set(this.mescroll, 'isDownEndSuccess', null)
}else if(msg.type === 'triggerDownScroll'){ }else if(msg.type === 'triggerDownScroll'){
// 主动触发下拉刷新 // 主动触发下拉刷新
this.mescroll.triggerDownScroll(); this.mescroll.triggerDownScroll();
}else if(msg.type === 'endDownScroll'){ }else if(msg.type === 'endDownScroll'){
// 结束下拉刷新 // 结束下拉刷新
this.mescroll.endDownScroll(); this.mescroll.endDownScroll();
}else if(msg.type === 'triggerUpScroll'){ }else if(msg.type === 'triggerUpScroll'){
// 主动触发上拉加载 // 主动触发上拉加载
this.mescroll.triggerUpScroll(true); this.mescroll.triggerUpScroll(true);
} }
} }
}, },
mounted() { mounted() {
// #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 // #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5
// 配置主动触发wxs显示加载进度的回调 // 配置主动触发wxs显示加载进度的回调
this.mescroll.optDown.afterLoading = ()=>{ this.mescroll.optDown.afterLoading = ()=>{
this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
} }
// 配置主动触发wxs隐藏加载进度的回调 // 配置主动触发wxs隐藏加载进度的回调
this.mescroll.optDown.afterEndDownScroll = ()=>{ this.mescroll.optDown.afterEndDownScroll = ()=>{
this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
let delay = 300 + (this.mescroll.optDown.beforeEndDelay || 0) let delay = 300 + (this.mescroll.optDown.beforeEndDelay || 0)
setTimeout(()=>{ setTimeout(()=>{
if(this.downLoadType === 4 || this.downLoadType === 0){ if(this.downLoadType === 4 || this.downLoadType === 0){
this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新)
} }
// 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中 // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如<me-video>中
this.$set(this.mescroll, 'downLoadType', this.downLoadType) this.$set(this.mescroll, 'downLoadType', this.downLoadType)
}, delay) }, delay)
} }
// 初始化wxs的数据 // 初始化wxs的数据
this.wxsCall({type: 'setWxsProp'}) this.wxsCall({type: 'setWxsProp'})
// #endif // #endif
} }
} }
export default WxsMixin; export default WxsMixin;

Some files were not shown because too many files have changed in this diff Show More