commit 68d9870c7ce7a8932ad92b940aa9dcfeb7479ba1 Author: wzgaoyn Date: Thu Mar 20 13:47:59 2025 +0800 初始提交 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fb43e5c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..58ea8d4 --- /dev/null +++ b/.env.development @@ -0,0 +1,17 @@ +# 如需添加更多环境变量,请以 VITE_APP_ 开头声明 +# 在代码中使用 import.meta.env.VITE_APP_XXX 获取指定变量 +# 环境配置标识 +VITE_APP_ENV = 'development' + +# 微信公众号appid +VITE_APP_MP_APPID = 'wx42bbe857570c5b40' + +# 统一接口域名 +VITE_APP_BASE_API = 'https://cloud-api-test.mall4j.com' + + +# 图片域名 +VITE_APP_RESOURCES_URL = 'https://mall4j-minio-test.mall4j.com/mall4cloud/' + +# 腾讯地图key (WebServiceAPI) 用于IP定位 & 地址位置解析 +VITE_APP_MAP_KEY = 'L4DBZ-VSSKJ-GCDFX-KGBVR-KHZ2J-RNF2Q' diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..bec9040 --- /dev/null +++ b/.env.production @@ -0,0 +1,16 @@ +# 如需添加更多环境变量,请以 VITE_APP_ 开头声明 +# 在代码中使用 import.meta.env.VITE_APP_XXX 获取指定变量 +# 环境配置标识 +VITE_APP_ENV = 'production' + +# 微信公众号appid +VITE_APP_MP_APPID = 'wx42bbe857570c5b40' + +# 统一接口域名 +VITE_APP_BASE_API = 'https://cloud-api.mall4j.com' + +# 图片域名 +VITE_APP_RESOURCES_URL = 'https://mall4cloud.oss-cn-guangzhou.aliyuncs.com' + +# 腾讯地图key (WebServiceAPI) 用于IP定位 & 地址位置解析 +VITE_APP_MAP_KEY = '' diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..a66c6af --- /dev/null +++ b/.env.testing @@ -0,0 +1,18 @@ +# 如需添加更多环境变量,请以 VITE_APP_ 开头声明 +# 在代码中使用 import.meta.env.VITE_APP_XXX 获取指定变量 +# 环境配置标识 +VITE_APP_ENV = 'testing' + +# 微信公众号appid +VITE_APP_MP_APPID = 'wx42bbe857570c5b40' + +# 统一接口域名 +VITE_APP_BASE_API = 'https://cloud-api-vue3.mall4j.com' + +# 图片域名 +VITE_APP_RESOURCES_URL = 'https://img.mall4j.com/' + +# 腾讯地图key (WebServiceAPI) 用于IP定位 & 地址位置解析 +# 同时需要配置到 manifest配置文件 h5 -> sdkConfigs -> maps -> qqmap -> key +VITE_APP_MAP_KEY = '' + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0ee3a0b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,17 @@ +# eslint 忽略列表 +src/utils/wxqrcode.js + +# disk编译目录 +dist + +build/*.js +src/assets +src/components/tki-barcode +src/uni_modules +src/utils/jwx +src/js_sdk +src/shime.uni.d.ts +public + +uni_modules +auto-imports.d.ts diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json new file mode 100644 index 0000000..51fe0a0 --- /dev/null +++ b/.eslintrc-auto-import.json @@ -0,0 +1,97 @@ +{ + "globals": { + "Component": true, + "ComponentPublicInstance": true, + "ComputedRef": true, + "EffectScope": true, + "InjectionKey": true, + "PropType": true, + "Ref": true, + "VNode": true, + "computed": true, + "createApp": true, + "customRef": true, + "defineAsyncComponent": true, + "defineComponent": true, + "effectScope": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "h": true, + "inject": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "markRaw": true, + "nextTick": true, + "onActivated": true, + "onBeforeMount": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onDeactivated": true, + "onErrorCaptured": true, + "onMounted": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onUnmounted": true, + "onUpdated": true, + "provide": true, + "reactive": true, + "readonly": true, + "ref": true, + "resolveComponent": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "toRaw": true, + "toRef": true, + "toRefs": true, + "toValue": true, + "triggerRef": true, + "unref": true, + "useAttrs": true, + "useCssModule": true, + "useCssVars": true, + "useSlots": true, + "watch": true, + "watchEffect": true, + "watchPostEffect": true, + "watchSyncEffect": true, + "onAddToFavorites": true, + "onBackPress": true, + "onError": true, + "onHide": true, + "onLaunch": true, + "onLoad": true, + "onNavigationBarButtonTap": true, + "onNavigationBarSearchInputChanged": true, + "onNavigationBarSearchInputClicked": true, + "onNavigationBarSearchInputConfirmed": true, + "onNavigationBarSearchInputFocusChanged": true, + "onPageNotFound": true, + "onPageScroll": true, + "onPullDownRefresh": true, + "onReachBottom": true, + "onReady": true, + "onResize": true, + "onShareAppMessage": true, + "onShareTimeline": true, + "onShow": true, + "onTabItemTap": true, + "onThemeChange": true, + "onUnhandledRejection": true, + "onUnload": true, + "encrypt": true, + "http": true, + "wechat": true, + "util": true, + "number": true, + "createQrCodeImg": true, + "ExtractDefaultPropTypes": true, + "ExtractPropTypes": true, + "ExtractPublicPropTypes": true, + "WritableComputedRef": true + } +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4abe9f8 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,86 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true + }, + globals: { + uni: 'readonly', + getApp: 'readonly', + wx: 'readonly', + getCurrentPages: 'readonly', + plus: 'readonly' + }, + extends: [ + 'standard', + './.eslintrc-auto-import.json', + 'plugin:vue/vue3-recommended', + 'plugin:vue-scoped-css/vue3-recommended' + ], + overrides: [ + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module' + }, + plugins: [ + 'vue' + ], + rules: { + // Possible Errors + // 要求使用 let 或 const 而不是 var + 'no-var': 'error', + // 强制 "for" 循环中更新子句的计数器朝着正确的方向移动 + 'for-direction': 'error', + // 强制 getter 函数中出现 return 语句 + 'getter-return': 'error', + // 禁止在嵌套的块中出现变量声明或 function 声明 + 'no-inner-declarations': 'error', + // 禁止由于 await 或 yield的使用而可能导致出现竞态条件的赋值 + 'require-atomic-updates': 'error', + // console 警告 + 'no-console': 'warn', + // 禁止出现未使用过的变量 + 'no-unused-vars': [ + 'warn', + { + args: 'all', + caughtErrors: 'none', + ignoreRestSiblings: true, + vars: 'all' + } + ], + // 关闭名称校验 + 'vue/multi-word-component-names': 'off', + // 非生产环境启用 debugger + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + + // Best Practices + eqeqeq: 'off', + + // Stylistic Issues + // 强制可嵌套的块的最大深度 + 'max-depth': ['error', 5], + // 强制函数最大代码行数 + 'max-lines-per-function': [ + 'error', + { + max: 150, + skipBlankLines: true + } + ], + // 强制回调函数最大嵌套深度 + 'max-nested-callbacks': ['error', { max: 10 }], + // 强制函数定义中最多允许的参数数量 + 'max-params': ['error', { max: 5 }], + // 强制每一行中所允许的最大语句数量 + 'max-statements-per-line': ['error', { max: 1 }], + // 三目运算符换行 + 'multiline-ternary': ['error', 'never'], + // 传值给组件时的使用 kebab-case + 'vue/v-on-event-hyphenation': ['warn', 'always', { + autofix: true, + ignore: [] + }] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3335c4e --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +.DS_Store +node_modules/ +unpackage/ +dist/ + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +pnpm-lock.yaml + +# Editor directories and files +.project +.idea +.vscode +.hbuilderx +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* + +src/auto-import diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..26e0c55 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run lint:staged diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..febf696 --- /dev/null +++ b/.npmrc @@ -0,0 +1,4 @@ +engine-strict = true +shamefully-hoist = true +strict-peer-dependencies = false +registry = https://registry.npmmirror.com diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..44a06c1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:1.20 +COPY ./dist/build/h5 /usr/share/nginx/html/h5/station +COPY ./nginx.conf /etc/nginx/conf.d \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/index.html b/index.html new file mode 100644 index 0000000..49a498b --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + +
+ + + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..78c48a8 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,26 @@ +server { + listen 80; + server_name h5.mall4j.com; + + location /station { + try_files $uri $uri/ /station/; + root /usr/share/nginx/html/h5; + index index.html; + + #### kill cache + add_header Last-Modified $date_gmt; + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + if_modified_since off; + expires off; + etag off; + } + + error_page 404 /404.html; + location = /404-light.html { + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + } +} + diff --git a/package.json b/package.json new file mode 100644 index 0000000..cc6b95d --- /dev/null +++ b/package.json @@ -0,0 +1,80 @@ +{ + "name": "mall4cloud-station", + "private": true, + "version": "0.0.0", + "scripts": { + "preinstall": "npx only-allow pnpm", + "dev:custom": "uni -p", + "dev:h5": "uni", + "dev:h5-test": "uni --mode testing", + "build:custom": "uni build -p", + "build:h5": "uni build", + "build:h5-test": "uni build --mode testing --outDir ./dist/build/test-h5", + "prepare": "husky install", + "lint:staged": "lint-staged" + }, + "dependencies": { + "@dcloudio/uni-app": "3.0.0-3090920231225001", + "@dcloudio/uni-app-plus": "3.0.0-3090920231225001", + "@dcloudio/uni-components": "3.0.0-3090920231225001", + "@dcloudio/uni-h5": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-alipay": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-baidu": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-jd": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-kuaishou": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-lark": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-qq": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-toutiao": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-weixin": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001", + "@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001", + "@uni-ui/code-ui": "1.5.3", + "crypto-js": "4.2.0", + "vite-plugin-commonjs": "0.10.1", + "vue": "3.3.8" + }, + "devDependencies": { + "@dcloudio/types": "3.4.3", + "@dcloudio/uni-automator": "3.0.0-3090920231225001", + "@dcloudio/uni-cli-shared": "3.0.0-3090920231225001", + "@dcloudio/uni-stacktracey": "3.0.0-3090920231225001", + "@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001", + "@vitejs/plugin-legacy": "4.1.1", + "@vue/runtime-core": "^3.2.45", + "eslint": "8.53.0", + "eslint-config-standard": "17.1.0", + "eslint-plugin-import": "2.29.0", + "eslint-plugin-n": "16.3.1", + "eslint-plugin-promise": "6.1.1", + "eslint-plugin-vue": "9.18.1", + "eslint-plugin-vue-scoped-css": "2.5.1", + "husky": "8.0.3", + "lint-staged": "15.1.0", + "sass": "1.69.5", + "terser": "5.24.0", + "unplugin-auto-import": "0.16.7", + "unplugin-vue-components": "0.25.2", + "vite": "4.5.0", + "vue-eslint-parser": "9.3.2" + }, + "lint-staged": { + "*.{js,vue}": [ + "eslint --fix" + ] + }, + "engines": { + "node": ">=18.12.0", + "pnpm": ">=7" + }, + "pnpm": { + "peerDependencyRules": { + "ignoreMissing": [ + "@babel/core*", + "jest*", + "postcss*", + "regenerator-runtime*", + "url*" + ] + } + } +} diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..7708b09 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,32 @@ + + + + diff --git a/src/app.scss b/src/app.scss new file mode 100644 index 0000000..64f9875 --- /dev/null +++ b/src/app.scss @@ -0,0 +1,37 @@ + +/* 隐藏头部 */ +uni-page-head { + display: none; +} + +.container { + height: 100%; + box-sizing: border-box; + color: #333; + font-family: helvetica, 'Heiti SC', PingFangSC-Light, sans-serif; +} + + +/* +*改变radio样式 +*自定义样式 +*/ +/* 未选中的 背景样式 */ +uni-radio .uni-radio-input{ + height: 36rpx; + width: 36rpx; + border-radius: 50%; + background: transparent; + box-sizing: border-box; + } + + /* z-paging 返回顶部按钮的图片样式 */ +.zp-back-to-top-img { + width: 40rpx !important; + height: 40rpx !important; +} +/* z-paging 底部加载更多的loading样式 */ +.zp-line-loading-image{ + width: 24rpx !important; + height: 24rpx !important; +} \ No newline at end of file diff --git a/src/components/area-picker/area-picker.vue b/src/components/area-picker/area-picker.vue new file mode 100644 index 0000000..f9f55fd --- /dev/null +++ b/src/components/area-picker/area-picker.vue @@ -0,0 +1,389 @@ + + + + diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..ebe9b26 --- /dev/null +++ b/src/main.js @@ -0,0 +1,10 @@ +import { + createSSRApp +} from 'vue' +import App from './App.vue' +export function createApp () { + const app = createSSRApp(App) + return { + app + } +} diff --git a/src/manifest.json b/src/manifest.json new file mode 100644 index 0000000..a3be646 --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,20 @@ +{ + "name" : "mall4cloud-station", + "appid" : "", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "h5" : { + "title" : "首页", + "domain" : "h5.mall4j.com", + "router" : { + "base" : "/station/", + "mode" : "history" + }, + "template" : "index.html", + "devServer" : { + "port" : 80, + "disableHostCheck" : true + } + } +} diff --git a/src/pages.json b/src/pages.json new file mode 100644 index 0000000..0dadd5a --- /dev/null +++ b/src/pages.json @@ -0,0 +1,70 @@ +{ + "easycom": { + "custom": { + "^w-(.*)": "@uni-ui/code-ui/components/w-$1/index.vue" // 匹配components目录内的vue文件 + } + }, + "pages": [ + //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页" + } + }, + { + "path": "pages/account-login/account-login", + "style": { + "navigationBarTitleText": "登录" + } + }, + { + "path": "pages/shop-adminsistration/shop-adminsistration", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "店铺管理" + } + }, + { + "path": "pages/order-list/order-list", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "订单列表" + } + }, + { + "path": "pages/order-detail/order-detail", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "订单详情" + } + }, + { + "path": "pages/scan-pick/scan-pick", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "核销订单" + } + }, + { + "path": "pages/pick-code/pick-code", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "核销码核销" + } + }, + { + "path": "pages/business-code/business-code", + "style": { + "backgroundTextStyle": "light", + "navigationBarTitleText": "商家码" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "蓝海商城门店端", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + } +} diff --git a/src/pages/account-login/account-login.scss b/src/pages/account-login/account-login.scss new file mode 100644 index 0000000..f9d916b --- /dev/null +++ b/src/pages/account-login/account-login.scss @@ -0,0 +1,122 @@ +.page-account-login { + background: #fff; + height: 100%; + padding-top: 100rpx; + .logo { display: flex; + justify-content: center; + height: 150rpx; + margin-bottom: 8%; +} +.logo { + image { + display: block; + width: 100%; + height: 100%; + } +} +.login-form { + width: 90%; + margin: 0 auto; + margin-bottom: 20%; +} +.authorized-btn { + width: 90%; + margin: 0 auto; + text-align: center; + background-color: #0ab906; + border: 1rpx solid #0ab906; + color: #fff; + border-radius: 6rpx; + font-size: 26rpx; + padding: 8rpx; + margin-top: 80rpx; +} +.to-idx-btn { + width: 90%; + margin: 0 auto; + text-align: center; + background-color: #eeeeee; + color: #333; + border-radius: 6rpx; + font-size: 26rpx; + padding: 8rpx; + margin-top: 30rpx; +} +.form-title { + width: 100%; + margin-bottom: 50rpx; + font-size: 32rpx; + text-align: center; + color: #00a0e9; +} +.item { + display: block; + margin-bottom: 30rpx; +} +.account { + display: flex; + background: #f8f8f8; + padding: 15rpx; + box-sizing: border-box; + font-size: 26rpx; + align-items: center; + input { + padding-left: 20rpx; + width: 75%; + } + input.int-yzm { + width: 410rpx; + padding-right: 10rpx; + box-sizing: border-box; + } +} +.inp-palcehoder { + font-size: 26rpx; +} +.input-btn { + width: 152rpx; + font-size: 26rpx; + color: #00a0ea; + text-align: center; +} +button { + &::after { + border: 0 !important; + } +} +.operate { + display: flex; + justify-content: space-between; + align-items: center; +} +.forgot-password { + font-size: 28rpx; + color: #00AAFF; +} +.to-register { + font-size: 28rpx; + color: #00AAFF; +} +.error { + .error-text { + display: block; + width: 100%; + font-size: 28rpx; + color: #e43130; + text-align: left; + margin-top: 10rpx; + .warning-icon { + display: inline-block; + color: #fff; + width: 26rpx; + height: 26rpx; + line-height: 26rpx; + background: #e43130; + border-radius: 50%; + text-align: center; + margin-right: 12rpx; + font-size: 22rpx; + } + } +} +} \ No newline at end of file diff --git a/src/pages/account-login/account-login.vue b/src/pages/account-login/account-login.vue new file mode 100644 index 0000000..0fe2e88 --- /dev/null +++ b/src/pages/account-login/account-login.vue @@ -0,0 +1,148 @@ + + + + diff --git a/src/pages/business-code/business-code.scss b/src/pages/business-code/business-code.scss new file mode 100644 index 0000000..ebee343 --- /dev/null +++ b/src/pages/business-code/business-code.scss @@ -0,0 +1,117 @@ +.page-business-code { + min-height: 100vh; + background: #f4f4f4; + overflow: auto; + image { + width: 100%; + height: 100%; +} +.delivery-certificate { + margin: 30rpx; + padding: 30rpx; + background: #fff; + font-size: 24rpx; + border-radius: 10rpx; + box-shadow: 0 0 6rpx rgba(0,0,0,0.05); + .item { + position: relative; + border-bottom: 2rpx dashed #ddd; + &::before { + position: absolute; + bottom: -20rpx; + display: block; + width: 40rpx; + height: 40rpx; + border-radius: 50%; + background: #f4f4f4; + content: " "; + font-size: 0; + left: -56rpx; + } + &::after { + position: absolute; + bottom: -20rpx; + display: block; + width: 40rpx; + height: 40rpx; + border-radius: 50%; + background: #f4f4f4; + content: " "; + font-size: 0; + right: -56rpx; + } + } + .address-box { + padding-bottom: 30rpx; + .name { + font-size: 28rpx; + display: flex; + align-items: center; + margin-bottom: 20rpx; + font-weight: 600; + .self-icon { + padding: 2rpx 6rpx; + line-height: 1; + color: #e43130; + border: 2rpx solid #e43130; + font-size: 20rpx; + margin-left: 10rpx; + border-radius: 4rpx; + font-weight: 400; + } + } + .a-item { + margin-bottom: 10rpx; + display: flex; + .img { + width: 24rpx; + height: 24rpx; + font-size: 0; + margin-right: 10rpx; + margin-top: 4rpx; + } + .text { + flex: 1; + } + } + } + .code-det { + padding: 40rpx 0; + .bar-code { + font-size: 0; + margin: auto; + width: 610rpx; + display: flex; + justify-content: center; + } + .code-number { + margin-top: 20rpx; + text-align: center; + } + .code { + width: 300rpx; + height: 300rpx; + margin: 40rpx auto 0; + } + } + .btn-box { + margin-top: 30rpx; + display: flex; + justify-content: center; + } +} +.btn { + width: auto; + text-align: center; + font-size: 26rpx; + font-weight: bold; + border-radius: 70rpx; +} +.code { + .qrcode-img { + display: block; + width: 100%; + height: 100%; + } +} +} diff --git a/src/pages/business-code/business-code.vue b/src/pages/business-code/business-code.vue new file mode 100644 index 0000000..5dc5f24 --- /dev/null +++ b/src/pages/business-code/business-code.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/src/pages/index/index.scss b/src/pages/index/index.scss new file mode 100644 index 0000000..7a19d51 --- /dev/null +++ b/src/pages/index/index.scss @@ -0,0 +1,161 @@ +.page-index { + height: 100vh; + width: 100%; + background-color: #F5F5F5; + /* 照片默认样式 */ + image { + display: block; + width: 100%; + height: 100%; +} +/* 自提点信息or业绩 */ +.shop-data { + display: block; + width: 100%; + height: auto; + min-height: 640rpx; + box-sizing: border-box; + color: #fff; +} +.bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 420rpx; +} +/* 自提点信息 */ +.data-top { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 15px; + padding: 10px; + position: relative; +} +.shop-info { + display: flex; + align-items: center; + width: 100%; + .shop-icon { + display: block; + width: 120rpx; + height: 120rpx; + border-radius: 60rpx; + margin-right: 20rpx; + overflow: hidden; + } + .shop-name { + width: auto; + max-width: 400rpx; + font-size: 32rpx; + font-weight: bold; + word-break: break-all; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } +} +.switch-num { + display: flex; + align-items: center; + margin-left: auto; + color: #FE3A26; + position: absolute; + right: 0; + font-size: 24rpx; + background-color: #fff; + padding: 15rpx 24rpx; + border-radius: 60rpx 0 0 60rpx; + image { + width: 24rpx; + height: 24rpx; + margin-right: 12rpx; + } +} +.search { + display: flex; + align-items: center; + width: 45%; + height: 35px; + background: rgba(255,255,255,.2); + border-radius: 60px; + box-sizing: border-box; + padding: 8px 10px; +} +.search-icon { + display: block; + width: 20px; + height: 15px; + padding-right: 5px; +} +/* 业绩信息 */ +.achievement { + font-size: 24rpx; + padding: 40rpx 0; + background-color: #fff; + width: 702rpx; + margin: 62rpx auto 0; + border-radius: 14rpx; + position: relative; + .data-line { + display: flex; + justify-content: center; + &:first-child { + margin-bottom: 48rpx; + } + .data-block { + width: 33.33%; + &:not(:last-child) { + border-right: 1rpx solid #E1E1E1; + } + .data-cont { + font-size: 40rpx; + color: #FE3A26; + font-weight: bold; + text-align: center; + } + .data-tit { + text-align: center; + line-height: 40rpx; + margin-top: 8rpx; + color: #333; + } + } + } +} +.commom-tit { + font-size: 32rpx; + font-weight: bold; + margin-bottom: 24rpx; + margin-left: 24rpx; +} +.app-list { + display: flex; + align-items: center; + flex-wrap: wrap; + padding: 32rpx 0 0 0; + background-color: #fff; + border-radius: 14rpx; + width: 702rpx; + margin: 0 auto; +} +.app-item { + text-align: center; + font-size: 24rpx; + color: #5B5B5B; + line-height: 28rpx; + padding: 0 38rpx; + margin-bottom: 32rpx; + width: 96rpx; + >image { + display: inline-block; + width: 72rpx; + height: 72rpx; + text-align: center; + margin-bottom: 8rpx; + } +} +} \ No newline at end of file diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue new file mode 100644 index 0000000..540b021 --- /dev/null +++ b/src/pages/index/index.vue @@ -0,0 +1,287 @@ + + + + + diff --git a/src/pages/order-detail/order-detail.scss b/src/pages/order-detail/order-detail.scss new file mode 100644 index 0000000..a932a55 --- /dev/null +++ b/src/pages/order-detail/order-detail.scss @@ -0,0 +1,441 @@ +/* pages/order-detail/order-detail.wxss */ +.page-order-detail { + background: #f4f4f4; + min-height: 100vh; + image { + width: 100%; + height: 100%; +} +.order-detail { + margin-bottom: 132rpx; + .order-status { + position: relative; + padding: 30rpx 20rpx; + background: #fff; + .status-bg { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 168rpx; + font-size: 0; + } + .status-text { + font-size: 36rpx; + font-weight: 600; + color: #fff; + margin: 26rpx 30rpx 24rpx; + position: relative; + } + .step { + position: relative; + display: flex; + align-items: center; + margin-top: 50rpx; + .item { + flex: 1; + .select { + width: 12rpx; + height: 12rpx; + border: 16rpx solid #fff; + background: #999; + margin: auto; + border-radius: 50%; + position: relative; + } + .des { + font-size: 24rpx; + margin-top: 10rpx; + text-align: center; + } + } + .item.active { + .select { + background: #e43130; + width: 32rpx; + height: 32rpx; + border: 6rpx solid #fff; + color: #fff; + &::after { + content: ""; + font: 0.625rem/1 uni; + position: absolute; + left: 20%; + top: 20%; + width: 55%; + height: 30%; + border: 0.125rem solid #FFFFFF; + border-radius: 0.0625rem; + border-top: none; + border-right: none; + background: transparent; + transform: rotate(-45deg); + } + } + .des { + color: #e43130; + } + } + } + } +} +.prod-item { + background: #fff; + margin-top: 20rpx; + font-size: 24rpx; + padding: 0 30rpx; + .shop-box { + padding: 24rpx 0; + display: flex; + align-items: center; + justify-content: space-between; + .refund-sts { + color: #e43130; + } + } + .shop-icon { + width: 24rpx; + height: 24rpx; + margin-right: 10rpx; + } + .shop-name { + flex: 1; + font-weight: 600; + } + .prod-box { + padding: 30rpx 0; + border-top: 2rpx solid #eee; + } + .item-cont { + position: relative; + display: flex; + .prod-pic { + font-size: 0; + width: 180rpx; + height: 180rpx; + } + .prod-info { + flex: 1; + margin-left: 20rpx; + position: relative; + .prodname { + display: flex; + align-items: flex-start; + .a-icon { + margin-right: 10rpx; + font-size: 20rpx; + color: #fff; + background: #e43130; + padding: 4rpx 10rpx; + border-radius: 4rpx; + line-height: 20rpx; + margin-top: 4rpx; + } + .text { + line-height: 36rpx; + max-height: 72rpx; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + text-overflow: ellipsis; + word-break: break-all; + } + } + .sku-name { + margin-top: 10rpx; + color: #999; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-overflow: ellipsis; + word-break: break-all; + } + } + } + .price-nums { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + display: flex; + align-items: baseline; + .prodprice { + color: #e43130; + margin-right: 10rpx; + } + .number { + color: #999; + } + } + .gift-prods { + margin-left: 200rpx; + margin-top: 30rpx; + .gift-item { + display: block; + width: 100%; + color: #333; + &:not(:last-child) { + margin-bottom: 12rpx; + } + .name { + display: inline-block; + vertical-align: middle; + box-sizing: border-box; + width: 90%; + padding-right: 10rpx; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .num { + display: inline-block; + vertical-align: middle; + box-sizing: border-box; + } + } + } + .sku-name { + .gift-icon { + display: inline-block; + margin-right: 10rpx; + color: #fff; + font-size: 24rpx; + background: #e43130; + padding: 6rpx; + border-radius: 6rpx; + line-height: 1em; + box-sizing: border-box; + } + } +} +.order-msg { + background: #fff; + margin-top: 20rpx; + font-size: 24rpx; + padding: 0 30rpx; + .msg-item { + padding: 20rpx 0; + border-top: 2rpx solid #eee; + &:first-child { + border: 0; + } + .item { + position: relative; + display: flex; + padding: 10rpx 0; + .item-tit { + color: #999; + } + .item-txt { + flex: 1; + } + .remarks-tit { + width: 120rpx; + } + .remarks-txt { + width: 400rpx; + word-wrap: break-word; + word-break: break-all; + overflow: hidden; + line-height: 38rpx; + } + .copy-btn { + display: block; + margin-left: 20rpx; + border: 2rpx solid #bbb; + padding: 6rpx 24rpx; + border-radius: 50rpx; + font-size: 24rpx; + } + } + .item.all-msg { + position: relative; + .item-txt { + word-break: break-word; + display: grid; + line-height: 1.5em; + } + .item-txt.pd { + padding-right: 32rpx; + } + .more-msg { + &::after { + position: absolute; + right: 8rpx; + top: 45%; + display: block; + width: 14rpx; + height: 14rpx; + border: 2rpx solid #666; + border-width: 2rpx 2rpx 0 0; + content: " "; + font-size: 0; + transform: rotate(45deg) translateY(-50%); + } + } + } + } +} +.order-msg.payment { + .msg-item { + .item { + .item-txt { + text-align: right; + } + } + } +} +.popup-hide { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.3); + .con-tit { + display: flex; + justify-content: space-around; + align-items: center; + font-size: 28rpx; + font-weight: bold; + padding: 30rpx; + .tit-text { + flex: 1; + text-align: center; + } + } + .virtual-goods-msg-pop { + height: auto; + .con-tit { + .tit-text { + text-align: left; + } + } + .msg-pop-con { + .msg-list { + padding: 20rpx 30rpx; + margin-bottom: 140rpx; + } + .msg-item { + display: flex; + margin-bottom: 30rpx; + } + .item-con { + font-size: 24rpx; + word-wrap: break-word; + word-break: break-word; + } + .item-con.weak { + color: #999999; + margin-right: 20rpx; + width: 180rpx; + min-width: 180rpx; + } + .pop-foot { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + padding: 0 20rpx; + margin-bottom: 30rpx; + margin-top: 20rpx; + box-sizing: border-box; + background: #fff; + .foot-btn { + font-size: 26rpx; + color: #fff; + width: 100%; + background: #E43130; + border-radius: 140rpx; + padding: 20rpx 0; + box-sizing: border-box; + } + } + } + } +} +.popup-box { + position: absolute; + bottom: 0; + width: 100%; + height: 80%; + overflow: hidden; + background-color: #fff; + border-radius: 10rpx 10rpx 0 0; +} +.close { + color: #666; + font-size: 32rpx; + &::before { + content: "\2715"; + } +} +.order-msg.voucher-code-con { + .msg-item.voucher-code-list { + max-height: 470rpx; + overflow-y: auto; + box-sizing: border-box; + padding-right: 10rpx; + } + .msg-item { + .item { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 0; + &:not(:last-child) { + margin-bottom: 16rpx; + } + .item-left { + .txt.flex-item { + display: flex; + .lf { + white-space: nowrap; + line-height: 1.5em; + } + .rg { + line-height: 1.5em; + } + } + } + .txt { + &:not(:last-child) { + margin-bottom: 10rpx; + } + } + .txt.strong { + font-weight: bold; + } + .txt.weak { + color: #999; + } + .tips { + color: #999; + } + .copy-btn2 { + background: #F7F8FA; + padding: 4rpx 20rpx; + border-radius: 60rpx; + font-size: 24rpx; + } + } + .item.used { + .tips { + margin-right: 8rpx; + height: 40rpx; + line-height: 40rpx; + } + .code-row { + .code { + text-decoration: line-through; + color: #999; + } + } + } + } +} +} \ No newline at end of file diff --git a/src/pages/order-detail/order-detail.vue b/src/pages/order-detail/order-detail.vue new file mode 100644 index 0000000..f5f3477 --- /dev/null +++ b/src/pages/order-detail/order-detail.vue @@ -0,0 +1,718 @@ + + + + diff --git a/src/pages/order-list/order-list.scss b/src/pages/order-list/order-list.scss new file mode 100644 index 0000000..187da46 --- /dev/null +++ b/src/pages/order-list/order-list.scss @@ -0,0 +1,346 @@ +/* pages/order-list/order-list.wxss */ +.page-order-list{ + background-color: #f4f4f4; + color: #333; + overflow: auto; + min-height: 100vh; + /* 头部菜单 */ + .order-tit { + position: fixed; + top: 0; + display: flex; + justify-content: space-around; + z-index: 999; + width: 100%; + height: 88rpx; + line-height: 88rpx; + background-color: #fff; + } + + .order-tit text { + display: block; + font-size: 24rpx; + text-align: center; + } + + .order-tit text.on { + border-bottom: 4rpx solid #e43130; + color: #e43130; + font-weight: 600; + } + + /* end 头部菜单 */ + + .main { + margin-top: 108rpx; + + } + + /* 商品列表 */ + + .prod-item { + background-color: #fff; + margin-bottom: 20rpx; + font-size: 28rpx; + } + + /* 店铺 */ + .shop-box { + padding: 20rpx; + border-bottom: 2rpx solid #f2f2f2; + display: flex; + align-items: center; + } + + .shop-icon { + width: 24rpx; + height: 24rpx; + margin-right: 10rpx; + font-size: 0; + } + + .shop-icon > image { + width: 100%; + height: 100%; + } + + .shop-name { + font-size: 24rpx; + font-weight: 600; + position: relative; + padding-right: 16rpx; + } + + .prod-item .order-num { + padding: 20rpx; + font-size: 24rpx; + display: flex; + align-items: center; + } + + .order-num > text { + flex: 1; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; + text-overflow: ellipsis; + } + + .order-state { + color: #999999; + display: flex; + align-items: center; + } + + .order-state.red { + color: #e43130; + } + + .prod-item .order-num .clear-btn { + width: 28rpx; + height: 28rpx; + font-size: 0; + margin-left: 42rpx; + position: relative; + } + + .prod-item .order-num .clear-btn::after { + content: " "; + display: block; + position: absolute; + left: -20rpx; + top: 0rpx; + width: 2rpx; + height: 32rpx; + background: #eee; + } + + .prod-item .order-num .clear-btn .clear-list-btn { + width: 100%; + height: 100%; + } + + .prod-item .item-cont { + display: flex; + align-items: center; + padding: 20rpx; + display: -webkit-flex; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + background: #f7f7f7; + position: relative; + } + + .prod-item .item-cont .categories { + white-space: nowrap; + } + + .prod-item .item-cont .prod-pic { + position: relative; + display: inline-block; + font-size: 0; + width: 160rpx; + height: 160rpx; + background: #fff; + margin-right: 20rpx; + } + + .prod-item .item-cont .prod-pic image { + width: 100%; + height: 100%; + } + + .spell-group-order { + position: absolute; + display: block; + top: 0; + left: 0; + width: 60rpx; + height: 30rpx; + } + + .prod-item .item-cont .prod-info { + font-size: 24rpx; + position: relative; + height: 160rpx; + -webkit-flex: 1; + -ms-flex: 1; + -webkit-box-flex: 1; + -moz-box-flex: 1; + flex: 1; + } + + .prod-item .item-cont .prod-info .prodname { + line-height: 34rpx; + max-height: 68rpx; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + } + + .prod-item .item-cont .prod-info .tag { + display: inline-block; + font-size: 24rpx; + color: #e43130; + border: 1px solid #e43130; + padding: 4rpx 8rpx; + line-height: 1em; + margin-right: 8rpx; + } + + .prod-item .item-cont .prod-info .prod-info-cont { + margin-top: 10rpx; + color: #999; + font-size: 24rpx; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; + text-overflow: ellipsis; + } + + .prod-item .price-nums { + position: absolute; + bottom: 0; + width: 100%; + display: flex; + align-items: baseline; + line-height: 32rpx; + } + + .prod-item .price-nums .prodprice { + flex: 1; + } + + .prod-item .price-nums .prodcount { + color: #999; + font-family: arial; + margin-right: 10rpx; + } + + .prod-item .total-num { + display: flex; + align-items: center; + padding: 20rpx; + position: relative; + } + + .prod-item .total-num .spell-group-icon { + margin-right: 10rpx; + padding: 4rpx 18rpx; + color: #fff; + border-radius: 20rpx; + font-size: 20rpx; + color: #e43130; + border: 2rpx solid #e43130; + } + + .prod-item .total-num .right { + flex: 1; + display: flex; + justify-content: flex-end; + align-items: baseline; + font-size: 24rpx; + } + + .prod-item .total-num .right .prodcount { + margin-right: 20rpx; + } + + .prod-item .prod-foot { + padding: 20rpx; + border-top: 2rpx solid #eee; + } + + .prod-item .prod-foot .total { + font-size: 24rpx; + margin-bottom: 20rpx; + padding-bottom: 20rpx; + border-bottom: 2rpx solid #eee; + } + + .other-button-hover { + background-color: blue; + } + + .button-hover { + background-color: #e43130; + } + + /** 添加自定义button点击态样式类**/ + + .button-hover { + background-color: blue; + } + + .btn { + display: flex; + justify-content: flex-end; + align-items: center; + } + + .button { + display: inline-block; + margin-left: 10px; + font-size: 24rpx; + background: #fff; + padding: 10rpx 30rpx; + border-radius: 80rpx; + border: 2rpx solid #ddd; + } + + .button.warn { + color: #e43130; + border-color: #e43130; + } + + /* end 商品列表 */ + + + /* 根据状态显示不同的颜色 */ + + .order-state .order-sts.red { + color: #e43130; + } + + .order-state .order-sts { + color: #333; + } + + /* 加载完成 */ + .loadall { + margin: 20rpx 0; + line-height: 2em; + font-size: 24rpx; + color: #aaa; + text-align: center; + } + + /* 列表为空 */ + .empty { + padding-top: 200rpx; + text-align: cneter; + } + .empty-icon { + display: block; + width: 80rpx; + height: 80rpx; + margin: 0 auto; + margin-bottom: 20rpx; + } + .empty-icon > image { + display: block; + width: 100%; + height: 100%; + } + .empty-text { + font-size: 28rpx; + text-align: center; + color: #999; + line-height: 40rpx; + } +} \ No newline at end of file diff --git a/src/pages/order-list/order-list.vue b/src/pages/order-list/order-list.vue new file mode 100644 index 0000000..33605ec --- /dev/null +++ b/src/pages/order-list/order-list.vue @@ -0,0 +1,370 @@ + + + + diff --git a/src/pages/pick-code/pick-code.scss b/src/pages/pick-code/pick-code.scss new file mode 100644 index 0000000..b544f41 --- /dev/null +++ b/src/pages/pick-code/pick-code.scss @@ -0,0 +1,40 @@ +page{ + overflow: hidden; +} + +.page-pick-code { + width: 500rpx; + margin: 0 auto; + margin-top: 45%; + .title { + width: 500rpx; + font-size: 40rpx; + text-align: center; + } + .inp-wrapper { + display: flex; + align-items: center; + width: 100%; + height: 100rpx; + margin-top: 50rpx; + border: 1rpx solid #fd6227; + border-radius: 15rpx; + overflow: hidden; + } + .input { + width: 370rpx; + height: 100rpx; + padding: 0 15rpx; + } + .sub-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100rpx; + height: 100rpx; + font-size: 30rpx; + color: #fff; + background-color: #fd6227; + } +} diff --git a/src/pages/pick-code/pick-code.vue b/src/pages/pick-code/pick-code.vue new file mode 100644 index 0000000..31826b3 --- /dev/null +++ b/src/pages/pick-code/pick-code.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/pages/scan-pick/scan-pick.scss b/src/pages/scan-pick/scan-pick.scss new file mode 100644 index 0000000..1cb339a --- /dev/null +++ b/src/pages/scan-pick/scan-pick.scss @@ -0,0 +1,267 @@ +.page-scan-pick { + min-height: 100vh; + background-color: #f8f8f8; + overflow: hidden; + .personal-inf{ display: flex; + align-items: center; + width: 690rpx; + font-size: 28rpx; + background-color: #fff; + border-radius: 10rpx; + margin: 0 auto; + margin-top: 30rpx; +} +.personal-inf-wrapper { + padding: 30rpx 0; +} +.personal-inf { + .line { + display: flex; + align-items: top; + &:not(:last-child) { + margin-bottom: 30rpx; + } + view { + display: inline-block; + } + .title { + white-space: nowrap; + color: #999; + padding-right: 15rpx; + margin-left: 30rpx; + width: 180rpx; + display: flex; + justify-content: space-between; + } + .detail { + width: 460rpx; + word-wrap: break-word; + word-break: normal; + color: 333; + } + } +} +.commodity-inf { + width: 690rpx; + background-color: #fff; + border-radius: 10rpx; + margin: 0 auto; + margin-top: 30rpx; + .title { + display: flex; + align-items: center; + width: 100%; + height: 80rpx; + border-bottom: 3rpx solid #eee; + } + .icon { + display: inline-block; + width: 30rpx; + height: 30rpx; + margin-right: 15rpx; + >image { + width: 100%; + height: 100%; + } + } + .font { + display: inline-block; + font-size: 28rpx; + font-weight: 550; + padding-right: 16rpx; + } + .total { + display: block; + padding: 30rpx 0; + text-align: right; + font-size: 28rpx; + box-sizing: border-box; + } +} +.commodity-inf-wrapper { + padding: 0 30rpx; +} +.prod-box { + display: block; +} +.item-cont { + border-bottom: 3rpx solid #eee; + .gift-prods { + margin-left: 200rpx; + margin-top: 10rpx; + margin-bottom: 30rpx; + font-size: 24rpx; + .gift-item { + display: block; + width: 100%; + color: #333; + margin-bottom: 10rpx; + .name { + display: inline-block; + vertical-align: middle; + padding-right: 10rpx; + box-sizing: border-box; + width: 90%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .num { + display: inline-block; + vertical-align: middle; + padding-right: 10rpx; + box-sizing: border-box; + } + } + } +} +.prod-detail { + display: flex; + align-items: center; + width: 100%; + height: 220rpx; + .prod-img { + display: inline-block; + width: 175rpx; + height: 175rpx; + margin-right: 20rpx; + image { + width: 175rpx; + height: 175rpx; + } + } + .prod-inf { + display: inline-block; + font-size: 25rpx; + width: 100%; + .prod-title { + line-height: 19px; + max-height: 39px; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + text-overflow: ellipsis; + word-break: break-all; + color: #333; + font-size: 26rpx; + font-weight: 549; + } + .brief { + font-size: 23rpx; + color: #999; + padding: 15rpx 0; + .gift-icon { + display: inline-block; + padding: 8rpx; + border-radius: 6rpx; + background: #e43130; + color: #fff; + margin-right: 8rpx; + line-height: 1em; + } + } + .price { + font-size: 31rpx; + font-weight: 520; + color: #e43130; + } + .num { + float: left; + font-size: 30rpx; + color: #999; + } + .sku-type { + font-size: 22rpx; + float: right; + word-break: break-all; + line-height: 30rpx; + color: #999; + border: 1rpx solid #999; + border-radius: 4rpx; + padding: 1rpx 6rpx; + } + } +} +.red { + color: #e43130; +} +.order-remarks { + display: flex; + width: 690rpx; + padding: 20rpx 0; + font-size: 28rpx; + background-color: #fff; + border-radius: 10rpx; + margin: 0 auto; + margin-top: 20rpx; + .remarks-title { + font-size: 28rpx; + color: #999; + margin-left: 30rpx; + width: 140rpx; + } + .remarks-txt { + width: 500rpx; + word-wrap: break-word; + word-break: break-all; + overflow: hidden; + } +} +.virtual-goods-code { + display: block; + width: 690rpx; + padding: 20rpx 30rpx; + box-sizing: border-box; + font-size: 28rpx; + background-color: #fff; + border-radius: 10rpx; + margin: 0 auto; + margin-top: 20rpx; + .code-tit { + margin-bottom: 20rpx; + } + .code-list.code-box { + max-height: 1000rpx; + overflow-y: auto; + .code-item { + font-size: 26rpx; + } + } + .code-list { + &:not(:last-child) { + border-bottom: 1px solid #eee; + padding-bottom: 10rpx; + margin-bottom: 20rpx; + } + .code-item { + margin-bottom: 16rpx; + font-size: 24rpx; + } + .date { + display: flex; + align-items: flex-start; + .lf { + white-space: nowrap; + } + } + } + .weak { + color: #999; + } +} +.pick-btn { + width: 690rpx; + height: 80rpx; + line-height: 80rpx; + font-size: 30rpx; + color: #fff; + background: #f81a1a; + text-align: center; + border-radius: 10rpx; + margin: 100rpx auto; +} +.no-pick-btn { + background: #e5e5e5; +} +} diff --git a/src/pages/scan-pick/scan-pick.vue b/src/pages/scan-pick/scan-pick.vue new file mode 100644 index 0000000..44932c9 --- /dev/null +++ b/src/pages/scan-pick/scan-pick.vue @@ -0,0 +1,499 @@ + + + + + diff --git a/src/pages/shop-adminsistration/shop-adminsistration.scss b/src/pages/shop-adminsistration/shop-adminsistration.scss new file mode 100644 index 0000000..be8eb14 --- /dev/null +++ b/src/pages/shop-adminsistration/shop-adminsistration.scss @@ -0,0 +1,306 @@ + +.page-shop-adminsistration { + width: 100%; + height: 100%; + overflow: auto; + .msg-box { display: block; + background: #fff; + margin-bottom: 15rpx; + width: 100%; + height: 100%; +} +.msg-tit { + padding: 20rpx; + border-bottom: 1rpx solid #f2f2f2; +} +.shop-icon { + display: inline-block; + width: 40rpx; + height: 40rpx; + margin-right: 15rpx; + vertical-align: middle; + >image { + display: block; + width: 100%; + height: 100%; + } +} +.shop-msg-tit { + display: inline-block; + font-size: 32rpx; + font-weight: bold; + vertical-align: middle; +} +.msg-cont-box { + font-size: 30rpx; + padding: 25rpx 0; + margin: 0 20rpx; + border-bottom: 1rpx solid #f2f2f2; + display: flex; +} +.cont-txt { + display: inline-block; + width: 150rpx; + text-align: right; + vertical-align: middle; + margin: auto 0; + margin-right: 40rpx; +} +.cont-int { + display: inline-block; + vertical-align: middle; + width: 70%; +} +.cont-left { + display: inline-block; + width: 100rpx; + height: 60rpx; + vertical-align: middle; + padding: 0 15rpx; + border: 1rpx solid #d8dbe2; +} +.cont-right { + display: inline-block; + height: 60rpx; + vertical-align: middle; + padding: 0 15rpx; + border: 1rpx solid #d8dbe2; +} +.num-line { + display: inline-block; + width: 30rpx; + height: 2rpx; + vertical-align: middle; + background-color: #606266; + margin: 30rpx 10rpx; +} +.picker-section { + display: inline-block; + font-size: 25rpx; + vertical-align: middle; + margin-top: 2rpx; + .station-time { + display: inline-block; + width: 150rpx; + color: red; + margin-left: 8rpx; + } + .inter-time { + width: 500rpx; + font-size: 30rpx; + } +} +.cont-day { + display: inline-block; + width: 60rpx; + height: 60rpx; + vertical-align: middle; + text-align: center; + border-bottom: 1rpx solid #d8dbe2; +} +.text-day { + font-size: 18rpx; +} +.station-status { + display: inline-block; + .right-radio { + margin-left: 50rpx; + } +} +.disable { + color: #aaa; +} +.align-top { + vertical-align: top; +} +.cont-textarea { + box-sizing: border-box; + vertical-align: top; + line-height: 1.5em; + border: 1rpx solid #ececec; + border-radius: 8rpx; + padding: 10rpx 15rpx; +} +.addr { + position: relative; +} +.pca { + display: inline-block; + width: 70%; + vertical-align: middle; +} +:deep(.arrow) { + width: 25rpx; + height: 25rpx; + image { + width: 100%; + height: 100%; + } + .areaPicker { + width: 100%; + height: 100%; + } +} +.animation-element-wrapper { + display: flex; + position: fixed; + left: 0; + top: 0; + height: 100%; + width: 100%; + background-color: rgba(0, 0, 0, 0.6); + z-index: 999; +} +.animation-element { + display: flex; + position: fixed; + width: 100%; + height: 470rpx; + bottom: 0; + background-color: rgba(255, 255, 255, 1); +} +.right-bt { + right: 20rpx; + top: 20rpx; + position: absolute; + width: 80rpx !important; +} +.line { + display: block; + position: fixed; + height: 2rpx; + width: 100%; + margin-top: 89rpx; + background-color: #eee; +} +picker-view { + background-color: white; + padding: 0; + width: 100%; + height: 380rpx; + bottom: 0; + position: fixed; +} +picker-view-column { + view { + vertical-align: middle; + font-size: 28rpx; + line-height: 28rpx; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } +} +.show-location { + display: inline-block; + vertical-align: middle; + font-size: 30rpx; + line-height: 1.5em; + width: 45%; + margin-top: 2rpx; +} +.map { + float: right; + color: #ffffff; + background: #e43130; + font-size: 25rpx; + line-height: 40rpx; + height: 40rpx; + padding: 10rpx 20rpx; + border-radius: 8rpx; + margin-top: 16rpx; + vertical-align: middle; +} +.clearfix { + &::after { + display: block; + height: 0; + overflow: hidden; + content: ''; + clear: both; + } +} +.upload-files { + display: inline-block; + vertical-align: top; +} +.upload-tips { + font-size: 26rpx; + color: #888888; + line-height: 2em; + margin-bottom: 15rpx; +} +.preview-img-box { + position: relative; + width: 120rpx; + height: 120rpx; + display: inline-block; + margin-bottom: 15rpx; + background: #eee; +} +.preview-logo { + width: 120rpx; + height: 120rpx; +} +image.preview-img { + width: 100%; + height: 100%; +} +.preview-img-del { + position: absolute; + top: -5rpx; + right: -5rpx; + width: 28rpx; + height: 28rpx; +} +.card-upload { + display: inline-block; + margin-right: 50rpx; +} +.card-txt { + font-size: 24rpx; + text-align: center; + color: #777; +} +.upload-icon { + display: inline-block; + width: 120rpx; + height: 120rpx; + line-height: 110rpx; + text-align: center; + border: 1rpx solid #e0e0e0; + vertical-align: top; + font-size: 90rpx; + color: #ddd; + margin-bottom: 15rpx; +} +.apply-btn { + padding: 100rpx 30rpx 150rpx 30rpx; +} +.btn { + font-size: 30rpx; + text-align: center; + background: #e43130; + padding-top: 20rpx; + padding-bottom: 20rpx; + color: #fff; + border-radius: 8rpx; +} +.foot-tips { + font-size: 28rpx; + color: #aaa; + line-height: 1.5em; + margin-top: 20rpx; +} +.audit-remark { + font-size: 26rpx; + background: #ffffcd; + color: #333; + padding: 20rpx; +} +image { + width: 100%; + height: 100%; +} +} diff --git a/src/pages/shop-adminsistration/shop-adminsistration.vue b/src/pages/shop-adminsistration/shop-adminsistration.vue new file mode 100644 index 0000000..b593b2a --- /dev/null +++ b/src/pages/shop-adminsistration/shop-adminsistration.vue @@ -0,0 +1,525 @@ + + + diff --git a/src/shime-uni.d.ts b/src/shime-uni.d.ts new file mode 100644 index 0000000..b3d3cc9 --- /dev/null +++ b/src/shime-uni.d.ts @@ -0,0 +1,6 @@ +export {}; + +declare module "vue" { + type Hooks = App.AppInstance & Page.PageInstance; + interface ComponentCustomOptions extends Hooks {} +} \ No newline at end of file diff --git a/src/static/images/icon/account-settings.png b/src/static/images/icon/account-settings.png new file mode 100644 index 0000000..90c67ff Binary files /dev/null and b/src/static/images/icon/account-settings.png differ diff --git a/src/static/images/icon/account-settings2.png b/src/static/images/icon/account-settings2.png new file mode 100644 index 0000000..a54d2b8 Binary files /dev/null and b/src/static/images/icon/account-settings2.png differ diff --git a/src/static/images/icon/activity-arr.png b/src/static/images/icon/activity-arr.png new file mode 100644 index 0000000..912449f Binary files /dev/null and b/src/static/images/icon/activity-arr.png differ diff --git a/src/static/images/icon/activity-bg.png b/src/static/images/icon/activity-bg.png new file mode 100644 index 0000000..2200373 Binary files /dev/null and b/src/static/images/icon/activity-bg.png differ diff --git a/src/static/images/icon/add.png b/src/static/images/icon/add.png new file mode 100644 index 0000000..28fd9df Binary files /dev/null and b/src/static/images/icon/add.png differ diff --git a/src/static/images/icon/addr.png b/src/static/images/icon/addr.png new file mode 100644 index 0000000..101f325 Binary files /dev/null and b/src/static/images/icon/addr.png differ diff --git a/src/static/images/icon/alipay.png b/src/static/images/icon/alipay.png new file mode 100644 index 0000000..d280021 Binary files /dev/null and b/src/static/images/icon/alipay.png differ diff --git a/src/static/images/icon/applyAshop.png b/src/static/images/icon/applyAshop.png new file mode 100644 index 0000000..ad117d0 Binary files /dev/null and b/src/static/images/icon/applyAshop.png differ diff --git a/src/static/images/icon/arrive-at-cash.png b/src/static/images/icon/arrive-at-cash.png new file mode 100644 index 0000000..e36fec6 Binary files /dev/null and b/src/static/images/icon/arrive-at-cash.png differ diff --git a/src/static/images/icon/arrow-right.png b/src/static/images/icon/arrow-right.png new file mode 100644 index 0000000..fd38af8 Binary files /dev/null and b/src/static/images/icon/arrow-right.png differ diff --git a/src/static/images/icon/back-to-top.png b/src/static/images/icon/back-to-top.png new file mode 100644 index 0000000..5bfad62 Binary files /dev/null and b/src/static/images/icon/back-to-top.png differ diff --git a/src/static/images/icon/banner.png b/src/static/images/icon/banner.png new file mode 100644 index 0000000..2a46ff3 Binary files /dev/null and b/src/static/images/icon/banner.png differ diff --git a/src/static/images/icon/bg-home.png b/src/static/images/icon/bg-home.png new file mode 100644 index 0000000..5ec30c7 Binary files /dev/null and b/src/static/images/icon/bg-home.png differ diff --git a/src/static/images/icon/bg.png b/src/static/images/icon/bg.png new file mode 100644 index 0000000..f143294 Binary files /dev/null and b/src/static/images/icon/bg.png differ diff --git a/src/static/images/icon/bg1.png b/src/static/images/icon/bg1.png new file mode 100644 index 0000000..bb679f9 Binary files /dev/null and b/src/static/images/icon/bg1.png differ diff --git a/src/static/images/icon/car-new.png b/src/static/images/icon/car-new.png new file mode 100644 index 0000000..2a25e25 Binary files /dev/null and b/src/static/images/icon/car-new.png differ diff --git a/src/static/images/icon/car.png b/src/static/images/icon/car.png new file mode 100644 index 0000000..6834595 Binary files /dev/null and b/src/static/images/icon/car.png differ diff --git a/src/static/images/icon/chat.png b/src/static/images/icon/chat.png new file mode 100644 index 0000000..7ff762f Binary files /dev/null and b/src/static/images/icon/chat.png differ diff --git a/src/static/images/icon/chongzhi.png b/src/static/images/icon/chongzhi.png new file mode 100644 index 0000000..1815f1a Binary files /dev/null and b/src/static/images/icon/chongzhi.png differ diff --git a/src/static/images/icon/clear-his.png b/src/static/images/icon/clear-his.png new file mode 100644 index 0000000..31780e6 Binary files /dev/null and b/src/static/images/icon/clear-his.png differ diff --git a/src/static/images/icon/close.png b/src/static/images/icon/close.png new file mode 100644 index 0000000..4b757f7 Binary files /dev/null and b/src/static/images/icon/close.png differ diff --git a/src/static/images/icon/close2.png b/src/static/images/icon/close2.png new file mode 100644 index 0000000..25b5a8c Binary files /dev/null and b/src/static/images/icon/close2.png differ diff --git a/src/static/images/icon/coupon-banner.png b/src/static/images/icon/coupon-banner.png new file mode 100644 index 0000000..c6e0e34 Binary files /dev/null and b/src/static/images/icon/coupon-banner.png differ diff --git a/src/static/images/icon/coupon-bg.png b/src/static/images/icon/coupon-bg.png new file mode 100644 index 0000000..8151a95 Binary files /dev/null and b/src/static/images/icon/coupon-bg.png differ diff --git a/src/static/images/icon/coupon-ot.png b/src/static/images/icon/coupon-ot.png new file mode 100644 index 0000000..0e1939d Binary files /dev/null and b/src/static/images/icon/coupon-ot.png differ diff --git a/src/static/images/icon/coupon-received.png b/src/static/images/icon/coupon-received.png new file mode 100644 index 0000000..bf6d13f Binary files /dev/null and b/src/static/images/icon/coupon-received.png differ diff --git a/src/static/images/icon/coupon-robbed.png b/src/static/images/icon/coupon-robbed.png new file mode 100644 index 0000000..8f9c921 Binary files /dev/null and b/src/static/images/icon/coupon-robbed.png differ diff --git a/src/static/images/icon/coupon-used.png b/src/static/images/icon/coupon-used.png new file mode 100644 index 0000000..1c70631 Binary files /dev/null and b/src/static/images/icon/coupon-used.png differ diff --git a/src/static/images/icon/customer-service.png b/src/static/images/icon/customer-service.png new file mode 100644 index 0000000..595c190 Binary files /dev/null and b/src/static/images/icon/customer-service.png differ diff --git a/src/static/images/icon/def.png b/src/static/images/icon/def.png new file mode 100644 index 0000000..75766ae Binary files /dev/null and b/src/static/images/icon/def.png differ diff --git a/src/static/images/icon/default-avatar.png b/src/static/images/icon/default-avatar.png new file mode 100644 index 0000000..cc662f1 Binary files /dev/null and b/src/static/images/icon/default-avatar.png differ diff --git a/src/static/images/icon/delete.png b/src/static/images/icon/delete.png new file mode 100644 index 0000000..617f75f Binary files /dev/null and b/src/static/images/icon/delete.png differ diff --git a/src/static/images/icon/delive-dot.png b/src/static/images/icon/delive-dot.png new file mode 100644 index 0000000..0573a75 Binary files /dev/null and b/src/static/images/icon/delive-dot.png differ diff --git a/src/static/images/icon/delivery-car.png b/src/static/images/icon/delivery-car.png new file mode 100644 index 0000000..7fdd500 Binary files /dev/null and b/src/static/images/icon/delivery-car.png differ diff --git a/src/static/images/icon/dot.png b/src/static/images/icon/dot.png new file mode 100644 index 0000000..c092003 Binary files /dev/null and b/src/static/images/icon/dot.png differ diff --git a/src/static/images/icon/dotted-line.png b/src/static/images/icon/dotted-line.png new file mode 100644 index 0000000..e717638 Binary files /dev/null and b/src/static/images/icon/dotted-line.png differ diff --git a/src/static/images/icon/down-arrow.png b/src/static/images/icon/down-arrow.png new file mode 100644 index 0000000..58bbdd9 Binary files /dev/null and b/src/static/images/icon/down-arrow.png differ diff --git a/src/static/images/icon/edit-score.png b/src/static/images/icon/edit-score.png new file mode 100644 index 0000000..57d9da8 Binary files /dev/null and b/src/static/images/icon/edit-score.png differ diff --git a/src/static/images/icon/empty-basket.png b/src/static/images/icon/empty-basket.png new file mode 100644 index 0000000..eefa2a4 Binary files /dev/null and b/src/static/images/icon/empty-basket.png differ diff --git a/src/static/images/icon/empty-cash.png b/src/static/images/icon/empty-cash.png new file mode 100644 index 0000000..860e9ae Binary files /dev/null and b/src/static/images/icon/empty-cash.png differ diff --git a/src/static/images/icon/empty-com.png b/src/static/images/icon/empty-com.png new file mode 100644 index 0000000..b356014 Binary files /dev/null and b/src/static/images/icon/empty-com.png differ diff --git a/src/static/images/icon/empty-dot.png b/src/static/images/icon/empty-dot.png new file mode 100644 index 0000000..6a86a87 Binary files /dev/null and b/src/static/images/icon/empty-dot.png differ diff --git a/src/static/images/icon/empty.png b/src/static/images/icon/empty.png new file mode 100644 index 0000000..3114802 Binary files /dev/null and b/src/static/images/icon/empty.png differ diff --git a/src/static/images/icon/enough.png b/src/static/images/icon/enough.png new file mode 100644 index 0000000..2422ff8 Binary files /dev/null and b/src/static/images/icon/enough.png differ diff --git a/src/static/images/icon/erweima.png b/src/static/images/icon/erweima.png new file mode 100644 index 0000000..3619fcd Binary files /dev/null and b/src/static/images/icon/erweima.png differ diff --git a/src/static/images/icon/everydaySale.png b/src/static/images/icon/everydaySale.png new file mode 100644 index 0000000..b0c869c Binary files /dev/null and b/src/static/images/icon/everydaySale.png differ diff --git a/src/static/images/icon/flash-banner.png b/src/static/images/icon/flash-banner.png new file mode 100644 index 0000000..58c9893 Binary files /dev/null and b/src/static/images/icon/flash-banner.png differ diff --git a/src/static/images/icon/flash-bg.png b/src/static/images/icon/flash-bg.png new file mode 100644 index 0000000..679bf37 Binary files /dev/null and b/src/static/images/icon/flash-bg.png differ diff --git a/src/static/images/icon/getCoupon.png b/src/static/images/icon/getCoupon.png new file mode 100644 index 0000000..8ed307d Binary files /dev/null and b/src/static/images/icon/getCoupon.png differ diff --git a/src/static/images/icon/gift.png b/src/static/images/icon/gift.png new file mode 100644 index 0000000..4aa6619 Binary files /dev/null and b/src/static/images/icon/gift.png differ diff --git a/src/static/images/icon/goumaihuiyuan@2x.png b/src/static/images/icon/goumaihuiyuan@2x.png new file mode 100644 index 0000000..365567b Binary files /dev/null and b/src/static/images/icon/goumaihuiyuan@2x.png differ diff --git a/src/static/images/icon/grade.png b/src/static/images/icon/grade.png new file mode 100644 index 0000000..d8db461 Binary files /dev/null and b/src/static/images/icon/grade.png differ diff --git a/src/static/images/icon/group-banner.png b/src/static/images/icon/group-banner.png new file mode 100644 index 0000000..767daf7 Binary files /dev/null and b/src/static/images/icon/group-banner.png differ diff --git a/src/static/images/icon/group-bg.png b/src/static/images/icon/group-bg.png new file mode 100644 index 0000000..8e23c82 Binary files /dev/null and b/src/static/images/icon/group-bg.png differ diff --git a/src/static/images/icon/group.png b/src/static/images/icon/group.png new file mode 100644 index 0000000..ffbd3df Binary files /dev/null and b/src/static/images/icon/group.png differ diff --git a/src/static/images/icon/handoff.png b/src/static/images/icon/handoff.png new file mode 100644 index 0000000..98444d9 Binary files /dev/null and b/src/static/images/icon/handoff.png differ diff --git a/src/static/images/icon/head01.png b/src/static/images/icon/head01.png new file mode 100644 index 0000000..aa7986d Binary files /dev/null and b/src/static/images/icon/head01.png differ diff --git a/src/static/images/icon/head04.png b/src/static/images/icon/head04.png new file mode 100644 index 0000000..2187de0 Binary files /dev/null and b/src/static/images/icon/head04.png differ diff --git a/src/static/images/icon/horn.png b/src/static/images/icon/horn.png new file mode 100644 index 0000000..ae9279b Binary files /dev/null and b/src/static/images/icon/horn.png differ diff --git a/src/static/images/icon/hotsell03.png b/src/static/images/icon/hotsell03.png new file mode 100644 index 0000000..6956de7 Binary files /dev/null and b/src/static/images/icon/hotsell03.png differ diff --git a/src/static/images/icon/huiyuan.png b/src/static/images/icon/huiyuan.png new file mode 100644 index 0000000..17d6b3c Binary files /dev/null and b/src/static/images/icon/huiyuan.png differ diff --git a/src/static/images/icon/integral-bg.png b/src/static/images/icon/integral-bg.png new file mode 100644 index 0000000..622b637 Binary files /dev/null and b/src/static/images/icon/integral-bg.png differ diff --git a/src/static/images/icon/integral-detail-bg1.png b/src/static/images/icon/integral-detail-bg1.png new file mode 100644 index 0000000..3d06501 Binary files /dev/null and b/src/static/images/icon/integral-detail-bg1.png differ diff --git a/src/static/images/icon/integral-detail-bg2.png b/src/static/images/icon/integral-detail-bg2.png new file mode 100644 index 0000000..37f9496 Binary files /dev/null and b/src/static/images/icon/integral-detail-bg2.png differ diff --git a/src/static/images/icon/integral-icon.png b/src/static/images/icon/integral-icon.png new file mode 100644 index 0000000..66d233c Binary files /dev/null and b/src/static/images/icon/integral-icon.png differ diff --git a/src/static/images/icon/integral-icon2.png b/src/static/images/icon/integral-icon2.png new file mode 100644 index 0000000..a6635b3 Binary files /dev/null and b/src/static/images/icon/integral-icon2.png differ diff --git a/src/static/images/icon/integral-icon3.png b/src/static/images/icon/integral-icon3.png new file mode 100644 index 0000000..2cbf110 Binary files /dev/null and b/src/static/images/icon/integral-icon3.png differ diff --git a/src/static/images/icon/integral.png b/src/static/images/icon/integral.png new file mode 100644 index 0000000..d2405c0 Binary files /dev/null and b/src/static/images/icon/integral.png differ diff --git a/src/static/images/icon/integralActBg1.png b/src/static/images/icon/integralActBg1.png new file mode 100644 index 0000000..38c5385 Binary files /dev/null and b/src/static/images/icon/integralActBg1.png differ diff --git a/src/static/images/icon/integralActBg2.png b/src/static/images/icon/integralActBg2.png new file mode 100644 index 0000000..dd320f0 Binary files /dev/null and b/src/static/images/icon/integralActBg2.png differ diff --git a/src/static/images/icon/jiantou.png b/src/static/images/icon/jiantou.png new file mode 100644 index 0000000..05f73fd Binary files /dev/null and b/src/static/images/icon/jiantou.png differ diff --git a/src/static/images/icon/jiantou2.png b/src/static/images/icon/jiantou2.png new file mode 100644 index 0000000..392b1af Binary files /dev/null and b/src/static/images/icon/jiantou2.png differ diff --git a/src/static/images/icon/jifen@2x.png b/src/static/images/icon/jifen@2x.png new file mode 100644 index 0000000..39e4698 Binary files /dev/null and b/src/static/images/icon/jifen@2x.png differ diff --git a/src/static/images/icon/lianjie.png b/src/static/images/icon/lianjie.png new file mode 100644 index 0000000..ae6c6e6 Binary files /dev/null and b/src/static/images/icon/lianjie.png differ diff --git a/src/static/images/icon/logo.png b/src/static/images/icon/logo.png new file mode 100644 index 0000000..671753e Binary files /dev/null and b/src/static/images/icon/logo.png differ diff --git a/src/static/images/icon/make-integral.png b/src/static/images/icon/make-integral.png new file mode 100644 index 0000000..b3a5312 Binary files /dev/null and b/src/static/images/icon/make-integral.png differ diff --git a/src/static/images/icon/memberIndexBg.png b/src/static/images/icon/memberIndexBg.png new file mode 100644 index 0000000..83d665a Binary files /dev/null and b/src/static/images/icon/memberIndexBg.png differ diff --git a/src/static/images/icon/menu-01.png b/src/static/images/icon/menu-01.png new file mode 100644 index 0000000..54f7aab Binary files /dev/null and b/src/static/images/icon/menu-01.png differ diff --git a/src/static/images/icon/menu-02.png b/src/static/images/icon/menu-02.png new file mode 100644 index 0000000..450cdd6 Binary files /dev/null and b/src/static/images/icon/menu-02.png differ diff --git a/src/static/images/icon/menu-03.png b/src/static/images/icon/menu-03.png new file mode 100644 index 0000000..fcce049 Binary files /dev/null and b/src/static/images/icon/menu-03.png differ diff --git a/src/static/images/icon/menu-04.png b/src/static/images/icon/menu-04.png new file mode 100644 index 0000000..d3ec6d9 Binary files /dev/null and b/src/static/images/icon/menu-04.png differ diff --git a/src/static/images/icon/merchant-code.png b/src/static/images/icon/merchant-code.png new file mode 100644 index 0000000..ac716f5 Binary files /dev/null and b/src/static/images/icon/merchant-code.png differ diff --git a/src/static/images/icon/miaosha.png b/src/static/images/icon/miaosha.png new file mode 100644 index 0000000..0720ee0 Binary files /dev/null and b/src/static/images/icon/miaosha.png differ diff --git a/src/static/images/icon/more-icon.png b/src/static/images/icon/more-icon.png new file mode 100644 index 0000000..99296b7 Binary files /dev/null and b/src/static/images/icon/more-icon.png differ diff --git a/src/static/images/icon/more.png b/src/static/images/icon/more.png new file mode 100644 index 0000000..3baecd2 Binary files /dev/null and b/src/static/images/icon/more.png differ diff --git a/src/static/images/icon/more2.png b/src/static/images/icon/more2.png new file mode 100644 index 0000000..f33f96a Binary files /dev/null and b/src/static/images/icon/more2.png differ diff --git a/src/static/images/icon/ms-edit.png b/src/static/images/icon/ms-edit.png new file mode 100644 index 0000000..d3e5ab9 Binary files /dev/null and b/src/static/images/icon/ms-edit.png differ diff --git a/src/static/images/icon/ms-search.png b/src/static/images/icon/ms-search.png new file mode 100644 index 0000000..ae1ed66 Binary files /dev/null and b/src/static/images/icon/ms-search.png differ diff --git a/src/static/images/icon/my-shop-bg.png b/src/static/images/icon/my-shop-bg.png new file mode 100644 index 0000000..e8fb937 Binary files /dev/null and b/src/static/images/icon/my-shop-bg.png differ diff --git a/src/static/images/icon/myAddr.png b/src/static/images/icon/myAddr.png new file mode 100644 index 0000000..0a4578e Binary files /dev/null and b/src/static/images/icon/myAddr.png differ diff --git a/src/static/images/icon/myCol.png b/src/static/images/icon/myCol.png new file mode 100644 index 0000000..e33d002 Binary files /dev/null and b/src/static/images/icon/myCol.png differ diff --git a/src/static/images/icon/myCoupon.png b/src/static/images/icon/myCoupon.png new file mode 100644 index 0000000..5176cb5 Binary files /dev/null and b/src/static/images/icon/myCoupon.png differ diff --git a/src/static/images/icon/myInt.png b/src/static/images/icon/myInt.png new file mode 100644 index 0000000..ab86fa0 Binary files /dev/null and b/src/static/images/icon/myInt.png differ diff --git a/src/static/images/icon/myshop-icon.png b/src/static/images/icon/myshop-icon.png new file mode 100644 index 0000000..315482d Binary files /dev/null and b/src/static/images/icon/myshop-icon.png differ diff --git a/src/static/images/icon/myshop.png b/src/static/images/icon/myshop.png new file mode 100644 index 0000000..acf2fab Binary files /dev/null and b/src/static/images/icon/myshop.png differ diff --git a/src/static/images/icon/newProd.png b/src/static/images/icon/newProd.png new file mode 100644 index 0000000..34d46dc Binary files /dev/null and b/src/static/images/icon/newProd.png differ diff --git a/src/static/images/icon/neweveryday.png b/src/static/images/icon/neweveryday.png new file mode 100644 index 0000000..a68b453 Binary files /dev/null and b/src/static/images/icon/neweveryday.png differ diff --git a/src/static/images/icon/newprods.png b/src/static/images/icon/newprods.png new file mode 100644 index 0000000..6f76a60 Binary files /dev/null and b/src/static/images/icon/newprods.png differ diff --git a/src/static/images/icon/normal-bg.png b/src/static/images/icon/normal-bg.png new file mode 100644 index 0000000..2a97563 Binary files /dev/null and b/src/static/images/icon/normal-bg.png differ diff --git a/src/static/images/icon/normal-icon.png b/src/static/images/icon/normal-icon.png new file mode 100644 index 0000000..3611b72 Binary files /dev/null and b/src/static/images/icon/normal-icon.png differ diff --git a/src/static/images/icon/notice.png b/src/static/images/icon/notice.png new file mode 100644 index 0000000..555a706 Binary files /dev/null and b/src/static/images/icon/notice.png differ diff --git a/src/static/images/icon/orders.png b/src/static/images/icon/orders.png new file mode 100644 index 0000000..82ac6fa Binary files /dev/null and b/src/static/images/icon/orders.png differ diff --git a/src/static/images/icon/pay.png b/src/static/images/icon/pay.png new file mode 100644 index 0000000..469eed9 Binary files /dev/null and b/src/static/images/icon/pay.png differ diff --git a/src/static/images/icon/phone.png b/src/static/images/icon/phone.png new file mode 100644 index 0000000..46d115b Binary files /dev/null and b/src/static/images/icon/phone.png differ diff --git a/src/static/images/icon/plus-sign.png b/src/static/images/icon/plus-sign.png new file mode 100644 index 0000000..b1d3915 Binary files /dev/null and b/src/static/images/icon/plus-sign.png differ diff --git a/src/static/images/icon/privilege-bg.png b/src/static/images/icon/privilege-bg.png new file mode 100644 index 0000000..31ef2fa Binary files /dev/null and b/src/static/images/icon/privilege-bg.png differ diff --git a/src/static/images/icon/prod-col-red.png b/src/static/images/icon/prod-col-red.png new file mode 100644 index 0000000..1437407 Binary files /dev/null and b/src/static/images/icon/prod-col-red.png differ diff --git a/src/static/images/icon/prod-col.png b/src/static/images/icon/prod-col.png new file mode 100644 index 0000000..8a03d7e Binary files /dev/null and b/src/static/images/icon/prod-col.png differ diff --git a/src/static/images/icon/promotion.png b/src/static/images/icon/promotion.png new file mode 100644 index 0000000..6f7dc21 Binary files /dev/null and b/src/static/images/icon/promotion.png differ diff --git a/src/static/images/icon/questions.png b/src/static/images/icon/questions.png new file mode 100644 index 0000000..16ded5a Binary files /dev/null and b/src/static/images/icon/questions.png differ diff --git a/src/static/images/icon/ranking-first.png b/src/static/images/icon/ranking-first.png new file mode 100644 index 0000000..b9dc726 Binary files /dev/null and b/src/static/images/icon/ranking-first.png differ diff --git a/src/static/images/icon/ranking-second.png b/src/static/images/icon/ranking-second.png new file mode 100644 index 0000000..7b0cb84 Binary files /dev/null and b/src/static/images/icon/ranking-second.png differ diff --git a/src/static/images/icon/ranking-third.png b/src/static/images/icon/ranking-third.png new file mode 100644 index 0000000..037059c Binary files /dev/null and b/src/static/images/icon/ranking-third.png differ diff --git a/src/static/images/icon/receive.png b/src/static/images/icon/receive.png new file mode 100644 index 0000000..795788d Binary files /dev/null and b/src/static/images/icon/receive.png differ diff --git a/src/static/images/icon/refund.png b/src/static/images/icon/refund.png new file mode 100644 index 0000000..7a68987 Binary files /dev/null and b/src/static/images/icon/refund.png differ diff --git a/src/static/images/icon/refunds.png b/src/static/images/icon/refunds.png new file mode 100644 index 0000000..431b695 Binary files /dev/null and b/src/static/images/icon/refunds.png differ diff --git a/src/static/images/icon/revise.png b/src/static/images/icon/revise.png new file mode 100644 index 0000000..5fb1ad7 Binary files /dev/null and b/src/static/images/icon/revise.png differ diff --git a/src/static/images/icon/rmb-icon.png b/src/static/images/icon/rmb-icon.png new file mode 100644 index 0000000..838578c Binary files /dev/null and b/src/static/images/icon/rmb-icon.png differ diff --git a/src/static/images/icon/salesman.png b/src/static/images/icon/salesman.png new file mode 100644 index 0000000..a09bb56 Binary files /dev/null and b/src/static/images/icon/salesman.png differ diff --git a/src/static/images/icon/search-01.png b/src/static/images/icon/search-01.png new file mode 100644 index 0000000..99eb77a Binary files /dev/null and b/src/static/images/icon/search-01.png differ diff --git a/src/static/images/icon/search-col.png b/src/static/images/icon/search-col.png new file mode 100644 index 0000000..587c2bf Binary files /dev/null and b/src/static/images/icon/search-col.png differ diff --git a/src/static/images/icon/search-col2.png b/src/static/images/icon/search-col2.png new file mode 100644 index 0000000..cdd35fb Binary files /dev/null and b/src/static/images/icon/search-col2.png differ diff --git a/src/static/images/icon/search.png b/src/static/images/icon/search.png new file mode 100644 index 0000000..feac7b9 Binary files /dev/null and b/src/static/images/icon/search.png differ diff --git a/src/static/images/icon/set-password.png b/src/static/images/icon/set-password.png new file mode 100644 index 0000000..aaa2048 Binary files /dev/null and b/src/static/images/icon/set-password.png differ diff --git a/src/static/images/icon/share-prod.png b/src/static/images/icon/share-prod.png new file mode 100644 index 0000000..0c7ee6a Binary files /dev/null and b/src/static/images/icon/share-prod.png differ diff --git a/src/static/images/icon/shop-customer-service.png b/src/static/images/icon/shop-customer-service.png new file mode 100644 index 0000000..2795da0 Binary files /dev/null and b/src/static/images/icon/shop-customer-service.png differ diff --git a/src/static/images/icon/shop-icon.png b/src/static/images/icon/shop-icon.png new file mode 100644 index 0000000..3c3a099 Binary files /dev/null and b/src/static/images/icon/shop-icon.png differ diff --git a/src/static/images/icon/shop-manage.png b/src/static/images/icon/shop-manage.png new file mode 100644 index 0000000..6991a73 Binary files /dev/null and b/src/static/images/icon/shop-manage.png differ diff --git a/src/static/images/icon/shop.png b/src/static/images/icon/shop.png new file mode 100644 index 0000000..cc93e56 Binary files /dev/null and b/src/static/images/icon/shop.png differ diff --git a/src/static/images/icon/sousuo.png b/src/static/images/icon/sousuo.png new file mode 100644 index 0000000..be1b2aa Binary files /dev/null and b/src/static/images/icon/sousuo.png differ diff --git a/src/static/images/icon/spell-group-order.png b/src/static/images/icon/spell-group-order.png new file mode 100644 index 0000000..e73b76f Binary files /dev/null and b/src/static/images/icon/spell-group-order.png differ diff --git a/src/static/images/icon/star-empty.png b/src/static/images/icon/star-empty.png new file mode 100644 index 0000000..47889ca Binary files /dev/null and b/src/static/images/icon/star-empty.png differ diff --git a/src/static/images/icon/star-red.png b/src/static/images/icon/star-red.png new file mode 100644 index 0000000..2c3efcd Binary files /dev/null and b/src/static/images/icon/star-red.png differ diff --git a/src/static/images/icon/status-bg.png b/src/static/images/icon/status-bg.png new file mode 100644 index 0000000..8463144 Binary files /dev/null and b/src/static/images/icon/status-bg.png differ diff --git a/src/static/images/icon/submit-address.png b/src/static/images/icon/submit-address.png new file mode 100644 index 0000000..4a20e43 Binary files /dev/null and b/src/static/images/icon/submit-address.png differ diff --git a/src/static/images/icon/submit-bg.png b/src/static/images/icon/submit-bg.png new file mode 100644 index 0000000..554acf3 Binary files /dev/null and b/src/static/images/icon/submit-bg.png differ diff --git a/src/static/images/icon/success.png b/src/static/images/icon/success.png new file mode 100644 index 0000000..5c76962 Binary files /dev/null and b/src/static/images/icon/success.png differ diff --git a/src/static/images/icon/sure.png b/src/static/images/icon/sure.png new file mode 100644 index 0000000..f0878e8 Binary files /dev/null and b/src/static/images/icon/sure.png differ diff --git a/src/static/images/icon/switch.png b/src/static/images/icon/switch.png new file mode 100644 index 0000000..a9e0072 Binary files /dev/null and b/src/static/images/icon/switch.png differ diff --git a/src/static/images/icon/thumb.png b/src/static/images/icon/thumb.png new file mode 100644 index 0000000..4d53d54 Binary files /dev/null and b/src/static/images/icon/thumb.png differ diff --git a/src/static/images/icon/time.png b/src/static/images/icon/time.png new file mode 100644 index 0000000..5a524c7 Binary files /dev/null and b/src/static/images/icon/time.png differ diff --git a/src/static/images/icon/timePrice.png b/src/static/images/icon/timePrice.png new file mode 100644 index 0000000..9daab00 Binary files /dev/null and b/src/static/images/icon/timePrice.png differ diff --git a/src/static/images/icon/title-background-left.png b/src/static/images/icon/title-background-left.png new file mode 100644 index 0000000..4441a7b Binary files /dev/null and b/src/static/images/icon/title-background-left.png differ diff --git a/src/static/images/icon/title-background-right.png b/src/static/images/icon/title-background-right.png new file mode 100644 index 0000000..4eb49d1 Binary files /dev/null and b/src/static/images/icon/title-background-right.png differ diff --git a/src/static/images/icon/title-bg2.png b/src/static/images/icon/title-bg2.png new file mode 100644 index 0000000..a7c7afe Binary files /dev/null and b/src/static/images/icon/title-bg2.png differ diff --git a/src/static/images/icon/toComment.png b/src/static/images/icon/toComment.png new file mode 100644 index 0000000..dd97528 Binary files /dev/null and b/src/static/images/icon/toComment.png differ diff --git a/src/static/images/icon/toDelivery.png b/src/static/images/icon/toDelivery.png new file mode 100644 index 0000000..499fd68 Binary files /dev/null and b/src/static/images/icon/toDelivery.png differ diff --git a/src/static/images/icon/toPay.png b/src/static/images/icon/toPay.png new file mode 100644 index 0000000..62b10e2 Binary files /dev/null and b/src/static/images/icon/toPay.png differ diff --git a/src/static/images/icon/toTake.png b/src/static/images/icon/toTake.png new file mode 100644 index 0000000..861cf5c Binary files /dev/null and b/src/static/images/icon/toTake.png differ diff --git a/src/static/images/icon/tuiguang01.png b/src/static/images/icon/tuiguang01.png new file mode 100644 index 0000000..0b7d086 Binary files /dev/null and b/src/static/images/icon/tuiguang01.png differ diff --git a/src/static/images/icon/tuiguang02.png b/src/static/images/icon/tuiguang02.png new file mode 100644 index 0000000..87aba09 Binary files /dev/null and b/src/static/images/icon/tuiguang02.png differ diff --git a/src/static/images/icon/tuiguang03.png b/src/static/images/icon/tuiguang03.png new file mode 100644 index 0000000..a3832d1 Binary files /dev/null and b/src/static/images/icon/tuiguang03.png differ diff --git a/src/static/images/icon/tw.png b/src/static/images/icon/tw.png new file mode 100644 index 0000000..caa9d14 Binary files /dev/null and b/src/static/images/icon/tw.png differ diff --git a/src/static/images/icon/unionpay.png b/src/static/images/icon/unionpay.png new file mode 100644 index 0000000..01da92d Binary files /dev/null and b/src/static/images/icon/unionpay.png differ diff --git a/src/static/images/icon/up-arrow.png b/src/static/images/icon/up-arrow.png new file mode 100644 index 0000000..2477bd8 Binary files /dev/null and b/src/static/images/icon/up-arrow.png differ diff --git a/src/static/images/icon/user-icon.png b/src/static/images/icon/user-icon.png new file mode 100644 index 0000000..826afe0 Binary files /dev/null and b/src/static/images/icon/user-icon.png differ diff --git a/src/static/images/icon/verification-code.png b/src/static/images/icon/verification-code.png new file mode 100644 index 0000000..88e7904 Binary files /dev/null and b/src/static/images/icon/verification-code.png differ diff --git a/src/static/images/icon/verification.png b/src/static/images/icon/verification.png new file mode 100644 index 0000000..9fa94fd Binary files /dev/null and b/src/static/images/icon/verification.png differ diff --git a/src/static/images/icon/vip-icon.png b/src/static/images/icon/vip-icon.png new file mode 100644 index 0000000..43b7f1d Binary files /dev/null and b/src/static/images/icon/vip-icon.png differ diff --git a/src/static/images/icon/vip1.png b/src/static/images/icon/vip1.png new file mode 100644 index 0000000..2870c7e Binary files /dev/null and b/src/static/images/icon/vip1.png differ diff --git a/src/static/images/icon/vip2.png b/src/static/images/icon/vip2.png new file mode 100644 index 0000000..be0f4ee Binary files /dev/null and b/src/static/images/icon/vip2.png differ diff --git a/src/static/images/icon/vip3.png b/src/static/images/icon/vip3.png new file mode 100644 index 0000000..07d3df6 Binary files /dev/null and b/src/static/images/icon/vip3.png differ diff --git a/src/static/images/icon/vip4.png b/src/static/images/icon/vip4.png new file mode 100644 index 0000000..f33f170 Binary files /dev/null and b/src/static/images/icon/vip4.png differ diff --git a/src/static/images/icon/vip5.png b/src/static/images/icon/vip5.png new file mode 100644 index 0000000..c7a4a83 Binary files /dev/null and b/src/static/images/icon/vip5.png differ diff --git a/src/static/images/icon/weixin.png b/src/static/images/icon/weixin.png new file mode 100644 index 0000000..cdd5842 Binary files /dev/null and b/src/static/images/icon/weixin.png differ diff --git a/src/static/images/icon/white-arr.png b/src/static/images/icon/white-arr.png new file mode 100644 index 0000000..d72407c Binary files /dev/null and b/src/static/images/icon/white-arr.png differ diff --git a/src/static/images/icon/wxpay.png b/src/static/images/icon/wxpay.png new file mode 100644 index 0000000..f18d9e9 Binary files /dev/null and b/src/static/images/icon/wxpay.png differ diff --git a/src/static/images/icon/zhiwen.png b/src/static/images/icon/zhiwen.png new file mode 100644 index 0000000..5973038 Binary files /dev/null and b/src/static/images/icon/zhiwen.png differ diff --git a/src/static/images/icon/zunxiang.png b/src/static/images/icon/zunxiang.png new file mode 100644 index 0000000..45b3780 Binary files /dev/null and b/src/static/images/icon/zunxiang.png differ diff --git a/src/static/logo.png b/src/static/logo.png new file mode 100644 index 0000000..671753e Binary files /dev/null and b/src/static/logo.png differ diff --git a/src/static/packageMemberIntegral/images/icon/dabiaoti@2x.png b/src/static/packageMemberIntegral/images/icon/dabiaoti@2x.png new file mode 100644 index 0000000..a55bc44 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/dabiaoti@2x.png differ diff --git a/src/static/packageMemberIntegral/images/icon/dianjichoujiang@2x.png b/src/static/packageMemberIntegral/images/icon/dianjichoujiang@2x.png new file mode 100644 index 0000000..d252868 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/dianjichoujiang@2x.png differ diff --git a/src/static/packageMemberIntegral/images/icon/integral-bg.png b/src/static/packageMemberIntegral/images/icon/integral-bg.png new file mode 100644 index 0000000..622b637 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/integral-bg.png differ diff --git a/src/static/packageMemberIntegral/images/icon/integral-detail-bg1.png b/src/static/packageMemberIntegral/images/icon/integral-detail-bg1.png new file mode 100644 index 0000000..3d06501 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/integral-detail-bg1.png differ diff --git a/src/static/packageMemberIntegral/images/icon/integral-detail-bg2.png b/src/static/packageMemberIntegral/images/icon/integral-detail-bg2.png new file mode 100644 index 0000000..37f9496 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/integral-detail-bg2.png differ diff --git a/src/static/packageMemberIntegral/images/icon/integralActBg1.png b/src/static/packageMemberIntegral/images/icon/integralActBg1.png new file mode 100644 index 0000000..38c5385 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/integralActBg1.png differ diff --git a/src/static/packageMemberIntegral/images/icon/integralActBg2.png b/src/static/packageMemberIntegral/images/icon/integralActBg2.png new file mode 100644 index 0000000..dd320f0 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/integralActBg2.png differ diff --git a/src/static/packageMemberIntegral/images/icon/jinbi@2x.png b/src/static/packageMemberIntegral/images/icon/jinbi@2x.png new file mode 100644 index 0000000..62368d7 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/jinbi@2x.png differ diff --git a/src/static/packageMemberIntegral/images/icon/memberIndexBg.png b/src/static/packageMemberIntegral/images/icon/memberIndexBg.png new file mode 100644 index 0000000..83d665a Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/memberIndexBg.png differ diff --git a/src/static/packageMemberIntegral/images/icon/memberLevelBg.png b/src/static/packageMemberIntegral/images/icon/memberLevelBg.png new file mode 100644 index 0000000..84f4069 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/memberLevelBg.png differ diff --git a/src/static/packageMemberIntegral/images/icon/nanguo@2x.png b/src/static/packageMemberIntegral/images/icon/nanguo@2x.png new file mode 100644 index 0000000..99f4244 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/nanguo@2x.png differ diff --git a/src/static/packageMemberIntegral/images/icon/people.png b/src/static/packageMemberIntegral/images/icon/people.png new file mode 100644 index 0000000..1616aa0 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/people.png differ diff --git a/src/static/packageMemberIntegral/images/icon/xingyunchoujiang-bg.png b/src/static/packageMemberIntegral/images/icon/xingyunchoujiang-bg.png new file mode 100644 index 0000000..2ac6769 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/xingyunchoujiang-bg.png differ diff --git a/src/static/packageMemberIntegral/images/icon/youhuiq@2x.png b/src/static/packageMemberIntegral/images/icon/youhuiq@2x.png new file mode 100644 index 0000000..26d683e Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/youhuiq@2x.png differ diff --git a/src/static/packageMemberIntegral/images/icon/zhuanpan@2x.png b/src/static/packageMemberIntegral/images/icon/zhuanpan@2x.png new file mode 100644 index 0000000..1901638 Binary files /dev/null and b/src/static/packageMemberIntegral/images/icon/zhuanpan@2x.png differ diff --git a/src/uni.scss b/src/uni.scss new file mode 100644 index 0000000..4362c07 --- /dev/null +++ b/src/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color: #333; // 基本色 +$uni-text-color-inverse: #fff; // 反色 +$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable: #c0c0c0; + +/* 背景颜色 */ +$uni-bg-color: #fff; +$uni-bg-color-grey: #f8f8f8; +$uni-bg-color-hover: #f1f1f1; // 点击状态颜色 +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色 + +/* 边框颜色 */ +$uni-border-color: #cccbc7; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm: 12px; +$uni-font-size-base: 14px; +$uni-font-size-lg: 16; + +/* 图片尺寸 */ +$uni-img-size-sm: 20px; +$uni-img-size-base: 26px; +$uni-img-size-lg: 40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2c405a; // 文章标题颜色 +$uni-font-size-title: 20px; +$uni-color-subtitle: #555; // 二级标题颜色 +$uni-font-size-subtitle: 18px; +$uni-color-paragraph: #3f536e; // 文章段落颜色 +$uni-font-size-paragraph: 15px; \ No newline at end of file diff --git a/src/uni_modules/z-paging/changelog.md b/src/uni_modules/z-paging/changelog.md new file mode 100644 index 0000000..5ec98ea --- /dev/null +++ b/src/uni_modules/z-paging/changelog.md @@ -0,0 +1,12 @@ +## 2.5.8(2023-05-03) +1.`新增` props:`refresher-no-transform`,支持控制下拉刷新时是否禁止下拉刷新view跟随用户触摸竖直移动。 +2.`新增` props:`refresher-refreshing-animated`,支持控制下拉刷新刷新中状态下是否展示旋转动画。 +3.`新增` vue3中页面滚动hooks。 +4.`新增` 全局拦截器-`@query`拦截器中回调函数添加当前列表最后一个item数据。 +5.`修复` 在vue3+内置浏览器中,报错`SyntaxError: Unexpected token . at xxx`的问题。 +6.`修复` 滑动切换选项卡简化写法queryList触发多次的问题。 +7.`优化` 底部加载更多展示逻辑,在各个平台中过渡更加自然。 +8.`优化` `@touchDirectionChange`触发逻辑,仅在值改变时触发,优化性能。 +## 2.5.7(2023-03-14) +1.`修复` 在nvue+安卓中,设置`empty-view-center`为false后空数据图被切割未能完整显示的问题。 +2.`修复` 由`2.5.4`引出的在nvue中,使用`slot="top"`后下拉刷新失效的问题。 diff --git a/src/uni_modules/z-paging/components/z-paging-cell/z-paging-cell.vue b/src/uni_modules/z-paging/components/z-paging-cell/z-paging-cell.vue new file mode 100644 index 0000000..e9aca70 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging-cell/z-paging-cell.vue @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging-empty-view/z-paging-empty-view.vue b/src/uni_modules/z-paging/components/z-paging-empty-view/z-paging-empty-view.vue new file mode 100644 index 0000000..18ee4ee --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging-empty-view/z-paging-empty-view.vue @@ -0,0 +1,162 @@ + + + + + + + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging-swiper-item/z-paging-swiper-item.vue b/src/uni_modules/z-paging/components/z-paging-swiper-item/z-paging-swiper-item.vue new file mode 100644 index 0000000..fed9080 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging-swiper-item/z-paging-swiper-item.vue @@ -0,0 +1,143 @@ + + + + + + + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging-swiper/z-paging-swiper.vue b/src/uni_modules/z-paging/components/z-paging-swiper/z-paging-swiper.vue new file mode 100644 index 0000000..e1c608b --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging-swiper/z-paging-swiper.vue @@ -0,0 +1,169 @@ + + + + + + + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging/components/z-paging-load-more.vue b/src/uni_modules/z-paging/components/z-paging/components/z-paging-load-more.vue new file mode 100644 index 0000000..3dd311c --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/components/z-paging-load-more.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging/components/z-paging-refresh.vue b/src/uni_modules/z-paging/components/z-paging/components/z-paging-refresh.vue new file mode 100644 index 0000000..12ac9db --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/components/z-paging-refresh.vue @@ -0,0 +1,182 @@ + + + + + diff --git a/src/uni_modules/z-paging/components/z-paging/config/index.js b/src/uni_modules/z-paging/components/z-paging/config/index.js new file mode 100644 index 0000000..2af6aa2 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/config/index.js @@ -0,0 +1,45 @@ +// z-paging全局配置文件,注意避免更新时此文件被覆盖,若被覆盖,可在此文件中右键->点击本地历史记录,找回覆盖前的配置 +export default { + //配置分页默认pageSize为20 + 'default-page-size': '20', + // 空数据图图片 + 'empty-view-img': '/static/empty-img/not-found.png', + // 空数据图图片是否居中 + 'empty-view-center':false, + // 空数据图img样式 + 'empty-view-img-style': { + 'display': 'block', + 'width': '200rpx', + 'height': '200rpx', + 'margin': '0 auto', + 'margin-bottom': '20rpx' + }, + // 滑动到底部"没有更多"文字 + 'loading-more-no-more-text': '没有更多了,看看别的吧', + // 底部加载更多文字样式 + 'loading-more-title-custom-style':{ + 'font-size': '24rpx' + }, + // 自动显示点击返回顶部按钮 + 'auto-show-back-to-top': true, + // 返回顶部按钮图标 + 'back-to-top-img': '/static/images/back-to-top.png', + // 返回顶部按钮样式 + 'back-to-top-style': { + 'display': 'flex', + 'justify-content': 'center', + 'align-items': 'center', + 'width': '80rpx', + 'height': '80rpx', + 'border-radius': '50%', + 'background': '#fff', + 'border': '2rpx solid #ccc' + }, + // 点击返回顶部按钮与底部的距离 + 'back-to-top-bottom': '150rpx', + // 当列表内容没有超出一页时,是否隐藏没有更多的提示 + 'hide-no-more-inside': true, + // 是否开启底部安全区域适配 + 'safe-area-inset-bottom': true, + 'auto-clean-list-when-reload': false +} \ No newline at end of file diff --git a/src/uni_modules/z-paging/components/z-paging/css/z-paging-main.css b/src/uni_modules/z-paging/components/z-paging/css/z-paging-main.css new file mode 100644 index 0000000..a12a458 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/css/z-paging-main.css @@ -0,0 +1,227 @@ +/* [z-paging]公共css*/ + +.z-paging-content { + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + height: 100%; + overflow: hidden; + /* #endif */ + flex-direction: column; +} + +.z-paging-content-fixed, .zp-loading-fixed { + position: fixed; + /* #ifndef APP-NVUE */ + height: auto; + width: auto; + /* #endif */ + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +.zp-page-top,.zp-page-bottom { + /* #ifndef APP-NVUE */ + width: auto; + /* #endif */ + position: fixed; + left: 0; + right: 0; + z-index: 999; +} + +.zp-page-left,.zp-page-right{ + /* #ifndef APP-NVUE */ + height: 100%; + /* #endif */ +} + +.zp-scroll-view-super { + flex: 1; + position: relative; +} + +.zp-view-super{ + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; +} + +.zp-custom-refresher-container { + overflow: hidden; +} + +.zp-scroll-view-container,.zp-scroll-view { + position: relative; + /* #ifndef APP-NVUE */ + height: 100%; + width: 100%; + /* #endif */ +} + +.zp-absoulte{ + /* #ifndef APP-NVUE */ + position: absolute; + top: 0; + width: auto; + /* #endif */ +} + +.zp-right{ + right: 0; +} + +.zp-scroll-view-absolute { + position: absolute; + top: 0; + left: 0; +} + +/* #ifndef APP-NVUE */ +.zp-scroll-view-hide-scrollbar ::-webkit-scrollbar { + display: none; + -webkit-appearance: none; + width: 0 !important; + height: 0 !important; + background: transparent; +} +/* #endif */ + +.zp-paging-touch-view { + width: 100%; + height: 100%; + position: relative; +} + +.zp-fixed-bac-view { + position: absolute; + width: 100%; + top: 0; + left: 0; + height: 200px; +} + +.zp-paging-main { + height: 100%; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; +} + +.zp-paging-container { + flex: 1; + position: relative; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; +} + +.zp-chat-record-loading-container { + /* #ifndef APP-NVUE */ + display: flex; + width: 100%; + /* #endif */ + /* #ifdef APP-NVUE */ + width: 750rpx; + /* #endif */ + align-items: center; + justify-content: center; + height: 60rpx; + font-size: 26rpx; +} + +.zp-chat-record-loading-custom-image { + width: 35rpx; + height: 35rpx; + /* #ifndef APP-NVUE */ + animation: loading-flower 1s linear infinite; + /* #endif */ +} + +.zp-custom-refresher-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + justify-content: center; + align-items: center; +} + +.zp-back-to-top { + width: 76rpx; + height: 76rpx; + z-index: 999; + position: absolute; + bottom: 0rpx; + right: 25rpx; + transition-duration: .3s; + transition-property: opacity; +} + +.zp-back-to-top-show { + opacity: 1; +} + +.zp-back-to-top-hide { + opacity: 0; +} + +.zp-back-to-top-img { + /* #ifndef APP-NVUE */ + width: 100%; + height: 100%; + /* #endif */ + /* #ifdef APP-NVUE */ + flex: 1; + /* #endif */ + z-index: 999; +} + +.zp-empty-view { + /* #ifdef APP-NVUE */ + height: 100%; + /* #endif */ + flex: 1; +} + +.zp-empty-view-center { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + align-items: center; + justify-content: center; +} + +.zp-loading-fixed { + z-index: 9999; +} + +.zp-safe-area-inset-bottom { + position: absolute; + /* #ifndef APP-PLUS */ + height: env(safe-area-inset-bottom); + /* #endif */ +} + +.zp-n-refresh-container { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + width: 750rpx; +} + +.zp-n-list-container{ + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex: 1; +} diff --git a/src/uni_modules/z-paging/components/z-paging/css/z-paging-static.css b/src/uni_modules/z-paging/components/z-paging/css/z-paging-static.css new file mode 100644 index 0000000..eaad977 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/css/z-paging-static.css @@ -0,0 +1,35 @@ +/* [z-paging]公用的静态css资源 */ + +.zp-line-loading-image { + margin-right: 8rpx; + width: 28rpx; + height: 28rpx; + /* #ifndef APP-NVUE */ + animation: loading-flower 1s steps(12) infinite; + /* #endif */ + color: #666666; +} + +.zp-loading-image-ios{ + width: 20px; + height: 20px; +} + +.zp-loading-image-android{ + width: 32rpx; + height: 32rpx; +} + +/* #ifndef APP-NVUE */ +@keyframes loading-flower { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + to { + -webkit-transform: rotate(1turn); + transform: rotate(1turn); + } +} +/* #endif */ + diff --git a/src/uni_modules/z-paging/components/z-paging/i18n/en.json b/src/uni_modules/z-paging/components/z-paging/i18n/en.json new file mode 100644 index 0000000..d93430f --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/i18n/en.json @@ -0,0 +1,22 @@ +{ + "zp.refresher.default": "Pull down to refresh", + "zp.refresher.pulling": "Release to refresh", + "zp.refresher.refreshing": "Refreshing...", + "zp.refresher.complete": "Refresh succeeded", + + "zp.loadingMore.default": "Click to load more", + "zp.loadingMore.loading": "Loading...", + "zp.loadingMore.noMore": "No more data", + "zp.loadingMore.fail": "Load failed,click to reload", + + "zp.emptyView.title": "No data", + "zp.emptyView.reload": "Reload", + "zp.emptyView.error": "Sorry,load failed", + + "zp.refresherUpdateTime.title": "Last update: ", + "zp.refresherUpdateTime.none": "None", + "zp.refresherUpdateTime.today": "Today", + "zp.refresherUpdateTime.yesterday": "Yesterday", + + "zp.systemLoading.title": "Loading..." +} diff --git a/src/uni_modules/z-paging/components/z-paging/i18n/index.js b/src/uni_modules/z-paging/components/z-paging/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hans.json b/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hans.json new file mode 100644 index 0000000..f2cc3c8 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hans.json @@ -0,0 +1,22 @@ +{ + "zp.refresher.default": "继续下拉刷新", + "zp.refresher.pulling": "松开立即刷新", + "zp.refresher.refreshing": "正在刷新...", + "zp.refresher.complete": "刷新成功", + + "zp.loadingMore.default": "点击加载更多", + "zp.loadingMore.loading": "正在加载...", + "zp.loadingMore.noMore": "没有更多了", + "zp.loadingMore.fail": "加载失败,点击重新加载", + + "zp.emptyView.title": "没有数据哦~", + "zp.emptyView.reload": "重新加载", + "zp.emptyView.error": "很抱歉,加载失败", + + "zp.refresherUpdateTime.title": "最后更新:", + "zp.refresherUpdateTime.none": "无", + "zp.refresherUpdateTime.today": "今天", + "zp.refresherUpdateTime.yesterday": "昨天", + + "zp.systemLoading.title": "加载中..." +} diff --git a/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hant.json b/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hant.json new file mode 100644 index 0000000..e9c80cf --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/i18n/zh-Hant.json @@ -0,0 +1,22 @@ +{ + "zp.refresher.default": "繼續下拉重繪", + "zp.refresher.pulling": "鬆開立即重繪", + "zp.refresher.refreshing": "正在重繪...", + "zp.refresher.complete": "重繪成功", + + "zp.loadingMore.default": "點擊加載更多", + "zp.loadingMore.loading": "正在加載...", + "zp.loadingMore.noMore": "沒有更多了", + "zp.loadingMore.fail": "加載失敗,點擊重新加載", + + "zp.emptyView.title": "沒有數據哦~", + "zp.emptyView.reload": "重新加載", + "zp.emptyView.error": "很抱歉,加載失敗", + + "zp.refresherUpdateTime.title": "最後更新:", + "zp.refresherUpdateTime.none": "無", + "zp.refresherUpdateTime.today": "今天", + "zp.refresherUpdateTime.yesterday": "昨天", + + "zp.systemLoading.title": "加載中..." +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js b/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js new file mode 100644 index 0000000..3c2d5f9 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js @@ -0,0 +1,25 @@ +// [z-paging]useZPaging hooks + +import { onPageScroll, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'; + +function useZPaging(paging) { + const cPaging = !!paging ? paging.value || paging : null; + + onPullDownRefresh(() => { + if (!cPaging) return; + cPaging.value.reload(); + }) + + onPageScroll(e => { + if (!cPaging) return; + cPaging.value.updatePageScrollTop(e.scrollTop); + e.scrollTop < 10 && cPaging.value.doChatRecordLoadMore(); + }) + + onReachBottom(() => { + if (!cPaging) return; + cPaging.value.pageReachBottom(); + }) +} + +export default useZPaging \ No newline at end of file diff --git a/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPagingComp.js b/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPagingComp.js new file mode 100644 index 0000000..b9a0054 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/hooks/useZPagingComp.js @@ -0,0 +1,26 @@ +// [z-paging]useZPagingComp hooks + +function useZPagingComp(paging) { + + const cPaging = !!paging ? paging.value || paging : null; + + const reload = () => { + if (!cPaging) return; + cPaging.value.reload(); + } + const updatePageScrollTop = scrollTop => { + if (!cPaging) return; + cPaging.value.updatePageScrollTop(scrollTop); + } + const doChatRecordLoadMore = () => { + if (!cPaging) return; + cPaging.value.doChatRecordLoadMore(); + } + const pageReachBottom = () => { + if (!cPaging) return; + cPaging.value.pageReachBottom(); + } + return { reload, updatePageScrollTop, doChatRecordLoadMore, pageReachBottom }; +} + +export default useZPagingComp \ No newline at end of file diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/back-to-top.js b/src/uni_modules/z-paging/components/z-paging/js/modules/back-to-top.js new file mode 100644 index 0000000..a490911 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/back-to-top.js @@ -0,0 +1,100 @@ +// [z-paging]点击返回顶部view模块 +import u from '.././z-paging-utils' + +export default { + props: { + //自动显示点击返回顶部按钮,默认为否 + autoShowBackToTop: { + type: Boolean, + default: u.gc('autoShowBackToTop', false) + }, + //点击返回顶部按钮显示/隐藏的阈值(滚动距离),单位为px,默认为400rpx + backToTopThreshold: { + type: [Number, String], + default: u.gc('backToTopThreshold', '400rpx') + }, + //点击返回顶部按钮的自定义图片地址,默认使用z-paging内置的图片 + backToTopImg: { + type: String, + default: u.gc('backToTopImg', '') + }, + //点击返回顶部按钮返回到顶部时是否展示过渡动画,默认为是 + backToTopWithAnimate: { + type: Boolean, + default: u.gc('backToTopWithAnimate', true) + }, + //点击返回顶部按钮与底部的距离,注意添加单位px或rpx,默认为160rpx + backToTopBottom: { + type: [Number, String], + default: u.gc('backToTopBottom', '160rpx') + }, + //点击返回顶部按钮的自定义样式 + backToTopStyle: { + type: Object, + default: function() { + return u.gc('backToTopStyle', {}); + }, + }, + //iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向,默认为是 + enableBackToTop: { + type: Boolean, + default: u.gc('enableBackToTop', true) + }, + }, + data() { + return { + backToTopClass: 'zp-back-to-top zp-back-to-top-hide', + lastBackToTopShowTime: 0, + showBackToTopClass: false, + } + }, + computed: { + finalEnableBackToTop() { + return this.usePageScroll ? false : this.enableBackToTop; + }, + finalBackToTopThreshold() { + return u.convertToPx(this.backToTopThreshold); + }, + finalBackToTopStyle() { + const backToTopStyle = this.backToTopStyle; + if (!backToTopStyle.bottom) { + backToTopStyle.bottom = this.windowBottom + u.convertToPx(this.backToTopBottom) + 'px'; + } + if(!backToTopStyle.position){ + backToTopStyle.position = this.usePageScroll ? 'fixed': 'absolute'; + } + return backToTopStyle; + }, + }, + methods: { + //点击返回顶部 + _backToTopClick() { + !this.backToTopWithAnimate && this._checkShouldShowBackToTop(0); + this.scrollToTop(this.backToTopWithAnimate); + }, + //判断是否要显示返回顶部按钮 + _checkShouldShowBackToTop(scrollTop) { + if (!this.autoShowBackToTop) { + this.showBackToTopClass = false; + return; + } + if (scrollTop > this.finalBackToTopThreshold) { + if (!this.showBackToTopClass) { + this.showBackToTopClass = true; + this.lastBackToTopShowTime = new Date().getTime(); + u.delay(() => { + this.backToTopClass = 'zp-back-to-top zp-back-to-top-show'; + }, 300) + } + } else { + if (this.showBackToTopClass) { + this.backToTopClass = 'zp-back-to-top zp-back-to-top-hide'; + u.delay(() => { + this.showBackToTopClass = false; + }, new Date().getTime() - this.lastBackToTopShowTime < 500 ? 0 : 300) + } + } + }, + } +} + diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/common-layout.js b/src/uni_modules/z-paging/components/z-paging/js/modules/common-layout.js new file mode 100644 index 0000000..c5cbc4f --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/common-layout.js @@ -0,0 +1,116 @@ +// [z-paging]通用布局相关模块 + +// #ifdef APP-NVUE +const weexDom = weex.requireModule('dom'); +// #endif + +export default { + data() { + return { + systemInfo: null, + cssSafeAreaInsetBottom: -1, + } + }, + computed: { + windowTop() { + if (!this.systemInfo) return 0; + //暂时修复vue3中隐藏系统导航栏后windowTop获取不正确的问题,具体bug详见https://ask.dcloud.net.cn/question/141634 + //感谢litangyu!!https://github.com/SmileZXLee/uni-z-paging/issues/25 + // #ifdef VUE3 && H5 + const pageHeadNode = document.getElementsByTagName("uni-page-head"); + if (!pageHeadNode.length) return 0; + // #endif + return this.systemInfo.windowTop || 0; + }, + safeAreaBottom() { + if (!this.systemInfo) return 0; + let safeAreaBottom = 0; + // #ifdef APP-PLUS + safeAreaBottom = this.systemInfo.safeAreaInsets.bottom || 0 ; + // #endif + // #ifndef APP-PLUS + safeAreaBottom = Math.max(this.cssSafeAreaInsetBottom, 0); + // #endif + return safeAreaBottom; + }, + isOldWebView() { + // #ifndef APP-NVUE || MP-KUAISHOU + try { + const systemInfos = systemInfo.system.split(' '); + const deviceType = systemInfos[0]; + const version = parseInt(systemInfos[1]); + if ((deviceType === 'iOS' && version <= 10) || (deviceType === 'Android' && version <= 6)) { + return true; + } + } catch(e) { + return false; + } + // #endif + return false; + }, + zSlots() { + // #ifdef VUE2 + + // #ifdef MP-ALIPAY + return this.$slots; + // #endif + + return this.$scopedSlots || this.$slots; + // #endif + + return this.$slots; + } + }, + methods: { + //获取节点尺寸 + _getNodeClientRect(select, inDom = true, scrollOffset = false) { + // #ifdef APP-NVUE + select = select.replace(/[.|#]/g, ''); + const ref = this.$refs[select]; + return new Promise((resolve, reject) => { + if (ref) { + weexDom.getComponentRect(ref, option => { + resolve(option && option.result ? [option.size] : false); + }) + } else { + resolve(false); + } + }); + return; + // #endif + //#ifdef MP-ALIPAY + inDom = false; + //#endif + let res = !!inDom ? uni.createSelectorQuery().in(inDom === true ? this : inDom) : uni.createSelectorQuery(); + scrollOffset ? res.select(select).scrollOffset() : res.select(select).boundingClientRect(); + return new Promise((resolve, reject) => { + res.exec(data => { + resolve((data && data != '' && data != undefined && data.length) ? data : false); + }); + }); + }, + //获取slot="left"和slot="right"宽度并且更新布局 + _updateLeftAndRightWidth(targetStyle, parentNodePrefix) { + this.$nextTick(() => { + let delayTime = 0; + // #ifdef MP-BAIDU + delayTime = 10; + // #endif + setTimeout(() => { + ['left','right'].map(position => { + this._getNodeClientRect(`.${parentNodePrefix}-${position}`).then(res => { + this.$set(targetStyle, position, res ? res[0].width + 'px' : '0px'); + }); + }) + }, delayTime) + }) + }, + //通过获取css设置的底部安全区域占位view高度设置bottom距离 + _getCssSafeAreaInsetBottom(success) { + this._getNodeClientRect('.zp-safe-area-inset-bottom').then(res => { + this.cssSafeAreaInsetBottom = res ? res[0].height : -1; + res && success && success(); + }); + } + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/data-handle.js b/src/uni_modules/z-paging/components/z-paging/js/modules/data-handle.js new file mode 100644 index 0000000..9cfebb5 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/data-handle.js @@ -0,0 +1,717 @@ +// [z-paging]数据处理模块 +import u from '.././z-paging-utils' +import c from '.././z-paging-constant' +import Enum from '.././z-paging-enum' +import interceptor from '../z-paging-interceptor' + +export default { + props: { + //自定义初始的pageNo,默认为1 + defaultPageNo: { + type: [Number, String], + default: u.gc('defaultPageNo', 1), + observer: function(newVal) { + this.pageNo = newVal; + }, + }, + //自定义pageSize,默认为10 + defaultPageSize: { + type: [Number, String], + default: u.gc('defaultPageSize', 10), + validator: (value) => { + if (value <= 0) u.consoleErr('default-page-size必须大于0!'); + return value > 0; + } + }, + //为保证数据一致,设置当前tab切换时的标识key,并在complete中传递相同key,若二者不一致,则complete将不会生效 + dataKey: { + type: [Number, String, Object], + default: function() { + return u.gc('dataKey', null); + }, + }, + //使用缓存,若开启将自动缓存第一页的数据,默认为否。请注意,因考虑到切换tab时不同tab数据不同的情况,默认仅会缓存组件首次加载时第一次请求到的数据,后续的下拉刷新操作不会更新缓存。 + useCache: { + type: Boolean, + default: u.gc('useCache', false) + }, + //使用缓存时缓存的key,用于区分不同列表的缓存数据,useCache为true时必须设置,否则缓存无效 + cacheKey: { + type: String, + default: u.gc('cacheKey', null) + }, + //缓存模式,默认仅会缓存组件首次加载时第一次请求到的数据,可设置为always,即代表总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存 + cacheMode: { + type: String, + default: u.gc('cacheMode', Enum.CacheMode.Default) + }, + //自动注入的list名,可自动修改父view(包含ref="paging")中对应name的list值 + autowireListName: { + type: String, + default: u.gc('autowireListName', '') + }, + //自动注入的query名,可自动调用父view(包含ref="paging")中的query方法 + autowireQueryName: { + type: String, + default: u.gc('autowireQueryName', '') + }, + //z-paging mounted后自动调用reload方法(mounted后自动调用接口),默认为是 + auto: { + type: Boolean, + default: u.gc('auto', true) + }, + //用户下拉刷新时是否触发reload方法,默认为是 + reloadWhenRefresh: { + type: Boolean, + default: u.gc('reloadWhenRefresh', true) + }, + //reload时自动滚动到顶部,默认为是 + autoScrollToTopWhenReload: { + type: Boolean, + default: u.gc('autoScrollToTopWhenReload', true) + }, + //reload时立即自动清空原list,默认为是,若立即自动清空,则在reload之后、请求回调之前页面是空白的 + autoCleanListWhenReload: { + type: Boolean, + default: u.gc('autoCleanListWhenReload', true) + }, + //列表刷新时自动显示下拉刷新view,默认为否 + showRefresherWhenReload: { + type: Boolean, + default: u.gc('showRefresherWhenReload', false) + }, + //列表刷新时自动显示加载更多view,且为加载中状态,默认为否 + showLoadingMoreWhenReload: { + type: Boolean, + default: u.gc('showLoadingMoreWhenReload', false) + }, + //组件created时立即触发reload(可解决一些情况下先看到页面再看到loading的问题),auto为true时有效。为否时将在mounted+nextTick后触发reload,默认为否 + createdReload: { + type: Boolean, + default: u.gc('createdReload', false) + }, + //本地分页时上拉加载更多延迟时间,单位为毫秒,默认200毫秒 + localPagingLoadingTime: { + type: [Number, String], + default: u.gc('localPagingLoadingTime', 200) + }, + //使用聊天记录模式,默认为否 + useChatRecordMode: { + type: Boolean, + default: u.gc('useChatRecordMode', false) + }, + //使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是 + autoHideKeyboardWhenChat: { + type: Boolean, + default: u.gc('autoHideKeyboardWhenChat', true) + }, + //自动拼接complete中传过来的数组(使用聊天记录模式时无效) + concat: { + type: Boolean, + default: u.gc('concat', true) + }, + //父组件v-model所绑定的list的值 + value: { + type: Array, + default: function() { + return []; + } + }, + // #ifdef VUE3 + modelValue: { + type: Array, + default: function() { + return []; + } + } + // #endif + }, + data (){ + return { + currentData: [], + totalData: [], + realTotalData: [], + totalLocalPagingList: [], + dataPromiseResultMap: { + reload: null, + complete: null, + localPaging: null + }, + isSettingCacheList: false, + pageNo: 1, + currentRefreshPageSize: 0, + isLocalPaging: false, + isAddedData: false, + isTotalChangeFromAddData: false, + privateConcat: true, + myParentQuery: -1, + firstPageLoaded: false, + pagingLoaded: false, + loaded: false, + isUserReload: true, + fromEmptyViewReload: false, + queryFrom: '', + listRendering: false, + } + }, + computed: { + pageSize() { + return this.defaultPageSize; + }, + finalConcat() { + return this.concat && this.privateConcat; + }, + finalUseCache() { + if (this.useCache && !this.cacheKey) { + u.consoleErr('use-cache为true时,必须设置cache-key,否则缓存无效!'); + } + return this.useCache && !!this.cacheKey; + }, + finalCacheKey() { + return this.cacheKey ? `${c.cachePrefixKey}-${this.cacheKey}` : null; + }, + isFirstPage() { + return this.pageNo === this.defaultPageNo; + } + }, + watch: { + totalData(newVal, oldVal) { + this._totalDataChange(newVal, oldVal); + }, + currentData(newVal, oldVal) { + this._currentDataChange(newVal, oldVal); + }, + useChatRecordMode(newVal, oldVal) { + if (newVal) { + this.nLoadingMoreFixedHeight = false; + } + }, + value: { + handler(newVal) { + this.realTotalData = newVal; + }, + immediate: true + }, + // #ifdef VUE3 + modelValue: { + handler(newVal) { + this.realTotalData = newVal; + }, + immediate: true + } + // #endif + }, + methods: { + //请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否成功(默认是是) + complete(data, success = true) { + this.customNoMore = -1; + return this.addData(data, success); + }, + //【保证数据一致】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为dataKey,需与:data-key绑定的一致,第三个参数为是否成功(默认为是) + completeByKey(data, dataKey = null, success = true) { + if (dataKey !== null && this.dataKey !== null && dataKey !== this.dataKey) { + this.isFirstPage && this.endRefresh(); + return new Promise(resolve => resolve()); + } + this.customNoMore = -1; + return this.addData(data, success); + }, + //【通过total判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为total(列表总数),第三个参数为是否成功(默认为是) + completeByTotal(data, total, success = true) { + if (total == 'undefined') { + this.customNoMore = -1; + } else { + const dataTypeRes = this._checkDataType(data, success, false); + data = dataTypeRes.data; + success = dataTypeRes.success; + if (total >= 0 && success) { + return new Promise((resolve, reject) => { + this.$nextTick(() => { + let nomore = false; + const realTotalDataCount = this.pageNo == this.defaultPageNo ? 0 : this.realTotalData.length; + const dataLength = this.privateConcat ? data.length : 0; + let exceedCount = realTotalDataCount + dataLength - total; + if (exceedCount >= 0) { + nomore = true; + exceedCount = this.defaultPageSize - exceedCount; + if (this.privateConcat && exceedCount > 0 && exceedCount < data.length) { + data = data.splice(0, exceedCount); + } + } + this.completeByNoMore(data, nomore, success).then(res => resolve(res)).catch(() => reject()); + }) + }); + } + } + return this.addData(data, success); + }, + //【自行判断是否有更多数据】请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging处理,第一个参数为请求结果数组,第二个参数为是否有更多数据,第三个参数为是否成功(默认是是) + completeByNoMore(data, nomore, success = true) { + if (nomore != 'undefined') { + this.customNoMore = nomore == true ? 1 : 0; + } + return this.addData(data, success); + }, + //与上方complete方法功能一致,新版本中设置服务端回调数组请使用complete方法 + addData(data, success = true) { + if (!this.fromCompleteEmit) { + this.disabledCompleteEmit = true; + this.fromCompleteEmit = false; + } + const currentTimeStamp = u.getTime(); + const disTime = currentTimeStamp - this.requestTimeStamp; + let minDelay = this.minDelay; + if (this.isFirstPage && this.finalShowRefresherWhenReload) { + minDelay = Math.max(400, minDelay); + } + const addDataDalay = (this.requestTimeStamp > 0 && disTime < minDelay) ? minDelay - disTime : 0; + this.$nextTick(() => { + u.delay(() => { + this._addData(data, success, false); + }, this.delay > 0 ? this.delay : addDataDalay) + }) + + return new Promise((resolve, reject) => { + this.dataPromiseResultMap.complete = { resolve, reject }; + }); + }, + //从顶部添加数据,不会影响分页的pageNo和pageSize + addDataFromTop(data, toTop = true, toTopWithAnimate = true) { + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data; + this.totalData = [...data, ...this.totalData]; + if (toTop) { + u.delay(() => { + this._scrollToTop(toTopWithAnimate); + }) + } + }, + //重新设置列表数据,调用此方法不会影响pageNo和pageSize,也不会触发请求。适用场景:当需要删除列表中某一项时,将删除对应项后的数组通过此方法传递给z-paging。(当出现类似的需要修改列表数组的场景时,请使用此方法,请勿直接修改page中:list.sync绑定的数组) + resetTotalData(data) { + this.isTotalChangeFromAddData = true; + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data; + this.totalData = data; + }, + //添加聊天记录 + addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) { + data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data; + if (!this.useChatRecordMode) return; + this.isTotalChangeFromAddData = true; + //#ifndef APP-NVUE + this.totalData = [...this.totalData, ...data]; + //#endif + //#ifdef APP-NVUE + this.totalData = this.nIsFirstPageAndNoMore ? [...this.totalData, ...data] : [...data, ...this.totalData]; + //#endif + if (toBottom) { + u.delay(() => { + //#ifndef APP-NVUE + this._scrollToBottom(toBottomWithAnimate); + //#endif + //#ifdef APP-NVUE + this.nIsFirstPageAndNoMore ? this._scrollToBottom(toBottomWithAnimate) : this._scrollToTop(toBottomWithAnimate); + //#endif + }) + } + }, + //设置本地分页数据,请求结束(成功或者失败)调用此方法,将请求的结果传递给z-paging作分页处理(若调用了此方法,则上拉加载更多时内部会自动分页,不会触发@query所绑定的事件) + setLocalPaging(data, success = true) { + this.isLocalPaging = true; + this.$nextTick(() => { + this._addData(data, success, true); + }) + return new Promise((resolve, reject) => { + this.dataPromiseResultMap.localPaging = { resolve, reject }; + }); + }, + //重新加载分页数据,pageNo会恢复为默认值,相当于下拉刷新的效果(animate为true时会展示下拉刷新动画,默认为false) + reload(animate = this.showRefresherWhenReload) { + if (animate) { + this.privateShowRefresherWhenReload = animate; + this.isUserPullDown = true; + } + if (!this.showLoadingMoreWhenReload) { + this.listRendering = true; + } + this.$nextTick(() => { + this._preReload(animate, false); + }) + return new Promise((resolve, reject) => { + this.dataPromiseResultMap.reload = { resolve, reject }; + }); + }, + //刷新列表数据,pageNo和pageSize不会重置,列表数据会重新从服务端获取。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致 + refresh() { + if (!this.realTotalData.length) return this.reload(); + const disPageNo = this.pageNo - this.defaultPageNo + 1; + if (disPageNo >= 1) { + this.loading = true; + this.privateConcat = false; + const totalPageSize = disPageNo * this.pageSize; + this.currentRefreshPageSize = totalPageSize; + this._emitQuery(this.defaultPageNo, totalPageSize, Enum.QueryFrom.Refresh); + this._callMyParentQuery(this.defaultPageNo, totalPageSize); + } + return new Promise((resolve, reject) => { + this.dataPromiseResultMap.reload = { resolve, reject }; + }); + }, + //手动更新列表缓存数据,将自动截取v-model绑定的list中的前pageSize条覆盖缓存,请确保在list数据更新到预期结果后再调用此方法 + updateCache() { + if (this.finalUseCache && this.totalData.length) { + this._saveLocalCache(this.totalData.slice(0, Math.min(this.totalData.length, this.pageSize))); + } + }, + //清空分页数据 + clean() { + this._reload(true); + this._addData([], true, false); + }, + //清空分页数据 + clear() { + this.clean(); + }, + //手动触发滚动到顶部加载更多,聊天记录模式时有效 + doChatRecordLoadMore() { + this.useChatRecordMode && this._onLoadingMore('click'); + }, + //reload之前的一些处理 + _preReload(animate = this.showRefresherWhenReload, isFromMounted = true) { + this.isUserReload = true; + this.loadingType = Enum.LoadingType.Refresher; + if (animate) { + this.privateShowRefresherWhenReload = animate; + // #ifndef APP-NVUE + if (this.useCustomRefresher) { + this._doRefresherRefreshAnimate(); + } else { + this.refresherTriggered = true; + } + // #endif + // #ifdef APP-NVUE + this.refresherStatus = Enum.Refresher.Loading; + this.refresherRevealStackCount ++; + u.delay(() => { + this._getNodeClientRect('zp-n-refresh-container', false).then((node) => { + if (node) { + let nodeHeight = node[0].height; + this.nShowRefresherReveal = true; + this.nShowRefresherRevealHeight = nodeHeight; + u.delay(() => { + this._nDoRefresherEndAnimation(0, -nodeHeight, false, false); + u.delay(() => { + this._nDoRefresherEndAnimation(nodeHeight, 0); + }, 10) + }, 10) + } + this._reload(false, isFromMounted); + this._doRefresherLoad(false); + }); + }, this.pagingLoaded ? 10 : 100) + return; + // #endif + } else { + this._refresherEnd(false, false, false, false); + } + this._reload(false, isFromMounted); + }, + //重新加载分页数据 + _reload(isClean = false, isFromMounted = false, isUserPullDown = false) { + this.isAddedData = false; + this.insideOfPaging = -1; + this.cacheScrollNodeHeight = -1; + this.pageNo = this.defaultPageNo; + this._cleanRefresherEndTimeout(); + !this.privateShowRefresherWhenReload && !isClean && this._startLoading(true); + this.firstPageLoaded = true; + this.isTotalChangeFromAddData = false; + if (!this.isSettingCacheList) { + this.totalData = []; + } + if (!isClean) { + this._emitQuery(this.pageNo, this.defaultPageSize, isUserPullDown ? Enum.QueryFrom.UserPullDown : Enum.QueryFrom.Reload); + let delay = 0; + // #ifdef MP-TOUTIAO + delay = 5; + // #endif + u.delay(this._callMyParentQuery, delay); + if (!isFromMounted && this.autoScrollToTopWhenReload) { + let checkedNRefresherLoading = true; + // #ifdef APP-NVUE + checkedNRefresherLoading = !this.nRefresherLoading; + // #endif + checkedNRefresherLoading && this._scrollToTop(false); + } + } + // #ifdef APP-NVUE + this.$nextTick(() => { + this.nShowBottom = this.realTotalData.length > 0; + }) + // #endif + }, + //处理服务端返回的数组 + _addData(data, success, isLocal) { + this.isAddedData = true; + this.fromEmptyViewReload = false; + this.isTotalChangeFromAddData = true; + this.refresherTriggered = false; + this._endSystemLoadingAndRefresh(); + const tempIsUserPullDown = this.isUserPullDown; + if (this.showRefresherUpdateTime && this.isFirstPage) { + u.setRefesrherTime(u.getTime(), this.refresherUpdateTimeKey); + this.$refs.refresh && this.$refs.refresh.updateTime(); + } + if (!isLocal && tempIsUserPullDown && this.isFirstPage) { + this.isUserPullDown = false; + } + if (!this.isFirstPage) { + this.listRendering = true; + this.$nextTick(() => { + u.delay(() => { + this.listRendering = false; + }) + }) + } else { + this.listRendering = false; + } + let dataTypeRes = this._checkDataType(data, success, isLocal); + data = dataTypeRes.data; + success = dataTypeRes.success; + let delayTime = c.delayTime; + // #ifdef APP-NVUE + if (this.useChatRecordMode) delayTime = 0; + // #endif + this.loadingForNow = false; + u.delay(() => { + this.pagingLoaded = true; + this.$nextTick(()=>{ + !isLocal && this._refresherEnd(delayTime > 0, true, tempIsUserPullDown); + }) + }) + if (this.isFirstPage) { + this.isLoadFailed = !success; + this.$emit('isLoadFailedChange', this.isLoadFailed); + if (this.finalUseCache && success && (this.cacheMode === Enum.CacheMode.Always ? true : this.isSettingCacheList)) { + this._saveLocalCache(data); + } + } + this.isSettingCacheList = false; + if (success) { + if (!(this.privateConcat === false && this.loadingStatus === Enum.More.NoMore)) { + this.loadingStatus = Enum.More.Default; + } + if (isLocal) { + this.totalLocalPagingList = data; + const localPageNo = this.defaultPageNo; + const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize; + this._localPagingQueryList(localPageNo, localPageSize, 0, res => { + this.completeByTotal(res, this.totalLocalPagingList.length); + }) + } else { + let dataChangeDelayTime = 0; + // #ifdef APP-NVUE + if (this.privateShowRefresherWhenReload && this.finalNvueListIs === 'waterfall') { + dataChangeDelayTime = 150; + } + // #endif + u.delay(() => { + this._currentDataChange(data, this.currentData); + this._callDataPromise(true, this.totalData); + }, dataChangeDelayTime) + } + } else { + this._currentDataChange(data, this.currentData); + this._callDataPromise(false); + this.loadingStatus = Enum.More.Fail; + if (this.loadingType === Enum.LoadingType.LoadingMore) { + this.pageNo --; + } + } + }, + //所有数据改变时调用 + _totalDataChange(newVal, oldVal, eventThrow=true) { + if ((!this.isUserReload || !this.autoCleanListWhenReload) && this.firstPageLoaded && !newVal.length && oldVal.length) { + return; + } + this._doCheckScrollViewShouldFullHeight(newVal); + if(!this.realTotalData.length && !newVal.length){ + eventThrow = false; + } + this.realTotalData = newVal; + if (eventThrow) { + this.$emit('input', newVal); + // #ifdef VUE3 + this.$emit('update:modelValue', newVal); + // #endif + this.$emit('update:list', newVal); + this.$emit('listChange', newVal); + this._callMyParentList(newVal); + } + this.firstPageLoaded = false; + this.isTotalChangeFromAddData = false; + this.$nextTick(() => { + u.delay(()=>{ + this._getNodeClientRect('.zp-paging-container-content').then(res => { + res && this.$emit('contentHeightChanged', res[0].height); + }); + }, c.delayTime * (this.isIos ? 1 : 3)) + // #ifdef APP-NVUE + if (this.useChatRecordMode && this.nIsFirstPageAndNoMore && this.isFirstPage && !this.nFirstPageAndNoMoreChecked) { + this.nFirstPageAndNoMoreChecked = true; + this._scrollToBottom(false); + } + u.delay(() => { + this.nShowBottom = true; + }, c.delayTime * 6, 'nShowBottomDelay'); + // #endif + }) + }, + //当前数据改变时调用 + _currentDataChange(newVal, oldVal) { + newVal = [...newVal]; + // #ifndef APP-NVUE + this.finalUseVirtualList && this._setCellIndex(newVal, this.totalData.length === 0) + this.useChatRecordMode && newVal.reverse(); + // #endif + if (this.isFirstPage && this.finalConcat) { + this.totalData = []; + } + if (this.customNoMore !== -1) { + if (this.customNoMore === 1 || !newVal.length) { + this.loadingStatus = Enum.More.NoMore; + } + } else { + if (!newVal.length || (newVal.length && newVal.length < this.defaultPageSize)) { + this.loadingStatus = Enum.More.NoMore; + } + } + if (!this.totalData.length) { + if (this.finalConcat) { + // #ifdef APP-NVUE + if (this.useChatRecordMode && this.isFirstPage && this.loadingStatus === Enum.More.NoMore) { + newVal.reverse(); + } + // #endif + this.totalData = newVal; + } + if (this.useChatRecordMode) { + // #ifndef APP-NVUE + this.$nextTick(() => { + this._scrollToBottom(false); + }) + // #endif + } + } else { + if (this.useChatRecordMode) { + // #ifdef APP-NVUE + this.totalData = [...this.totalData, ...newVal]; + // #endif + //#ifndef APP-NVUE + const idIndex = newVal.length; + let idIndexStr = `z-paging-${idIndex}`; + this.totalData = [...newVal, ...this.totalData]; + if (this.pageNo !== this.defaultPageNo) { + this.privateScrollWithAnimation = 0; + this.$emit('update:chatIndex', idIndex); + this.$nextTick(() => { + this._scrollIntoView(idIndexStr, 30 + Math.max(0, this.cacheTopHeight), false, () => { + this.$emit('update:chatIndex', 0); + }); + }) + } else { + this.$nextTick(() => { + this._scrollToBottom(false); + }) + } + //#endif + + } else { + if (this.finalConcat) { + const currentScrollTop = this.oldScrollTop; + this.totalData = [...this.totalData, ...newVal]; + // #ifdef MP-WEIXIN + if (!this.isIos && !this.refresherOnly && !this.usePageScroll && newVal.length) { + this.loadingMoreTimeStamp = u.getTime(); + this.$nextTick(() => { + this.scrollToY(currentScrollTop); + }) + } + // #endif + } else { + this.totalData = newVal; + } + } + } + this.privateConcat = true; + }, + //本地分页请求 + _localPagingQueryList(pageNo, pageSize, localPagingLoadingTime, callback) { + pageNo = Math.max(1, pageNo); + pageSize = Math.max(1, pageSize); + const totalPagingList = [...this.totalLocalPagingList]; + const pageNoIndex = (pageNo - 1) * pageSize; + const finalPageNoIndex = Math.min(totalPagingList.length, pageNoIndex + pageSize); + const resultPagingList = totalPagingList.splice(pageNoIndex, finalPageNoIndex - pageNoIndex); + u.delay(() => callback(resultPagingList), localPagingLoadingTime) + }, + //存储列表缓存数据 + _saveLocalCache(data) { + uni.setStorageSync(this.finalCacheKey, data); + }, + //通过缓存数据填充列表数据 + _setListByLocalCache() { + this.totalData = uni.getStorageSync(this.finalCacheKey) || []; + this.isSettingCacheList = true; + }, + //修改父view的list + _callMyParentList(newVal) { + if (this.autowireListName.length) { + const myParent = u.getParent(this.$parent); + if (myParent && myParent[this.autowireListName]) { + myParent[this.autowireListName] = newVal; + } + } + }, + //调用父view的query + _callMyParentQuery(customPageNo = 0, customPageSize = 0) { + if (this.autowireQueryName) { + if (this.myParentQuery === -1) { + const myParent = u.getParent(this.$parent); + if (myParent && myParent[this.autowireQueryName]) { + this.myParentQuery = myParent[this.autowireQueryName]; + } + } + if (this.myParentQuery !== -1) { + customPageSize > 0 ? this.myParentQuery(customPageNo, customPageSize) : this.myParentQuery(this.pageNo, this.defaultPageSize); + } + } + }, + //emit query事件 + _emitQuery(pageNo, pageSize, from){ + this.queryFrom = from; + this.requestTimeStamp = u.getTime(); + const [lastItem] = this.realTotalData.slice(-1); + this.$emit('query', ...interceptor._handleQuery(pageNo, pageSize, from, lastItem || null)); + }, + //触发数据改变promise + _callDataPromise(success, totalList) { + for (const key in this.dataPromiseResultMap) { + const obj = this.dataPromiseResultMap[key]; + success ? (!!obj && obj.resolve({ totalList, noMore: this.loadingStatus === Enum.More.NoMore })) : (!!obj && obj.reject()); + } + }, + //检查complete data的类型 + _checkDataType(data, success, isLocal) { + const dataType = Object.prototype.toString.call(data); + if (dataType === '[object Boolean]') { + success = data; + data = []; + } else if (dataType !== '[object Array]') { + data = []; + if (dataType !== '[object Undefined]' && dataType !== '[object Null]') { + u.consoleErr(`${isLocal ? 'setLocalPaging' : 'complete'}参数类型不正确,第一个参数类型必须为Array!`); + } + } + return { data, success }; + }, + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/empty.js b/src/uni_modules/z-paging/components/z-paging/js/modules/empty.js new file mode 100644 index 0000000..3d6ec6f --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/empty.js @@ -0,0 +1,147 @@ +// [z-paging]空数据图view模块 +import u from '.././z-paging-utils' + +export default { + props: { + //是否强制隐藏空数据图,默认为否 + hideEmptyView: { + type: Boolean, + default: u.gc('hideEmptyView', false) + }, + //空数据图描述文字,默认为“没有数据哦~” + emptyViewText: { + type: [String, Object], + default: u.gc('emptyViewText', null) + }, + //是否显示空数据图重新加载按钮(无数据时),默认为否 + showEmptyViewReload: { + type: Boolean, + default: u.gc('showEmptyViewReload', false) + }, + //加载失败时是否显示空数据图重新加载按钮,默认为是 + showEmptyViewReloadWhenError: { + type: Boolean, + default: u.gc('showEmptyViewReloadWhenError', true) + }, + //空数据图点击重新加载文字,默认为“重新加载” + emptyViewReloadText: { + type: [String, Object], + default: u.gc('emptyViewReloadText', null) + }, + //空数据图图片,默认使用z-paging内置的图片 + emptyViewImg: { + type: String, + default: u.gc('emptyViewImg', '') + }, + //空数据图“加载失败”描述文字,默认为“很抱歉,加载失败” + emptyViewErrorText: { + type: [String, Object], + default: u.gc('emptyViewErrorText', null) + }, + //空数据图“加载失败”图片,默认使用z-paging内置的图片 + emptyViewErrorImg: { + type: String, + default: u.gc('emptyViewErrorImg', '') + }, + //空数据图样式 + emptyViewStyle: { + type: Object, + default: function() { + return u.gc('emptyViewStyle', {}); + } + }, + //空数据图容器样式 + emptyViewSuperStyle: { + type: Object, + default: function() { + return u.gc('emptyViewSuperStyle', {}); + } + }, + //空数据图img样式 + emptyViewImgStyle: { + type: Object, + default: function() { + return u.gc('emptyViewImgStyle', {}); + } + }, + //空数据图描述文字样式 + emptyViewTitleStyle: { + type: Object, + default: function() { + return u.gc('emptyViewTitleStyle', {}); + } + }, + //空数据图重新加载按钮样式 + emptyViewReloadStyle: { + type: Object, + default: function() { + return u.gc('emptyViewReloadStyle', {}); + } + }, + //空数据图片是否铺满z-paging,默认为否,即填充满z-paging内列表(滚动区域)部分。若设置为否,则为填铺满整个z-paging + emptyViewFixed: { + type: Boolean, + default: u.gc('emptyViewFixed', false) + }, + //空数据图片是否垂直居中,默认为是,若设置为否即为从空数据容器顶部开始显示。emptyViewFixed为false时有效 + emptyViewCenter: { + type: Boolean, + default: u.gc('emptyViewCenter', true) + }, + //加载中时是否自动隐藏空数据图,默认为是 + autoHideEmptyViewWhenLoading: { + type: Boolean, + default: u.gc('autoHideEmptyViewWhenLoading', true) + }, + //用户下拉列表触发下拉刷新加载中时是否自动隐藏空数据图,默认为是 + autoHideEmptyViewWhenPull: { + type: Boolean, + default: u.gc('autoHideEmptyViewWhenPull', true) + }, + //空数据view的z-index,默认为9 + emptyViewZIndex: { + type: Number, + default: u.gc('emptyViewZIndex', 9) + }, + }, + computed: { + finalEmptyViewImg() { + return this.isLoadFailed ? this.emptyViewErrorImg : this.emptyViewImg; + }, + finalShowEmptyViewReload() { + return this.isLoadFailed ? this.showEmptyViewReloadWhenError : this.showEmptyViewReload; + }, + showEmpty() { + if (this.refresherOnly || this.hideEmptyView || this.realTotalData.length) return false; + if (this.autoHideEmptyViewWhenLoading) { + if (this.isAddedData && !this.firstPageLoaded && !this.loading) return true; + } else { + return true; + } + return !this.autoHideEmptyViewWhenPull && !this.isUserReload; + }, + }, + methods: { + //点击了空数据view重新加载按钮 + _emptyViewReload() { + let callbacked = false; + this.$emit('emptyViewReload', reload => { + if (reload === undefined || reload === true) { + this.fromEmptyViewReload = true; + this.reload(); + } + callbacked = true; + }); + this.$nextTick(() => { + if (!callbacked) { + this.fromEmptyViewReload = true; + this.reload(); + } + }) + }, + //点击了空数据view + _emptyViewClick() { + this.$emit('emptyViewClick'); + }, + } +} \ No newline at end of file diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/i18n.js b/src/uni_modules/z-paging/components/z-paging/js/modules/i18n.js new file mode 100644 index 0000000..4a99a71 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/i18n.js @@ -0,0 +1,100 @@ +// [z-paging]i18n模块 +import { initVueI18n } from '@dcloudio/uni-i18n' +import messages from '../../i18n/index.js' +const { t } = initVueI18n(messages) + +import u from '.././z-paging-utils' +import c from '.././z-paging-constant' +import interceptor from '../z-paging-interceptor' + +export default { + data() { + return { + language: uni.getSystemInfoSync().language + } + }, + computed: { + finalLanguage() { + try { + const local = uni.getLocale(); + const language = this.language; + return local === 'auto' ? interceptor._handleLanguage2Local(language, this._language2Local(language)) : local; + } catch (e) { + return 'zh-Hans'; + } + }, + finalRefresherDefaultText() { + return this._getI18nText('zp.refresher.default', this.refresherDefaultText); + }, + finalRefresherPullingText() { + return this._getI18nText('zp.refresher.pulling', this.refresherPullingText); + }, + finalRefresherRefreshingText() { + return this._getI18nText('zp.refresher.refreshing', this.refresherRefreshingText); + }, + finalRefresherCompleteText() { + return this._getI18nText('zp.refresher.complete', this.refresherCompleteText); + }, + finalRefresherUpdateTimeTextMap() { + return { + title: t('zp.refresherUpdateTime.title'), + none: t('zp.refresherUpdateTime.none'), + today: t('zp.refresherUpdateTime.today'), + yesterday: t('zp.refresherUpdateTime.yesterday') + }; + }, + finalLoadingMoreDefaultText() { + return this._getI18nText('zp.loadingMore.default', this.loadingMoreDefaultText); + }, + finalLoadingMoreLoadingText() { + return this._getI18nText('zp.loadingMore.loading', this.loadingMoreLoadingText); + }, + finalLoadingMoreNoMoreText() { + return this._getI18nText('zp.loadingMore.noMore', this.loadingMoreNoMoreText); + }, + finalLoadingMoreFailText() { + return this._getI18nText('zp.loadingMore.fail', this.loadingMoreFailText); + }, + finalEmptyViewText() { + return this.isLoadFailed ? this.finalEmptyViewErrorText : this._getI18nText('zp.emptyView.title', this.emptyViewText); + }, + finalEmptyViewReloadText() { + return this._getI18nText('zp.emptyView.reload', this.emptyViewReloadText); + }, + finalEmptyViewErrorText() { + return this._getI18nText('zp.emptyView.error', this.emptyViewErrorText); + }, + finalSystemLoadingText() { + return this._getI18nText('zp.systemLoading.title', this.systemLoadingText); + }, + }, + methods: { + //获取当前z-paging的语言 + getLanguage() { + return this.finalLanguage; + }, + //获取国际化转换后的文本 + _getI18nText(key, value) { + const dataType = Object.prototype.toString.call(value); + if (dataType === '[object Object]') { + const nextValue = value[this.finalLanguage]; + if (nextValue) return nextValue; + } else if (dataType === '[object String]') { + return value; + } + return t(key); + }, + //系统language转i18n local + _language2Local(language) { + const formatedLanguage = language.toLowerCase().replace(new RegExp('_', ''), '-'); + if (formatedLanguage.indexOf('zh') !== -1) { + if (formatedLanguage === 'zh' || formatedLanguage === 'zh-cn' || formatedLanguage.indexOf('zh-hans') !== -1) { + return 'zh-Hans'; + } + return 'zh-Hant'; + } + if (formatedLanguage.indexOf('en') !== -1) return 'en'; + return language; + } + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/load-more.js b/src/uni_modules/z-paging/components/z-paging/js/modules/load-more.js new file mode 100644 index 0000000..c24a535 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/load-more.js @@ -0,0 +1,315 @@ +// [z-paging]滚动到底部加载更多模块 +import u from '.././z-paging-utils' +import Enum from '.././z-paging-enum' + +export default { + props: { + //自定义底部加载更多样式 + loadingMoreCustomStyle: { + type: Object, + default: function() { + return u.gc('loadingMoreCustomStyle', {}); + } + }, + //自定义底部加载更多文字样式 + loadingMoreTitleCustomStyle: { + type: Object, + default: function() { + return u.gc('loadingMoreTitleCustomStyle', {}); + } + }, + //自定义底部加载更多加载中动画样式 + loadingMoreLoadingIconCustomStyle: { + type: Object, + default: function() { + return u.gc('loadingMoreLoadingIconCustomStyle', {}); + } + }, + //自定义底部加载更多加载中动画图标类型,可选flower或circle,默认为flower + loadingMoreLoadingIconType: { + type: String, + default: u.gc('loadingMoreLoadingIconType', 'flower') + }, + //自定义底部加载更多加载中动画图标图片 + loadingMoreLoadingIconCustomImage: { + type: String, + default: u.gc('loadingMoreLoadingIconCustomImage', '') + }, + //底部加载更多加载中view是否展示旋转动画,默认为是 + loadingMoreLoadingAnimated: { + type: Boolean, + default: u.gc('loadingMoreLoadingAnimated', true) + }, + //是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为是 + loadingMoreEnabled: { + type: Boolean, + default: u.gc('loadingMoreEnabled', true) + }, + //是否启用滑动到底部加载更多数据,默认为是 + toBottomLoadingMoreEnabled: { + type: Boolean, + default: u.gc('toBottomLoadingMoreEnabled', true) + }, + //滑动到底部状态为默认状态时,以加载中的状态展示,默认为否。若设置为是,可避免滚动到底部看到默认状态然后立刻变为加载中状态的问题,但分页数量未超过一屏时,不会显示【点击加载更多】 + loadingMoreDefaultAsLoading: { + type: [Boolean], + default: u.gc('loadingMoreDefaultAsLoading', false) + }, + //滑动到底部"默认"文字,默认为【点击加载更多】 + loadingMoreDefaultText: { + type: [String, Object], + default: u.gc('loadingMoreDefaultText', null) + }, + //滑动到底部"加载中"文字,默认为【正在加载...】 + loadingMoreLoadingText: { + type: [String, Object], + default: u.gc('loadingMoreLoadingText', null) + }, + //滑动到底部"没有更多"文字,默认为【没有更多了】 + loadingMoreNoMoreText: { + type: [String, Object], + default: u.gc('loadingMoreNoMoreText', null) + }, + //滑动到底部"加载失败"文字,默认为【加载失败,点击重新加载】 + loadingMoreFailText: { + type: [String, Object], + default: u.gc('loadingMoreFailText', null) + }, + //当没有更多数据且分页内容未超出z-paging时是否隐藏没有更多数据的view,默认为否 + hideNoMoreInside: { + type: Boolean, + default: u.gc('hideNoMoreInside', false) + }, + //当没有更多数据且分页数组长度少于这个值时,隐藏没有更多数据的view,默认为0,代表不限制。 + hideNoMoreByLimit: { + type: Number, + default: u.gc('hideNoMoreByLimit', 0) + }, + //是否显示默认的加载更多text,默认为是 + showDefaultLoadingMoreText: { + type: Boolean, + default: u.gc('showDefaultLoadingMoreText', true) + }, + //是否显示没有更多数据的view + showLoadingMoreNoMoreView: { + type: Boolean, + default: u.gc('showLoadingMoreNoMoreView', true) + }, + //是否显示没有更多数据的分割线,默认为是 + showLoadingMoreNoMoreLine: { + type: Boolean, + default: u.gc('showLoadingMoreNoMoreLine', true) + }, + //自定义底部没有更多数据的分割线样式 + loadingMoreNoMoreLineCustomStyle: { + type: Object, + default: function() { + return u.gc('loadingMoreNoMoreLineCustomStyle', {}); + }, + }, + //当分页未满一屏时,是否自动加载更多,默认为否(nvue无效) + insideMore: { + type: Boolean, + default: u.gc('insideMore', false) + }, + //距底部/右边多远时(单位px),触发 scrolltolower 事件,默认为100rpx + lowerThreshold: { + type: [Number, String], + default: u.gc('lowerThreshold', '100rpx') + }, + }, + data() { + return { + M: Enum.More, + //底部加载更多状态 + loadingStatus: Enum.More.Default, + loadingStatusAfterRender: Enum.More.Default, + loadingMoreTimeStamp: 0, + loadingMoreDefaultSlot: null, + showLoadingMore: false, + customNoMore: -1, + } + }, + computed: { + zLoadMoreConfig() { + return { + status: this.loadingStatusAfterRender, + defaultAsLoading: this.loadingMoreDefaultAsLoading, + defaultThemeStyle: this.finalLoadingMoreThemeStyle, + customStyle: this.loadingMoreCustomStyle, + titleCustomStyle: this.loadingMoreTitleCustomStyle, + iconCustomStyle: this.loadingMoreLoadingIconCustomStyle, + loadingIconType: this.loadingMoreLoadingIconType, + loadingIconCustomImage: this.loadingMoreLoadingIconCustomImage, + loadingAnimated: this.loadingMoreLoadingAnimated, + showNoMoreLine: this.showLoadingMoreNoMoreLine, + noMoreLineCustomStyle: this.loadingMoreNoMoreLineCustomStyle, + defaultText: this.finalLoadingMoreDefaultText, + loadingText: this.finalLoadingMoreLoadingText, + noMoreText: this.finalLoadingMoreNoMoreText, + failText: this.finalLoadingMoreFailText, + hideContent: !this.loadingMoreDefaultAsLoading && this.listRendering, + }; + }, + finalLoadingMoreThemeStyle() { + return this.loadingMoreThemeStyle.length ? this.loadingMoreThemeStyle : this.defaultThemeStyle; + }, + showLoadingMoreDefault() { + return this._showLoadingMore('Default'); + }, + showLoadingMoreLoading() { + return this._showLoadingMore('Loading'); + }, + showLoadingMoreNoMore() { + return this._showLoadingMore('NoMore'); + }, + showLoadingMoreFail() { + return this._showLoadingMore('Fail'); + }, + showLoadingMoreCustom() { + return this._showLoadingMore('Custom'); + } + }, + methods: { + //页面滚动到底部时通知z-paging进行进一步处理 + pageReachBottom() { + !this.useChatRecordMode && this._onLoadingMore('toBottom'); + }, + //手动触发上拉加载更多(非必须,可依据具体需求使用) + doLoadMore(type) { + this._onLoadingMore(type); + }, + //通过@scroll事件检测是否滚动到了底部 + _checkScrolledToBottom(scrollDiff, checked = false) { + if (this.cacheScrollNodeHeight === -1) { + this._getNodeClientRect('.zp-scroll-view').then((res) => { + if (res) { + const pageScrollNodeHeight = res[0].height; + this.cacheScrollNodeHeight = pageScrollNodeHeight; + if (scrollDiff - pageScrollNodeHeight <= this.finalLowerThreshold) { + this._onLoadingMore('toBottom'); + } + } + }); + } else { + if (scrollDiff - this.cacheScrollNodeHeight <= this.finalLowerThreshold) { + this._onLoadingMore('toBottom'); + } else if (scrollDiff - this.cacheScrollNodeHeight <= 500 && !checked) { + u.delay(() => { + this._getNodeClientRect('.zp-scroll-view', true, true).then((res) => { + this.oldScrollTop = res[0].scrollTop; + const newScrollDiff = res[0].scrollHeight - this.oldScrollTop; + this._checkScrolledToBottom(newScrollDiff, true); + }) + }, 150, 'checkScrolledToBottomDelay') + } + } + }, + //触发加载更多时调用,from:0-滑动到底部触发;1-点击加载更多触发 + _onLoadingMore(from = 'click') { + if (from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) { + this.scrollEnable = false; + this.$nextTick(() => { + this.scrollEnable = true; + }) + } + this.$emit('scrolltolower', from); + if (from === 'toBottom' && (!this.toBottomLoadingMoreEnabled || this.useChatRecordMode)) return; + if (this.refresherOnly || !this.loadingMoreEnabled || !(this.loadingStatus === Enum.More.Default || this.loadingStatus === Enum.More.Fail) || this.loading) return; + // #ifdef MP-WEIXIN + if (!this.isIos && !this.refresherOnly && !this.usePageScroll) { + const currentTimestamp = u.getTime(); + if (this.loadingMoreTimeStamp > 0 && currentTimestamp - this.loadingMoreTimeStamp < 100) { + this.loadingMoreTimeStamp = 0; + return; + } + } + // #endif + this._doLoadingMore(); + }, + //处理开始加载更多 + _doLoadingMore() { + if (this.pageNo >= this.defaultPageNo && this.loadingStatus !== Enum.More.NoMore) { + this.pageNo ++; + this._startLoading(false); + if (this.isLocalPaging) { + this._localPagingQueryList(this.pageNo, this.defaultPageSize, this.localPagingLoadingTime, res => { + this.completeByTotal(res, this.totalLocalPagingList.length); + }) + } else { + this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadingMore); + this._callMyParentQuery(); + } + this.loadingType = Enum.LoadingType.LoadingMore; + } + }, + //(预处理)判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view + _preCheckShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode) { + if (this.loadingStatus === Enum.More.NoMore && this.hideNoMoreByLimit > 0 && newVal.length) { + this.showLoadingMore = newVal.length > this.hideNoMoreByLimit; + } else if ((this.loadingStatus === Enum.More.NoMore && this.hideNoMoreInside && newVal.length) || (this.insideMore && this.insideOfPaging !== false && newVal.length)) { + this.$nextTick(() => { + this._checkShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode); + }) + if (this.insideMore && this.insideOfPaging !== false && newVal.length) { + this.showLoadingMore = newVal.length; + } + } else { + this.showLoadingMore = newVal.length; + } + }, + //判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view + async _checkShowNoMoreInside(totalData, oldScrollViewNode, oldPagingContainerNode) { + try { + const scrollViewNode = oldScrollViewNode || await this._getNodeClientRect('.zp-scroll-view'); + if (this.usePageScroll) { + if (scrollViewNode) { + const scrollViewTotalH = scrollViewNode[0].top + scrollViewNode[0].height; + this.insideOfPaging = scrollViewTotalH < this.windowHeight; + if (this.hideNoMoreInside) { + this.showLoadingMore = !this.insideOfPaging; + } + this._updateInsideOfPaging(); + } + } else { + const pagingContainerNode = oldPagingContainerNode || await this._getNodeClientRect('.zp-paging-container-content'); + const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0; + const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0; + this.insideOfPaging = pagingContainerH < scrollViewH; + if (this.hideNoMoreInside) { + this.showLoadingMore = !this.insideOfPaging; + } + this._updateInsideOfPaging(); + } + } catch (e) { + this.insideOfPaging = !totalData.length; + if (this.hideNoMoreInside) { + this.showLoadingMore = !this.insideOfPaging; + } + this._updateInsideOfPaging(); + } + }, + //是否要展示上拉加载更多view + _showLoadingMore(type) { + if (!this.showLoadingMoreWhenReload && (!(this.loadingStatus === Enum.More.Default ? this.nShowBottom : true) || !this.realTotalData.length)) return false; + if (((!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading) && !this.showLoadingMore) || + (!this.loadingMoreEnabled && (!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading)) || this.refresherOnly) { + return false; + } + if (this.useChatRecordMode && type !== 'Loading') return false; + if (!this.$slots) return false; + if (type === 'Custom') { + return this.showDefaultLoadingMoreText && !(this.loadingStatus === Enum.More.NoMore && !this.showLoadingMoreNoMoreView); + } + const res = this.loadingStatus === Enum.More[type] && this.$slots[`loadingMore${type}`] && (type === 'NoMore' ? this.showLoadingMoreNoMoreView : true); + if (res) { + // #ifdef APP-NVUE + if (!this.isIos) { + this.nLoadingMoreFixedHeight = false; + } + // #endif + } + return res; + }, + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/loading.js b/src/uni_modules/z-paging/components/z-paging/js/modules/loading.js new file mode 100644 index 0000000..52960a5 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/loading.js @@ -0,0 +1,93 @@ +// [z-paging]loading相关模块 +import u from '.././z-paging-utils' +import Enum from '.././z-paging-enum' + +export default { + props: { + //第一次加载后自动隐藏loading slot,默认为是 + autoHideLoadingAfterFirstLoaded: { + type: Boolean, + default: u.gc('autoHideLoadingAfterFirstLoaded', true) + }, + //loading slot是否铺满屏幕并固定,默认为否 + loadingFullFixed: { + type: Boolean, + default: u.gc('loadingFullFixed', false) + }, + //是否自动显示系统Loading:即uni.showLoading,若开启则将在刷新列表时(调用reload、refresh时)显示,下拉刷新和滚动到底部加载更多不会显示,默认为false。 + autoShowSystemLoading: { + type: Boolean, + default: u.gc('autoShowSystemLoading', false) + }, + //显示系统Loading时是否显示透明蒙层,防止触摸穿透,默认为是(H5、App、微信小程序、百度小程序有效) + systemLoadingMask: { + type: Boolean, + default: u.gc('systemLoadingMask', true) + }, + //显示系统Loading时显示的文字,默认为"加载中" + systemLoadingText: { + type: [String, Object], + default: u.gc('systemLoadingText', null) + }, + }, + data() { + return { + loading: false, + loadingForNow: false, + } + }, + watch: { + loadingStatus(newVal) { + this.$emit('loadingStatusChange', newVal); + this.$nextTick(() => { + this.loadingStatusAfterRender = newVal; + }) + // #ifdef APP-NVUE + if (this.useChatRecordMode) { + if (this.pageNo === this.defaultPageNo && newVal === Enum.More.NoMore) { + this.nIsFirstPageAndNoMore = true; + return; + } + } + this.nIsFirstPageAndNoMore = false; + // #endif + }, + loading(newVal){ + if (newVal) { + this.loadingForNow = newVal; + } + }, + }, + computed: { + showLoading() { + if (this.firstPageLoaded || !this.loading || !this.loadingForNow) return false; + if (this.finalShowSystemLoading){ + uni.showLoading({ + title: this.finalSystemLoadingText, + mask: this.systemLoadingMask + }) + } + return this.autoHideLoadingAfterFirstLoaded ? (this.fromEmptyViewReload ? true : !this.pagingLoaded) : this.loadingType === Enum.LoadingType.Refresher; + }, + finalShowSystemLoading() { + return this.autoShowSystemLoading && this.loadingType === Enum.LoadingType.Refresher; + } + }, + methods: { + //处理开始加载更多状态 + _startLoading(isReload = false) { + if ((this.showLoadingMoreWhenReload && !this.isUserPullDown) || !isReload) { + this.loadingStatus = Enum.More.Loading; + } + this.loading = true; + }, + //停止系统loading和refresh + _endSystemLoadingAndRefresh(){ + this.finalShowSystemLoading && uni.hideLoading(); + !this.useCustomRefresher && uni.stopPullDownRefresh(); + // #ifdef APP-NVUE + this.usePageScroll && uni.stopPullDownRefresh(); + // #endif + } + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/nvue.js b/src/uni_modules/z-paging/components/z-paging/js/modules/nvue.js new file mode 100644 index 0000000..2228841 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/nvue.js @@ -0,0 +1,249 @@ +// [z-paging]nvue独有部分模块 +import u from '.././z-paging-utils' +import c from '.././z-paging-constant' +import Enum from '.././z-paging-enum' + +// #ifdef APP-NVUE +const weexAnimation = weex.requireModule('animation'); +// #endif +export default { + props: { + // #ifdef APP-NVUE + //nvue中修改列表类型,可选值有list、waterfall和scroller,默认为list + nvueListIs: { + type: String, + default: u.gc('nvueListIs', 'list') + }, + //nvue waterfall配置,仅在nvue中且nvueListIs=waterfall时有效,配置参数详情参见:https://uniapp.dcloud.io/component/waterfall + nvueWaterfallConfig: { + type: Object, + default: function() { + return u.gc('nvueWaterfallConfig', {}); + } + }, + //nvue 控制是否回弹效果,iOS不支持动态修改 + nvueBounce: { + type: Boolean, + default: u.gc('nvueBounce', true) + }, + //nvue中通过代码滚动到顶部/底部时,是否加快动画效果(无滚动动画时无效),默认为否 + nvueFastScroll: { + type: Boolean, + default: u.gc('nvueFastScroll', false) + }, + //nvue中list的id + nvueListId: { + type: String, + default: u.gc('nvueListId', '') + }, + //nvue中refresh组件的样式 + nvueRefresherStyle: { + type: Object, + default: function() { + return u.gc('nvueRefresherStyle', {}); + } + }, + //nvue中是否按分页模式(类似竖向swiper)显示List,默认为false + nvuePagingEnabled: { + type: Boolean, + default: u.gc('nvuePagingEnabled', false) + }, + //是否隐藏nvue列表底部的tagView,此view用于标识滚动到底部位置,若隐藏则滚动到底部功能将失效,在nvue中实现吸顶+swiper功能时需将最外层z-paging的此属性设置为true。默认为否 + hideNvueBottomTag: { + type: Boolean, + default: u.gc('hideNvueBottomTag', false) + }, + //nvue中控制onscroll事件触发的频率:表示两次onscroll事件之间列表至少滚动了10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能 + offsetAccuracy: { + type: Number, + default: u.gc('offsetAccuracy', 10) + }, + // #endif + }, + data() { + return { + nRefresherLoading: false, + nListIsDragging: false, + nShowBottom: true, + nFixFreezing: false, + nShowRefresherReveal: false, + nIsFirstPageAndNoMore: false, + nFirstPageAndNoMoreChecked: false, + nLoadingMoreFixedHeight: false, + nShowRefresherRevealHeight: 0, + nOldShowRefresherRevealHeight: -1, + nRefresherWidth: uni.upx2px(750), + } + }, + watch: { + // #ifdef APP-NVUE + nIsFirstPageAndNoMore: { + handler(newVal) { + const cellStyle = !this.useChatRecordMode || newVal ? {} : { transform: 'rotate(180deg)' }; + this.$emit('update:cellStyle', cellStyle); + this.$emit('cellStyleChange', cellStyle); + }, + immediate: true + }, + // #endif + }, + computed: { + // #ifdef APP-NVUE + nScopedSlots() { + // #ifdef VUE2 + return this.$scopedSlots; + // #endif + // #ifdef VUE3 + return null; + // #endif + }, + nWaterfallColumnCount() { + if (this.finalNvueListIs !== 'waterfall') return 0; + return this._nGetWaterfallConfig('column-count', 2); + }, + nWaterfallColumnWidth() { + return this._nGetWaterfallConfig('column-width', 'auto'); + }, + nWaterfallColumnGap() { + return this._nGetWaterfallConfig('column-gap', 'normal'); + }, + nWaterfallLeftGap() { + return this._nGetWaterfallConfig('left-gap', 0); + }, + nWaterfallRightGap() { + return this._nGetWaterfallConfig('right-gap', 0); + }, + nViewIs() { + const is = this.finalNvueListIs; + return is === 'scroller' || is === 'view' ? 'view' : is === 'waterfall' ? 'header' : 'cell'; + }, + nSafeAreaBottomHeight() { + return this.safeAreaInsetBottom ? this.safeAreaBottom : 0; + }, + nChatRecordRotateStyle() { + return this.useChatRecordMode ? { transform: this.nIsFirstPageAndNoMore ? 'rotate(0deg)' : 'rotate(180deg)' } : {}; + }, + finalNvueListIs() { + if (this.usePageScroll) return 'view'; + const nvueListIsLowerCase = this.nvueListIs.toLowerCase(); + if (['list','waterfall','scroller'].indexOf(nvueListIsLowerCase) !== -1) return nvueListIsLowerCase; + return 'list'; + }, + finalNvueSuperListIs() { + return this.usePageScroll ? 'view' : 'scroller'; + }, + finalNvueRefresherEnabled() { + return this.finalNvueListIs !== 'view' && this.finalRefresherEnabled && !this.nShowRefresherReveal && !this.useChatRecordMode; + }, + // #endif + }, + mounted(){ + // #ifdef APP-NVUE + //旋转屏幕时更新宽度 + uni.onWindowResize((res) => { + // this._nUpdateRefresherWidth(); + }) + // #endif + }, + methods: { + // #ifdef APP-NVUE + //列表滚动时触发 + _nOnScroll(e) { + this.$emit('scroll', e); + const contentOffsetY = -e.contentOffset.y; + this.oldScrollTop = contentOffsetY; + this.nListIsDragging = e.isDragging; + this._checkShouldShowBackToTop(contentOffsetY, contentOffsetY - 1); + }, + //下拉刷新刷新中 + _nOnRrefresh() { + if (this.nShowRefresherReveal) return; + this.nRefresherLoading = true; + this.refresherStatus = Enum.Refresher.Loading; + this._doRefresherLoad(); + }, + //下拉刷新下拉中 + _nOnPullingdown(e) { + if (this.refresherStatus === Enum.Refresher.Loading || (this.isIos && !this.nListIsDragging)) return; + this._emitTouchmove(e); + const { viewHeight, pullingDistance } = e; + this.refresherStatus = pullingDistance >= viewHeight ? Enum.Refresher.ReleaseToRefresh : Enum.Refresher.Default; + }, + //下拉刷新结束 + _nRefresherEnd(doEnd = true) { + if (doEnd) { + this._nDoRefresherEndAnimation(0, -this.nShowRefresherRevealHeight); + !this.usePageScroll && this.$refs['zp-n-list'].resetLoadmore(); + this.nRefresherLoading = false; + } + }, + //执行主动触发下拉刷新动画 + _nDoRefresherEndAnimation(height, translateY, animate = true, checkStack = true) { + this._cleanRefresherCompleteTimeout(); + this._cleanRefresherEndTimeout(); + + if (!this.finalShowRefresherWhenReload) { + this.refresherEndTimeout = u.delay(() => { + this.refresherStatus = Enum.Refresher.Default; + }, this.refresherCompleteDuration); + return; + } + const stackCount = this.refresherRevealStackCount; + if (height === 0 && checkStack) { + this.refresherRevealStackCount --; + if (stackCount > 1) return; + this.refresherEndTimeout = u.delay(() => { + this.refresherStatus = Enum.Refresher.Default; + }, this.refresherCompleteDuration); + } + if (stackCount > 1) { + this.refresherStatus = Enum.Refresher.Loading; + } + + const duration = animate ? 200 : 0; + if (this.nOldShowRefresherRevealHeight !== height) { + if (height > 0) { + this.nShowRefresherReveal = true; + } + weexAnimation.transition(this.$refs['zp-n-list-refresher-reveal'], { + styles: { + height: `${height}px`, + transform: `translateY(${translateY}px)`, + }, + duration, + timingFunction: 'linear', + needLayout: true, + delay: 0 + }) + } + u.delay(() => { + if (animate) { + this.nShowRefresherReveal = height > 0; + } + }, duration > 0 ? duration - 60 : 0); + this.nOldShowRefresherRevealHeight = height; + }, + //滚动到底部加载更多 + _nOnLoadmore() { + if (this.nShowRefresherReveal || !this.totalData.length) return; + this.useChatRecordMode ? this.doChatRecordLoadMore() : this._onLoadingMore('toBottom'); + }, + //获取nvue waterfall单项配置 + _nGetWaterfallConfig(key, defaultValue) { + return this.nvueWaterfallConfig[key] || defaultValue; + }, + //更新nvue 下拉刷新view容器的宽度 + _nUpdateRefresherWidth() { + u.delay(() => { + this.$nextTick(()=>{ + this._getNodeClientRect('.zp-n-list').then(node => { + if (node) { + this.nRefresherWidth = node[0].width || this.nRefresherWidth; + } + }) + }) + }) + } + // #endif + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/refresher.js b/src/uni_modules/z-paging/components/z-paging/js/modules/refresher.js new file mode 100644 index 0000000..d8fd8ad --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/refresher.js @@ -0,0 +1,681 @@ +// [z-paging]下拉刷新view模块 +import u from '.././z-paging-utils' +import c from '.././z-paging-constant' +import Enum from '.././z-paging-enum' + +export default { + props: { + //下拉刷新的主题样式,支持black,white,默认black + refresherThemeStyle: { + type: String, + default: u.gc('refresherThemeStyle', '') + }, + //自定义下拉刷新中左侧图标的样式 + refresherImgStyle: { + type: Object, + default: function() { + return u.gc('refresherImgStyle', {}); + } + }, + //自定义下拉刷新中右侧状态描述文字的样式 + refresherTitleStyle: { + type: Object, + default: function() { + return u.gc('refresherTitleStyle', {}); + } + }, + //自定义下拉刷新中右侧最后更新时间文字的样式(show-refresher-update-time为true时有效) + refresherUpdateTimeStyle: { + type: Object, + default: function() { + return u.gc('refresherUpdateTimeStyle', {}); + } + }, + //在微信小程序和QQ小程序中,是否实时监听下拉刷新中进度,默认为否 + watchRefresherTouchmove: { + type: Boolean, + default: u.gc('watchRefresherTouchmove', false) + }, + //底部加载更多的主题样式,支持black,white,默认black + loadingMoreThemeStyle: { + type: String, + default: u.gc('loadingMoreThemeStyle', '') + }, + //是否只使用下拉刷新,设置为true后将关闭mounted自动请求数据、关闭滚动到底部加载更多,强制隐藏空数据图。默认为否 + refresherOnly: { + type: Boolean, + default: u.gc('refresherOnly', false) + }, + //自定义下拉刷新默认状态下回弹动画时间,单位为毫秒,默认为100毫秒,nvue无效 + refresherDefaultDuration: { + type: [Number, String], + default: u.gc('refresherDefaultDuration', 100) + }, + //自定义下拉刷新结束以后延迟回弹的时间,单位为毫秒,默认为0 + refresherCompleteDelay: { + type: [Number, String], + default: u.gc('refresherCompleteDelay', 0) + }, + //自定义下拉刷新结束回弹动画时间,单位为毫秒,默认为300毫秒(refresherEndBounceEnabled为false时,refresherCompleteDuration为设定值的1/3),nvue无效 + refresherCompleteDuration: { + type: [Number, String], + default: u.gc('refresherCompleteDuration', 300) + }, + //自定义下拉刷新结束状态下是否允许列表滚动,默认为否 + refresherCompleteScrollable: { + type: Boolean, + default: u.gc('refresherCompleteScrollable', false) + }, + //是否使用自定义的下拉刷新,默认为是,即使用z-paging的下拉刷新。设置为false即代表使用uni scroll-view自带的下拉刷新,h5、App、微信小程序以外的平台不支持uni scroll-view自带的下拉刷新 + useCustomRefresher: { + type: Boolean, + default: u.gc('useCustomRefresher', true) + }, + //自定义下拉刷新下拉帧率,默认为40,过高可能会出现抖动问题 + refresherFps: { + type: [Number, String], + default: u.gc('refresherFps', 40) + }, + //自定义下拉刷新允许触发的最大下拉角度,默认为40度,当下拉角度小于设定值时,自定义下拉刷新动画不会被触发 + refresherMaxAngle: { + type: [Number, String], + default: u.gc('refresherMaxAngle', 40) + }, + //自定义下拉刷新的角度由未达到最大角度变到达到最大角度时,是否继续下拉刷新手势,默认为否 + refresherAngleEnableChangeContinued: { + type: Boolean, + default: u.gc('refresherAngleEnableChangeContinued', false) + }, + //自定义下拉刷新默认状态下的文字 + refresherDefaultText: { + type: [String, Object], + default: u.gc('refresherDefaultText', null) + }, + //自定义下拉刷新松手立即刷新状态下的文字 + refresherPullingText: { + type: [String, Object], + default: u.gc('refresherPullingText', null) + }, + //自定义下拉刷新刷新中状态下的文字 + refresherRefreshingText: { + type: [String, Object], + default: u.gc('refresherRefreshingText', null) + }, + //自定义下拉刷新刷新结束状态下的文字 + refresherCompleteText: { + type: [String, Object], + default: u.gc('refresherCompleteText', null) + }, + //自定义下拉刷新默认状态下的图片 + refresherDefaultImg: { + type: String, + default: u.gc('refresherDefaultImg', null) + }, + //自定义下拉刷新松手立即刷新状态下的图片,默认与refresherDefaultImg一致 + refresherPullingImg: { + type: String, + default: u.gc('refresherPullingImg', null) + }, + //自定义下拉刷新刷新中状态下的图片 + refresherRefreshingImg: { + type: String, + default: u.gc('refresherRefreshingImg', null) + }, + //自定义下拉刷新刷新结束状态下的图片 + refresherCompleteImg: { + type: String, + default: u.gc('refresherCompleteImg', null) + }, + //自定义下拉刷新刷新中状态下是否展示旋转动画 + refresherRefreshingAnimated: { + type: Boolean, + default: u.gc('refresherRefreshingAnimated', true) + }, + //是否开启自定义下拉刷新刷新结束回弹效果,默认为是 + refresherEndBounceEnabled: { + type: Boolean, + default: u.gc('refresherEndBounceEnabled', true) + }, + //是否开启自定义下拉刷新,默认为是 + refresherEnabled: { + type: Boolean, + default: u.gc('refresherEnabled', true) + }, + //设置自定义下拉刷新阈值,默认为80rpx + refresherThreshold: { + type: [Number, String], + default: u.gc('refresherThreshold', '80rpx') + }, + //设置系统下拉刷新默认样式,支持设置 black,white,none,none 表示不使用默认样式,默认为black + refresherDefaultStyle: { + type: String, + default: u.gc('refresherDefaultStyle', 'black') + }, + //设置自定义下拉刷新区域背景 + refresherBackground: { + type: String, + default: u.gc('refresherBackground', 'transparent') + }, + //设置固定的自定义下拉刷新区域背景 + refresherFixedBackground: { + type: String, + default: u.gc('refresherFixedBackground', 'transparent') + }, + //设置固定的自定义下拉刷新区域高度,默认为0 + refresherFixedBacHeight: { + type: [Number, String], + default: u.gc('refresherFixedBacHeight', 0) + }, + //设置自定义下拉刷新下拉超出阈值后继续下拉位移衰减的比例,范围0-1,值越大代表衰减越多。默认为0.65(nvue无效) + refresherOutRate: { + type: Number, + default: u.gc('refresherOutRate', 0.65) + }, + //设置自定义下拉刷新下拉时实际下拉位移与用户下拉距离的比值,默认为0.75,即代表若用户下拉10px,则实际位移为7.5px(nvue无效) + refresherPullRate: { + type: Number, + default: u.gc('refresherPullRate', 0.75) + }, + //是否显示最后更新时间,默认为否 + showRefresherUpdateTime: { + type: Boolean, + default: u.gc('showRefresherUpdateTime', false) + }, + //如果需要区别不同页面的最后更新时间,请为不同页面的z-paging的`refresher-update-time-key`设置不同的字符串 + refresherUpdateTimeKey: { + type: String, + default: u.gc('refresherUpdateTimeKey', 'default') + }, + //下拉刷新时下拉到“松手立即刷新”状态时是否使手机短振动,默认为否(h5无效) + refresherVibrate: { + type: Boolean, + default: u.gc('refresherVibrate', false) + }, + //下拉刷新时是否禁止下拉刷新view跟随用户触摸竖直移动,默认为否。注意此属性只是禁止下拉刷新view移动,其他下拉刷新逻辑依然会正常触发 + refresherNoTransform: { + type: Boolean, + default: u.gc('refresherNoTransform', false) + }, + }, + data() { + return { + R: Enum.Refresher, + //下拉刷新状态 + refresherStatus: Enum.Refresher.Default, + refresherTouchstartY: 0, + lastRefresherTouchmove: null, + refresherReachMaxAngle: true, + refresherTransform: 'translateY(0px)', + refresherTransition: '', + finalRefresherDefaultStyle: 'black', + refresherRevealStackCount: 0, + refresherCompleteTimeout: null, + refresherCompleteSubTimeout: null, + refresherEndTimeout: null, + isTouchmovingTimeout: null, + refresherTriggered: false, + isTouchmoving: false, + isTouchEnded: false, + isUserPullDown: false, + privateRefresherEnabled: -1, + privateShowRefresherWhenReload: false, + customRefresherHeight: -1, + showCustomRefresher: false, + doRefreshAnimateAfter: false, + isRefresherInComplete: false, + pullDownTimeStamp: 0, + moveDis: 0, + oldMoveDis: 0, + currentDis: 0, + oldCurrentMoveDis: 0, + oldRefresherTouchmoveY: 0, + oldTouchDirection: '', + oldEmitedTouchDirection: '', + oldPullingDistance: -1 + } + }, + watch: { + refresherDefaultStyle: { + handler(newVal) { + if (newVal.length) { + this.finalRefresherDefaultStyle = newVal; + } + }, + immediate: true + }, + refresherStatus(newVal) { + newVal === Enum.Refresher.Loading && this._cleanRefresherEndTimeout(); + this.refresherVibrate && newVal === Enum.Refresher.ReleaseToRefresh && this._doVibrateShort(); + this.$emit('refresherStatusChange', newVal); + this.$emit('update:refresherStatus', newVal); + }, + refresherEnabled(newVal) { + !newVal && this.endRefresh(); + } + }, + computed: { + pullDownDisTimeStamp() { + return 1000 / this.refresherFps; + }, + finalRefresherEnabled() { + if (this.useChatRecordMode) return false; + if (this.privateRefresherEnabled === -1) return this.refresherEnabled; + return this.privateRefresherEnabled === 1; + }, + finalRefresherThreshold() { + let refresherThreshold = this.refresherThreshold; + let idDefault = false; + if (refresherThreshold === '80rpx') { + idDefault = true; + if (this.showRefresherUpdateTime) { + refresherThreshold = '120rpx'; + } + } + if (idDefault && this.customRefresherHeight > 0) return this.customRefresherHeight; + return u.convertToPx(refresherThreshold); + }, + finalRefresherFixedBacHeight() { + return u.convertToPx(this.refresherFixedBacHeight); + }, + finalRefresherThemeStyle() { + return this.refresherThemeStyle.length ? this.refresherThemeStyle : this.defaultThemeStyle; + }, + finalRefresherOutRate() { + let rate = this.refresherOutRate; + rate = Math.max(0,rate); + rate = Math.min(1,rate); + return rate; + }, + finalRefresherPullRate() { + let rate = this.refresherPullRate; + rate = Math.max(0,rate); + return rate; + }, + finalRefresherTransform() { + if (this.refresherNoTransform || this.refresherTransform === 'translateY(0px)') return 'none'; + return this.refresherTransform; + }, + finalShowRefresherWhenReload() { + return this.showRefresherWhenReload || this.privateShowRefresherWhenReload; + }, + finalRefresherTriggered() { + if (!(this.finalRefresherEnabled && !this.useCustomRefresher)) return false; + return this.refresherTriggered; + }, + showRefresher() { + const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher; + // #ifndef APP-NVUE + if (this.customRefresherHeight === -1 && showRefresher) { + u.delay(() => { + this.$nextTick(()=>{ + this._updateCustomRefresherHeight(); + }) + }) + } + // #endif + return showRefresher; + }, + hasTouchmove(){ + // #ifdef VUE2 + // #ifdef APP-VUE || H5 + if (this.$listeners && !this.$listeners.refresherTouchmove) return false; + // #endif + // #ifdef MP-WEIXIN || MP-QQ + return this.watchRefresherTouchmove; + // #endif + return true; + // #endif + return this.watchRefresherTouchmove; + }, + }, + methods: { + //终止下拉刷新状态 + endRefresh(){ + this.totalData = this.realTotalData; + this._refresherEnd(); + this._endSystemLoadingAndRefresh(); + this._handleScrollViewDisableBounce({ bounce: true }); + }, + handleRefresherStatusChanged(func) { + this.refresherStatusChangedFunc = func; + }, + //自定义下拉刷新被触发 + _onRefresh(fromScrollView = false,isUserPullDown = true) { + if (fromScrollView && !(this.finalRefresherEnabled && !this.useCustomRefresher)) return; + this.$emit('onRefresh'); + this.$emit('Refresh'); + // #ifdef APP-NVUE + if (this.loading) { + u.delay(this._nRefresherEnd, 500) + return; + } + // #endif + if (this.loading || this.isRefresherInComplete) return; + this.loadingType = Enum.LoadingType.Refresher; + if (this.nShowRefresherReveal) return; + this.isUserPullDown = isUserPullDown; + this.isUserReload = !isUserPullDown; + this._startLoading(true); + this.refresherTriggered = true; + if(this.reloadWhenRefresh && isUserPullDown){ + this.useChatRecordMode ? this._onLoadingMore('click') : this._reload(false, false, isUserPullDown); + } + }, + //自定义下拉刷新被复位 + _onRestore() { + this.refresherTriggered = 'restore'; + this.$emit('onRestore'); + this.$emit('Restore'); + }, + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + //拖拽开始 + _refresherTouchstart(e) { + this._handleListTouchstart(); + if (this._touchDisabled()) return; + this._handleRefresherTouchstart(u.getTouch(e)); + }, + // #endif + //进一步处理拖拽开始结果 + _handleRefresherTouchstart(touch) { + if (!this.loading && this.isTouchEnded) { + this.isTouchmoving = false; + } + this.loadingType = Enum.LoadingType.Refresher; + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout); + this.isTouchEnded = false; + this.refresherTransition = ''; + this.refresherTouchstartY = touch.touchY; + this.$emit('refresherTouchstart', this.refresherTouchstartY); + this.lastRefresherTouchmove = touch; + this._cleanRefresherCompleteTimeout(); + this._cleanRefresherEndTimeout(); + }, + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + //拖拽中 + _refresherTouchmove(e) { + const currentTimeStamp = u.getTime(); + let touch = null; + let refresherTouchmoveY = 0; + if (this.watchTouchDirectionChange) { + touch = u.getTouch(e); + refresherTouchmoveY = touch.touchY; + const direction = refresherTouchmoveY > this.oldRefresherTouchmoveY ? 'top' : 'bottom'; + if (direction === this.oldTouchDirection && direction !== this.oldEmitedTouchDirection) { + this._handleTouchDirectionChange({ direction }); + this.oldEmitedTouchDirection = direction; + } + this.oldTouchDirection = direction; + this.oldRefresherTouchmoveY = refresherTouchmoveY; + } + if (this.pullDownTimeStamp && currentTimeStamp - this.pullDownTimeStamp <= this.pullDownDisTimeStamp) return; + if (this._touchDisabled()) return; + this.pullDownTimeStamp = Number(currentTimeStamp); + touch = u.getTouch(e); + refresherTouchmoveY = touch.touchY; + let moveDis = refresherTouchmoveY - this.refresherTouchstartY; + if (moveDis < 0) return; + if (this.refresherMaxAngle >= 0 && this.refresherMaxAngle <= 90 && this.lastRefresherTouchmove && this.lastRefresherTouchmove.touchY <= refresherTouchmoveY) { + if (!moveDis && !this.refresherAngleEnableChangeContinued && this.moveDis < 1 && !this.refresherReachMaxAngle) return; + const x = Math.abs(touch.touchX - this.lastRefresherTouchmove.touchX); + const y = Math.abs(refresherTouchmoveY - this.lastRefresherTouchmove.touchY); + const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + if ((x || y) && x > 1) { + const angle = Math.asin(y / z) / Math.PI * 180; + if (angle < this.refresherMaxAngle) { + this.lastRefresherTouchmove = touch; + this.refresherReachMaxAngle = false; + return; + } + } + } + moveDis = this._getFinalRefresherMoveDis(moveDis); + this._handleRefresherTouchmove(moveDis, touch); + if (!this.disabledBounce) { + if(this.isIos){ + // #ifndef MP-LARK + this._handleScrollViewDisableBounce({ bounce: false }); + // #endif + } + this.disabledBounce = true; + } + this._emitTouchmove({ pullingDistance: moveDis, dy: this.moveDis - this.oldMoveDis }); + }, + // #endif + //进一步处理拖拽中结果 + _handleRefresherTouchmove(moveDis, touch) { + this.refresherReachMaxAngle = true; + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout); + this.isTouchmoving = true; + this.isTouchEnded = false; + this.refresherStatus = moveDis >= this.finalRefresherThreshold ? Enum.Refresher.ReleaseToRefresh : this.refresherStatus = Enum.Refresher.Default; + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + // this.scrollEnable = false; + this.refresherTransform = `translateY(${moveDis}px)`; + this.lastRefresherTouchmove = touch; + // #endif + this.moveDis = moveDis; + }, + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + //拖拽结束 + _refresherTouchend(e) { + if (this._touchDisabled() || !this.isTouchmoving) return; + const touch = u.getTouch(e); + let refresherTouchendY = touch.touchY; + let moveDis = refresherTouchendY - this.refresherTouchstartY; + moveDis = this._getFinalRefresherMoveDis(moveDis); + this._handleRefresherTouchend(moveDis); + this._handleScrollViewDisableBounce({bounce: true}); + this.disabledBounce = false; + }, + // #endif + //进一步处理拖拽结束结果 + _handleRefresherTouchend(moveDis) { + // #ifndef APP-PLUS || H5 || MP-WEIXIN + if (!this.isTouchmoving) return; + // #endif + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout); + this.refresherReachMaxAngle = true; + this.isTouchEnded = true; + const refresherThreshold = this.finalRefresherThreshold; + if (moveDis >= refresherThreshold && this.refresherStatus === Enum.Refresher.ReleaseToRefresh) { + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.refresherTransform = `translateY(${refresherThreshold}px)`; + this.refresherTransition = 'transform .1s linear'; + // #endif + u.delay(() => { + this._emitTouchmove({ pullingDistance: refresherThreshold, dy: this.moveDis - refresherThreshold }); + }, 0.1); + this.moveDis = refresherThreshold; + this.refresherStatus = Enum.Refresher.Loading; + this._doRefresherLoad(); + } else { + this._refresherEnd(); + this.isTouchmovingTimeout = u.delay(() => { + this.isTouchmoving = false; + }, this.refresherDefaultDuration); + } + this.scrollEnable = true; + this.$emit('refresherTouchend', moveDis); + }, + //处理列表触摸开始事件 + _handleListTouchstart() { + if (this.useChatRecordMode && this.autoHideKeyboardWhenChat) { + uni.hideKeyboard(); + this.$emit('hidedKeyboard'); + } + }, + //处理scroll-view bounce是否生效 + _handleScrollViewDisableBounce({ bounce }) { + if (!this.usePageScroll && !this.scrollToTopBounceEnabled) { + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.refresherTransition = ''; + // #endif + this.scrollEnable = bounce; + } + }, + //wxs正在下拉状态改变处理 + _handleWxsPullingDownStatusChange(onPullingDown) { + this.wxsOnPullingDown = onPullingDown; + if (onPullingDown && !this.useChatRecordMode) { + this.renderPropScrollTop = 0; + } + }, + //wxs正在下拉处理 + _handleWxsPullingDown({ moveDis, diffDis }){ + this._emitTouchmove({ pullingDistance: moveDis,dy: diffDis }); + }, + //wxs触摸方向改变 + _handleTouchDirectionChange({ direction }) { + this.$emit('touchDirectionChange',direction); + }, + //wxs通知更新其props + _handlePropUpdate(){ + this.wxsPropType = u.getTime().toString(); + }, + //下拉刷新结束 + _refresherEnd(shouldEndLoadingDelay = true, fromAddData = false, isUserPullDown = false, setLoading = true) { + if (this.loadingType === Enum.LoadingType.Refresher) { + const refresherCompleteDelay = (fromAddData && (isUserPullDown || this.showRefresherWhenReload)) ? this.refresherCompleteDelay : 0; + const refresherStatus = refresherCompleteDelay > 0 ? Enum.Refresher.Complete : Enum.Refresher.Default; + if (this.finalShowRefresherWhenReload) { + const stackCount = this.refresherRevealStackCount; + this.refresherRevealStackCount --; + if (stackCount > 1) return; + } + this._cleanRefresherEndTimeout(); + this.refresherEndTimeout = u.delay(() => { + this.refresherStatus = refresherStatus; + }, this.refresherStatus !== Enum.Refresher.Default && refresherStatus === Enum.Refresher.Default ? this.refresherCompleteDuration : 0); + + // #ifndef APP-NVUE + if (refresherCompleteDelay > 0) { + this.isRefresherInComplete = true; + } + // #endif + this._cleanRefresherCompleteTimeout(); + this.refresherCompleteTimeout = u.delay(() => { + let animateDuration = 1; + const animateType = this.refresherEndBounceEnabled && fromAddData ? 'cubic-bezier(0.19,1.64,0.42,0.72)' : 'linear'; + if (fromAddData) { + animateDuration = this.refresherEndBounceEnabled ? this.refresherCompleteDuration / 1000 : this.refresherCompleteDuration / 3000; + } + this.refresherTransition = `transform ${fromAddData ? animateDuration : this.refresherDefaultDuration / 1000}s ${animateType}`; + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.refresherTransform = 'translateY(0px)'; + this.currentDis = 0; + // #endif + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.wxsPropType = this.refresherTransition + 'end' + u.getTime(); + // #endif + // #ifdef APP-NVUE + this._nRefresherEnd(); + // #endif + this.moveDis = 0; + // #ifndef APP-NVUE + if (refresherStatus === Enum.Refresher.Complete) { + if (this.refresherCompleteSubTimeout) { + clearTimeout(this.refresherCompleteSubTimeout); + this.refresherCompleteSubTimeout = null; + } + this.refresherCompleteSubTimeout = u.delay(() => { + this.$nextTick(() => { + this.refresherStatus = Enum.Refresher.Default; + this.isRefresherInComplete = false; + }) + }, animateDuration * 800); + } + // #endif + this._emitTouchmove({ pullingDistance: 0, dy: this.moveDis }); + }, refresherCompleteDelay); + } + if (setLoading) { + u.delay(() => { + this.loading = false; + }, shouldEndLoadingDelay ? c.delayTime : 0); + isUserPullDown && this._onRestore(); + } + }, + //模拟用户手动触发下拉刷新 + _doRefresherRefreshAnimate() { + this._cleanRefresherCompleteTimeout(); + // #ifndef APP-NVUE + const doRefreshAnimateAfter = !this.doRefreshAnimateAfter && (this.finalShowRefresherWhenReload) && this + .customRefresherHeight === -1 && this.refresherThreshold === '80rpx'; + if (doRefreshAnimateAfter) { + this.doRefreshAnimateAfter = true; + return; + } + // #endif + this.refresherRevealStackCount ++; + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.refresherTransform = `translateY(${this.finalRefresherThreshold}px)`; + // #endif + // #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 + this.wxsPropType = 'begin' + u.getTime(); + // #endif + this.moveDis = this.finalRefresherThreshold; + this.refresherStatus = Enum.Refresher.Loading; + this.isTouchmoving = true; + this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout); + this._doRefresherLoad(false); + }, + //触发下拉刷新 + _doRefresherLoad(isUserPullDown = true) { + this._onRefresh(false,isUserPullDown); + this.loading = true; + }, + // #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 + //获取处理后的moveDis + _getFinalRefresherMoveDis(moveDis) { + let diffDis = moveDis - this.oldCurrentMoveDis; + this.oldCurrentMoveDis = moveDis; + if (diffDis > 0) { + diffDis = diffDis * this.finalRefresherPullRate; + if (this.currentDis > this.finalRefresherThreshold) { + diffDis = diffDis * (1 - this.finalRefresherOutRate); + } + } + diffDis = diffDis > 100 ? diffDis / 100 : diffDis; + this.currentDis += diffDis; + this.currentDis = Math.max(0, this.currentDis); + return this.currentDis; + }, + //判断touch手势是否要触发 + _touchDisabled() { + const checkOldScrollTop = this.oldScrollTop > 5; + return this.loading || this.isRefresherInComplete || this.useChatRecordMode || !this.refresherEnabled || !this.useCustomRefresher ||(this.usePageScroll && this.useCustomRefresher && this.pageScrollTop > 10) || (!(this.usePageScroll && this.useCustomRefresher) && checkOldScrollTop); + }, + // #endif + //更新自定义下拉刷新view高度 + _updateCustomRefresherHeight() { + this._getNodeClientRect('.zp-custom-refresher-slot-view').then((res) => { + this.customRefresherHeight = res ? res[0].height : 0; + this.showCustomRefresher = this.customRefresherHeight > 0; + if (this.doRefreshAnimateAfter) { + this.doRefreshAnimateAfter = false; + this._doRefresherRefreshAnimate(); + } + }); + }, + //发射pullingDown事件 + _emitTouchmove(e) { + // #ifndef APP-NVUE + e.viewHeight = this.finalRefresherThreshold; + // #endif + e.rate = e.viewHeight > 0 ? e.pullingDistance / e.viewHeight : 0; + this.hasTouchmove && this.oldPullingDistance !== e.pullingDistance && this.$emit('refresherTouchmove', e); + this.oldPullingDistance = e.pullingDistance; + }, + //清除refresherCompleteTimeout + _cleanRefresherCompleteTimeout() { + this.refresherCompleteTimeout = this._cleanTimeout(this.refresherCompleteTimeout); + // #ifdef APP-NVUE + this._nRefresherEnd(false); + // #endif + }, + //清除refresherEndTimeout + _cleanRefresherEndTimeout() { + this.refresherEndTimeout = this._cleanTimeout(this.refresherEndTimeout); + }, + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/scroller.js b/src/uni_modules/z-paging/components/z-paging/js/modules/scroller.js new file mode 100644 index 0000000..a10b564 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/scroller.js @@ -0,0 +1,462 @@ +// [z-paging]scroll相关模块 +import u from '.././z-paging-utils' +import Enum from '.././z-paging-enum' + +// #ifdef APP-NVUE +const weexDom = weex.requireModule('dom'); +// #endif + +export default { + props: { + //使用页面滚动,默认为否,当设置为是时则使用页面的滚动而非此组件内部的scroll-view的滚动,使用页面滚动时z-paging无需设置确定的高度且对于长列表展示性能更高,但配置会略微繁琐 + usePageScroll: { + type: Boolean, + default: u.gc('usePageScroll', false) + }, + //是否可以滚动,使用内置scroll-view和nvue时有效,默认为是 + scrollable: { + type: Boolean, + default: u.gc('scrollable', true) + }, + //控制是否出现滚动条,默认为是 + showScrollbar: { + type: Boolean, + default: u.gc('showScrollbar', true) + }, + //是否允许横向滚动,默认为否 + scrollX: { + type: Boolean, + default: u.gc('scrollX', false) + }, + //iOS设备上滚动到顶部时是否允许回弹效果,默认为否。关闭回弹效果后可使滚动到顶部与下拉刷新更连贯,但是有吸顶view时滚动到顶部时可能出现抖动。 + scrollToTopBounceEnabled: { + type: Boolean, + default: u.gc('scrollToTopBounceEnabled', false) + }, + //iOS设备上滚动到底部时是否允许回弹效果,默认为是。 + scrollToBottomBounceEnabled: { + type: Boolean, + default: u.gc('scrollToBottomBounceEnabled', true) + }, + //在设置滚动条位置时使用动画过渡,默认为否 + scrollWithAnimation: { + type: Boolean, + default: u.gc('scrollWithAnimation', false) + }, + //值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 + scrollIntoView: { + type: String, + default: u.gc('scrollIntoView', '') + }, + }, + data() { + return { + scrollTop: 0, + oldScrollTop: 0, + scrollViewStyle: {}, + scrollViewContainerStyle: {}, + scrollViewInStyle: {}, + pageScrollTop: -1, + scrollEnable: true, + privateScrollWithAnimation: -1, + cacheScrollNodeHeight: -1 + } + }, + watch: { + oldScrollTop(newVal) { + !this.usePageScroll && this._scrollTopChange(newVal,false); + }, + pageScrollTop(newVal) { + this.usePageScroll && this._scrollTopChange(newVal,true); + }, + usePageScroll: { + handler(newVal) { + this.loaded && this.autoHeight && this._setAutoHeight(!newVal); + // #ifdef H5 + if (newVal) { + this.$nextTick(() => { + const mainScrollRef = this.$refs['zp-scroll-view'].$refs.main; + if (mainScrollRef) { + mainScrollRef.style = {}; + } + }) + } + // #endif + }, + immediate: true + }, + finalScrollTop(newVal) { + if (!this.useChatRecordMode) { + this.renderPropScrollTop = newVal < 6 ? 0 : 10; + } + }, + }, + computed: { + finalScrollWithAnimation() { + if (this.privateScrollWithAnimation !== -1) { + const scrollWithAnimation = this.privateScrollWithAnimation === 1; + this.privateScrollWithAnimation = -1; + return scrollWithAnimation; + } + return this.scrollWithAnimation; + }, + finalScrollViewStyle() { + if (this.superContentZIndex != 1) { + this.scrollViewStyle['z-index'] = this.superContentZIndex; + this.scrollViewStyle['position'] = 'relative'; + } + return this.scrollViewStyle; + }, + finalScrollTop() { + return this.usePageScroll ? this.pageScrollTop : this.oldScrollTop; + }, + finalIsOldWebView() { + return this.isOldWebView && !this.usePageScroll; + } + }, + methods: { + //滚动到顶部,animate为是否展示滚动动画,默认为是 + scrollToTop(animate, checkReverse = true) { + // #ifdef APP-NVUE + if (checkReverse && this.useChatRecordMode) { + if (!this.nIsFirstPageAndNoMore) { + this.scrollToBottom(animate, false); + return; + } + } + // #endif + this.$nextTick(() => { + this._scrollToTop(animate, false); + // #ifdef APP-NVUE + if (this.nvueFastScroll && animate) { + u.delay(() => { + this._scrollToTop(false, false); + }); + } + // #endif + }) + }, + //滚动到底部,animate为是否展示滚动动画,默认为是 + scrollToBottom(animate, checkReverse = true) { + // #ifdef APP-NVUE + if (checkReverse && this.useChatRecordMode) { + if (!this.nIsFirstPageAndNoMore) { + this.scrollToTop(animate, false); + return; + } + } + // #endif + this.$nextTick(() => { + this._scrollToBottom(animate); + // #ifdef APP-NVUE + if (this.nvueFastScroll && animate) { + u.delay(() => { + this._scrollToBottom(false); + }); + } + // #endif + }) + }, + //滚动到指定view(vue中有效)。sel为需要滚动的view的id值,不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否 + scrollIntoViewById(sel, offset, animate) { + this._scrollIntoView(sel, offset, animate); + }, + //滚动到指定view(vue中有效)。nodeTop为需要滚动的view的top值(通过uni.createSelectorQuery()获取);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否 + scrollIntoViewByNodeTop(nodeTop, offset, animate) { + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + this._scrollIntoViewByNodeTop(nodeTop, offset, animate); + }) + }, + //滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否 + scrollToY(y, offset, animate) { + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + this._scrollToY(y, offset, animate); + }) + }, + //滚动到指定view(nvue中有效)。index为需要滚动的view的index(第几个);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否 + scrollIntoViewByIndex(index, offset, animate) { + this._scrollIntoView(index, offset, animate); + }, + //滚动到指定view(nvue中有效)。view为需要滚动的view(通过`this.$refs.xxx`获取),不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否 + scrollIntoViewByView(view, offset, animate) { + this._scrollIntoView(view, offset, animate); + }, + //当使用页面滚动并且自定义下拉刷新时,请在页面的onPageScroll中调用此方法,告知z-paging当前的pageScrollTop,否则会导致在任意位置都可以下拉刷新 + updatePageScrollTop(value) { + this.pageScrollTop = value; + }, + //当使用页面滚动并且设置了slot="top"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="top"的view高度动态改变时,在其高度需要更新时调用此方法 + updatePageScrollTopHeight() { + this._updatePageScrollTopOrBottomHeight('top'); + }, + //当使用页面滚动并且设置了slot="bottom"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="bottom"的view高度动态改变时,在其高度需要更新时调用此方法 + updatePageScrollBottomHeight() { + this._updatePageScrollTopOrBottomHeight('bottom'); + }, + //更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变时调用 + updateLeftAndRightWidth() { + if (!this.finalIsOldWebView) return; + this.$nextTick(() => this._updateLeftAndRightWidth(this.scrollViewContainerStyle, 'zp-page')); + }, + //更新z-paging内置scroll-view的scrollTop + updateScrollViewScrollTop(scrollTop, animate = true) { + this.privateScrollWithAnimation = animate ? 1 : 0; + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + this.scrollTop = scrollTop; + this.oldScrollTop = this.scrollTop; + }); + }, + + //当滚动到顶部时 + _onScrollToUpper() { + this.$emit('scrolltoupper'); + this.$emit('scrollTopChange', 0); + this.$nextTick(() => { + this.oldScrollTop = 0; + }) + if (!this.useChatRecordMode || this.loadingStatus === Enum.More.NoMore) return; + this._onLoadingMore('click'); + }, + //当滚动到底部时 + _onScrollToLower(e) { + (!e.detail || !e.detail.direction || e.detail.direction === 'bottom') && this._onLoadingMore('toBottom') + }, + //滚动到顶部 + _scrollToTop(animate = true, isPrivate = true) { + // #ifdef APP-NVUE + const el = this.$refs['zp-n-list-top-tag']; + if (this.usePageScroll) { + this._getNodeClientRect('zp-page-scroll-top', false).then(node => { + const nodeHeight = node ? node[0].height : 0; + weexDom.scrollToElement(el, { + offset: -nodeHeight, + animated: animate + }); + }); + } else { + if (!this.isIos && this.nvueListIs === 'scroller') { + this._getNodeClientRect('zp-n-refresh-container', false).then(node => { + const nodeHeight = node ? node[0].height : 0; + weexDom.scrollToElement(el, { + offset: -nodeHeight, + animated: animate + }); + }); + } else { + weexDom.scrollToElement(el, { + offset: 0, + animated: animate + }); + } + } + return; + // #endif + if (this.usePageScroll) { + this.$nextTick(() => { + uni.pageScrollTo({ + scrollTop: 0, + duration: animate ? 100 : 0, + }); + }); + return; + } + this.privateScrollWithAnimation = animate ? 1 : 0; + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + this.scrollTop = 0; + this.oldScrollTop = this.scrollTop; + }); + }, + //滚动到底部 + async _scrollToBottom(animate = true) { + // #ifdef APP-NVUE + const el = this.$refs['zp-n-list-bottom-tag']; + if (el) { + weexDom.scrollToElement(el, { + offset: 0, + animated: animate + }); + } else { + u.consoleErr('滚动到底部失败,因为您设置了hideNvueBottomTag为true'); + } + return; + // #endif + if (this.usePageScroll) { + this.$nextTick(() => { + uni.pageScrollTo({ + scrollTop: Number.MAX_VALUE, + duration: animate ? 100 : 0, + }); + }); + return; + } + try { + this.privateScrollWithAnimation = animate ? 1 : 0; + const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container'); + const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view'); + const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0; + const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0; + if (pagingContainerH > scrollViewH) { + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + this.scrollTop = pagingContainerH - scrollViewH + this.virtualPlaceholderTopHeight; + this.oldScrollTop = this.scrollTop; + }); + } + } catch (e) {} + }, + //滚动到指定view + _scrollIntoView(sel, offset = 0, animate = false, finishCallback) { + try { + this.scrollTop = this.oldScrollTop; + this.$nextTick(() => { + // #ifdef APP-NVUE + const refs = this.$parent.$refs; + if (!refs) return; + const dataType = Object.prototype.toString.call(sel); + let el = null; + if (dataType === '[object Number]') { + const els = refs[`z-paging-${sel}`]; + el = els ? els[0] : null; + } else if (dataType === '[object Array]') { + el = sel[0]; + } else { + el = sel; + } + if (el) { + weexDom.scrollToElement(el, { + offset: -offset, + animated: animate + }); + } else { + u.consoleErr('在nvue中滚动到指定位置,cell必须设置 :ref="`z-paging-${index}`"'); + } + return; + // #endif + this._getNodeClientRect('#' + sel.replace('#', ''), this.$parent).then((node) => { + if (node) { + let nodeTop = node[0].top; + this._scrollIntoViewByNodeTop(nodeTop, offset, animate); + finishCallback && finishCallback(); + } + }); + }); + } catch (e) {} + }, + //通过nodeTop滚动到指定view + _scrollIntoViewByNodeTop(nodeTop, offset = 0, animate = false) { + this._scrollToY(nodeTop, offset, animate, true); + }, + //滚动到指定位置 + _scrollToY(y, offset = 0, animate = false, addScrollTop = false) { + this.privateScrollWithAnimation = animate ? 1 : 0; + if (this.usePageScroll) { + uni.pageScrollTo({ + scrollTop: y - offset, + duration: animate ? 100 : 0 + }); + } else { + if(addScrollTop){ + y += this.oldScrollTop; + } + this.scrollTop = y - offset; + this.oldScrollTop = this.scrollTop; + } + }, + //scroll-view滚动中 + _scroll(e) { + this.$emit('scroll', e); + const scrollTop = e.detail.scrollTop; + // #ifndef APP-NVUE + this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop); + // #endif + this.oldScrollTop = scrollTop; + const scrollDiff = e.detail.scrollHeight - this.oldScrollTop; + !this.isIos && this._checkScrolledToBottom(scrollDiff); + }, + //检测scrollView是否要铺满屏幕 + _doCheckScrollViewShouldFullHeight(totalData) { + if (this.autoFullHeight && this.usePageScroll && this.isTotalChangeFromAddData) { + // #ifndef APP-NVUE + this.$nextTick(() => { + this._checkScrollViewShouldFullHeight((scrollViewNode, pagingContainerNode) => { + this._preCheckShowNoMoreInside(totalData, scrollViewNode, pagingContainerNode) + }); + }) + // #endif + // #ifdef APP-NVUE + this._preCheckShowNoMoreInside(totalData) + // #endif + } else { + this._preCheckShowNoMoreInside(totalData) + } + }, + //检测z-paging是否要全屏覆盖(当使用页面滚动并且不满全屏时,默认z-paging需要铺满全屏,避免数据过少时内部的empty-view无法正确展示) + async _checkScrollViewShouldFullHeight(callback) { + try { + const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view'); + const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container-content'); + if (!scrollViewNode || !pagingContainerNode) return; + const scrollViewHeight = pagingContainerNode[0].height; + const scrollViewTop = scrollViewNode[0].top; + if (this.isAddedData && scrollViewHeight + scrollViewTop <= this.windowHeight) { + this._setAutoHeight(true, scrollViewNode); + callback(scrollViewNode, pagingContainerNode); + } else { + this._setAutoHeight(false); + callback(null, null); + } + } catch (e) { + callback(null, null); + } + }, + //scrollTop改变时触发 + _scrollTopChange(newVal, isPageScrollTop){ + this.$emit('scrollTopChange', newVal); + this.$emit('update:scrollTop', newVal); + this._checkShouldShowBackToTop(newVal); + const scrollTop = this.isIos ? (newVal > 5 ? 6 : 0) : newVal; + if (isPageScrollTop) { + this.wxsPageScrollTop = scrollTop; + } else { + this.wxsScrollTop = scrollTop; + } + }, + //更新使用页面滚动时slot="top"或"bottom"插入view的高度 + _updatePageScrollTopOrBottomHeight(type) { + // #ifndef APP-NVUE + if (!this.usePageScroll) return; + // #endif + this._doCheckScrollViewShouldFullHeight(this.realTotalData); + const node = `.zp-page-${type}`; + const marginText = `margin${type.slice(0,1).toUpperCase() + type.slice(1)}`; + let safeAreaInsetBottomAdd = this.safeAreaInsetBottom; + this.$nextTick(() => { + let delayTime = 0; + // #ifdef MP-BAIDU || APP-NVUE + delayTime = 50; + // #endif + u.delay(() => { + this._getNodeClientRect(node).then((res) => { + if (res) { + let pageScrollNodeHeight = res[0].height; + if (type === 'bottom') { + if (safeAreaInsetBottomAdd) { + pageScrollNodeHeight += this.safeAreaBottom; + } + } else { + this.cacheTopHeight = pageScrollNodeHeight; + } + this.$set(this.scrollViewStyle, marginText, `${pageScrollNodeHeight}px`); + } else if (safeAreaInsetBottomAdd) { + this.$set(this.scrollViewStyle, marginText, `${this.safeAreaBottom}px`); + } + }); + }, delayTime) + }) + }, + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/modules/virtual-list.js b/src/uni_modules/z-paging/components/z-paging/js/modules/virtual-list.js new file mode 100644 index 0000000..f713e84 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/modules/virtual-list.js @@ -0,0 +1,395 @@ +// [z-paging]虚拟列表模块 +import u from '.././z-paging-utils' +import c from '.././z-paging-constant' +import Enum from '.././z-paging-enum' + +export default { + props: { + //是否使用虚拟列表,默认为否 + useVirtualList: { + type: Boolean, + default: u.gc('useVirtualList', false) + }, + //在使用虚拟列表时,是否使用兼容模式,默认为否 + useCompatibilityMode: { + type: Boolean, + default: u.gc('useCompatibilityMode', false) + }, + //使用兼容模式时传递的附加数据 + extraData: { + type: Object, + default: function() { + return u.gc('extraData', {}); + } + }, + //是否在z-paging内部循环渲染列表(内置列表),默认为否。若use-virtual-list为true,则此项恒为true + useInnerList: { + type: Boolean, + default: u.gc('useInnerList', false) + }, + //强制关闭inner-list,默认为false,如果为true将强制关闭innerList,适用于开启了虚拟列表后需要强制关闭inner-list的情况 + forceCloseInnerList: { + type: Boolean, + default: u.gc('forceCloseInnerList', false) + }, + //内置列表cell的key名称,仅nvue有效,在nvue中开启use-inner-list时必须填此项 + cellKeyName: { + type: String, + default: u.gc('cellKeyName', '') + }, + //innerList样式 + innerListStyle: { + type: Object, + default: function() { + return u.gc('innerListStyle', {}); + } + }, + //innerCell样式 + innerCellStyle: { + type: Object, + default: function() { + return u.gc('innerCellStyle', {}); + } + }, + //预加载的列表可视范围(列表高度)页数,默认为7,即预加载当前页及上下各7页的cell。此数值越大,则虚拟列表中加载的dom越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题 + preloadPage: { + type: [Number, String], + default: u.gc('preloadPage', 7), + validator: (value) => { + if (value <= 0) u.consoleErr('preload-page必须大于0!'); + return value > 0; + } + }, + //虚拟列表cell高度模式,默认为fixed,也就是每个cell高度完全相同,将以第一个cell高度为准进行计算。可选值【dynamic】,即代表高度是动态非固定的,【dynamic】性能低于【fixed】。 + cellHeightMode: { + type: String, + default: u.gc('cellHeightMode', Enum.CellHeightMode.Fixed) + }, + //虚拟列表列数,默认为1。常用于每行有多列的情况,例如每行有2列数据,需要将此值设置为2 + virtualListCol: { + type: [Number, String], + default: u.gc('virtualListCol', 1) + }, + //虚拟列表scroll取样帧率,默认为80,过低容易出现白屏问题,过高容易出现卡顿问题 + virtualScrollFps: { + type: [Number, String], + default: u.gc('virtualScrollFps', 80) + }, + }, + data() { + return { + virtualListKey: u.getInstanceId(), + virtualPageHeight: 0, + virtualCellHeight: 0, + virtualScrollTimeStamp: 0, + + virtualList: [], + virtualPlaceholderTopHeight: 0, + virtualPlaceholderBottomHeight: 0, + virtualTopRangeIndex: 0, + virtualBottomRangeIndex: 0, + lastVirtualTopRangeIndex: 0, + lastVirtualBottomRangeIndex: 0, + + virtualHeightCacheList: [], + + getCellHeightRetryCount: { + fixed: 0, + dynamic: 0 + }, + pagingOrgTop: -1, + updateVirtualListFromDataChange: false + } + }, + watch: { + realTotalData(newVal) { + // #ifndef APP-NVUE + if (this.finalUseVirtualList) { + this.updateVirtualListFromDataChange = true; + this.$nextTick(() => { + this.getCellHeightRetryCount.fixed = 0; + !newVal.length && this._resetDynamicListState(!this.isUserPullDown); + newVal.length && this.cellHeightMode === Enum.CellHeightMode.Fixed && this.isFirstPage && this._updateFixedCellHeight(); + this._updateVirtualScroll(this.oldScrollTop); + }) + } + // #endif + }, + virtualList(newVal){ + this.$emit('update:virtualList', newVal); + this.$emit('virtualListChange', newVal); + } + }, + computed: { + finalUseVirtualList() { + if (this.useVirtualList && this.usePageScroll){ + u.consoleErr('使用页面滚动时,开启虚拟列表无效!'); + } + return this.useVirtualList && !this.usePageScroll; + }, + finalUseInnerList() { + return this.useInnerList || (this.finalUseVirtualList && !this.forceCloseInnerList); + }, + finalCellKeyName() { + // #ifdef APP-NVUE + if (this.finalUseVirtualList && !this.cellKeyName.length){ + u.consoleErr('在nvue中开启use-virtual-list必须设置cell-key-name,否则将可能导致列表渲染错误!'); + } + // #endif + return this.cellKeyName; + }, + finalVirtualPageHeight(){ + return this.virtualPageHeight > 0 ? this.virtualPageHeight : this.windowHeight; + }, + virtualRangePageHeight(){ + return this.finalVirtualPageHeight * this.preloadPage; + }, + virtualScrollDisTimeStamp() { + return 1000 / this.virtualScrollFps; + }, + }, + methods: { + //在使用动态高度虚拟列表时,手动更新指定cell的缓存高度(当cell高度在初始化之后再次改变时调用),index代表需要更新的cell在列表中的位置,从0开始 + didUpdateVirtualListCell(index) { + if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return; + const currentNode = this.virtualHeightCacheList[index]; + this._getNodeClientRect(`#zp-id-${index}`, this.finalUseInnerList).then(cellNode => { + const cellNodeHeight = cellNode ? cellNode[0].height : 0; + + const heightDis = cellNodeHeight - currentNode.height; + currentNode.height = cellNodeHeight; + currentNode.totalHeight = currentNode.lastHeight + cellNodeHeight; + + for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) { + const thisNode = this.virtualHeightCacheList[i]; + if (i === index + 1) { + thisNode.lastHeight = cellNodeHeight; + } + thisNode.totalHeight += heightDis; + } + }); + }, + //在使用动态高度虚拟列表时,若删除了列表数组中的某个item,需要调用此方法以更新高度缓存数组,index代表需要更新的cell在列表中的位置,从0开始 + didDeleteVirtualListCell(index) { + if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return; + const currentNode = this.virtualHeightCacheList[index]; + for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) { + const thisNode = this.virtualHeightCacheList[i]; + if (i === index + 1) { + thisNode.lastHeight = currentNode.lastHeight; + } + thisNode.totalHeight -= currentNode.height; + } + this.virtualHeightCacheList.splice(index, 1); + }, + //初始化虚拟列表 + _virtualListInit() { + this.$nextTick(() => { + u.delay(() => { + this._getNodeClientRect('.zp-scroll-view').then(node => { + if (node) { + this.pagingOrgTop = node[0].top; + this.virtualPageHeight = node[0].height; + } + }); + }); + }) + }, + //cellHeightMode为fixed时获取第一个cell高度 + _updateFixedCellHeight() { + this.$nextTick(() => { + u.delay(() => { + this._getNodeClientRect(`#zp-id-${0}`,this.finalUseInnerList).then(cellNode => { + if (!cellNode) { + if (this.getCellHeightRetryCount.fixed > 10) return; + this.getCellHeightRetryCount.fixed ++; + this._updateFixedCellHeight(); + } else { + this.virtualCellHeight = cellNode[0].height; + this._updateVirtualScroll(this.oldScrollTop); + } + }); + }, c.delayTime, 'updateFixedCellHeightDelay'); + }) + }, + //cellHeightMode为dynamic时获取每个cell高度 + _updateDynamicCellHeight(list) { + this.$nextTick(() => { + u.delay(async () => { + for (let i = 0; i < list.length; i++) { + let item = list[i]; + const cellNode = await this._getNodeClientRect(`#zp-id-${item[c.listCellIndexKey]}`, this.finalUseInnerList); + const currentHeight = cellNode ? cellNode[0].height : 0; + if (!cellNode) { + this.virtualHeightCacheList = this.virtualHeightCacheList.slice(-i); + if (this.getCellHeightRetryCount.dynamic > 10) return; + this.getCellHeightRetryCount.dynamic ++; + this._updateDynamicCellHeight(list); + break; + } + const lastHeightCache = this.virtualHeightCacheList.length ? this.virtualHeightCacheList.slice(-1)[0] : null; + const lastHeight = lastHeightCache ? lastHeightCache.totalHeight : 0; + this.virtualHeightCacheList.push({ + height: currentHeight, + lastHeight, + totalHeight: lastHeight + currentHeight + }); + } + this._updateVirtualScroll(this.oldScrollTop); + }, c.delayTime, 'updateDynamicCellHeightDelay') + }) + }, + //设置cellItem的index + _setCellIndex(list, isFirstPage) { + let lastItemIndex = 0; + if (!isFirstPage) { + lastItemIndex = this.realTotalData.length; + const lastItem = this.realTotalData.length ? this.realTotalData.slice(-1)[0] : null; + if (lastItem && lastItem[c.listCellIndexKey] !== undefined) { + lastItemIndex = lastItem[c.listCellIndexKey] + 1; + } + } else { + this._resetDynamicListState(); + } + for (let i = 0; i < list.length; i++) { + let item = list[i]; + if (!item || Object.prototype.toString.call(item) !== '[object Object]') { + item = { item }; + } + item[c.listCellIndexKey] = lastItemIndex + i; + item[c.listCellIndexUniqueKey] = `${this.virtualListKey}-${item[c.listCellIndexKey]}`; + list[i] = item; + } + this.getCellHeightRetryCount.dynamic = 0; + this.cellHeightMode === Enum.CellHeightMode.Dynamic && this._updateDynamicCellHeight(list); + }, + //更新scroll滚动 + _updateVirtualScroll(scrollTop, scrollDiff = 0) { + const currentTimeStamp = u.getTime(); + scrollTop === 0 && this._resetTopRange(); + if (scrollTop !== 0 && this.virtualScrollTimeStamp && currentTimeStamp - this.virtualScrollTimeStamp <= this.virtualScrollDisTimeStamp) { + return; + } + this.virtualScrollTimeStamp = currentTimeStamp; + + let scrollIndex = 0; + const cellHeightMode = this.cellHeightMode; + if (cellHeightMode === Enum.CellHeightMode.Fixed) { + scrollIndex = parseInt(scrollTop / this.virtualCellHeight) || 0; + this._updateFixedTopRangeIndex(scrollIndex); + this._updateFixedBottomRangeIndex(scrollIndex); + } else if(cellHeightMode === Enum.CellHeightMode.Dynamic) { + const scrollDirection = scrollDiff > 0 ? 'top' : 'bottom'; + const rangePageHeight = this.virtualRangePageHeight; + const topRangePageOffset = scrollTop - rangePageHeight; + const bottomRangePageOffset = scrollTop + this.finalVirtualPageHeight + rangePageHeight; + + let virtualBottomRangeIndex = 0; + let virtualPlaceholderBottomHeight = 0; + let reachedLimitBottom = false; + const heightCacheList = this.virtualHeightCacheList; + const lastHeightCache = !!heightCacheList ? heightCacheList.slice(-1)[0] : null; + + let startTopRangeIndex = this.virtualTopRangeIndex; + if (scrollDirection === 'bottom') { + for (let i = startTopRangeIndex; i < heightCacheList.length; i++){ + const heightCacheItem = heightCacheList[i]; + if (heightCacheItem && heightCacheItem.totalHeight > topRangePageOffset) { + this.virtualTopRangeIndex = i; + this.virtualPlaceholderTopHeight = heightCacheItem.lastHeight; + break; + } + } + } else { + let topRangeMatched = false; + for (let i = startTopRangeIndex; i >= 0; i--){ + const heightCacheItem = heightCacheList[i]; + if (heightCacheItem && heightCacheItem.totalHeight < topRangePageOffset) { + this.virtualTopRangeIndex = i; + this.virtualPlaceholderTopHeight = heightCacheItem.lastHeight; + topRangeMatched = true; + break; + } + } + !topRangeMatched && this._resetTopRange(); + } + for (let i = this.virtualTopRangeIndex; i < heightCacheList.length; i++){ + const heightCacheItem = heightCacheList[i]; + if (heightCacheItem && heightCacheItem.totalHeight > bottomRangePageOffset) { + virtualBottomRangeIndex = i; + virtualPlaceholderBottomHeight = lastHeightCache.totalHeight - heightCacheItem.totalHeight; + reachedLimitBottom = true; + break; + } + } + if (!reachedLimitBottom || this.virtualBottomRangeIndex === 0) { + this.virtualBottomRangeIndex = this.realTotalData.length ? this.realTotalData.length - 1 : this.pageSize; + this.virtualPlaceholderBottomHeight = 0; + } else { + this.virtualBottomRangeIndex = virtualBottomRangeIndex; + this.virtualPlaceholderBottomHeight = virtualPlaceholderBottomHeight; + } + this._updateVirtualList(); + } + }, + //更新fixedCell模式下topRangeIndex&placeholderTopHeight + _updateFixedTopRangeIndex(scrollIndex) { + let virtualTopRangeIndex = this.virtualCellHeight === 0 ? 0 : scrollIndex - parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) * this.preloadPage; + virtualTopRangeIndex *= this.virtualListCol; + virtualTopRangeIndex = Math.max(0, virtualTopRangeIndex); + this.virtualTopRangeIndex = virtualTopRangeIndex; + this.virtualPlaceholderTopHeight = (virtualTopRangeIndex / this.virtualListCol) * this.virtualCellHeight; + }, + //更新fixedCell模式下bottomRangeIndex&placeholderBottomHeight + _updateFixedBottomRangeIndex(scrollIndex) { + let virtualBottomRangeIndex = this.virtualCellHeight === 0 ? this.pageSize : scrollIndex + parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) * (this.preloadPage + 1); + virtualBottomRangeIndex *= this.virtualListCol; + virtualBottomRangeIndex = Math.min(this.realTotalData.length, virtualBottomRangeIndex); + this.virtualBottomRangeIndex = virtualBottomRangeIndex; + this.virtualPlaceholderBottomHeight = (this.realTotalData.length - virtualBottomRangeIndex) * this.virtualCellHeight / this.virtualListCol; + this._updateVirtualList(); + }, + //更新virtualList + _updateVirtualList() { + const shouldUpdateList = this.updateVirtualListFromDataChange || (this.lastVirtualTopRangeIndex !== this.virtualTopRangeIndex || this.lastVirtualBottomRangeIndex !== this.virtualBottomRangeIndex); + if (shouldUpdateList) { + this.updateVirtualListFromDataChange = false; + this.lastVirtualTopRangeIndex = this.virtualTopRangeIndex; + this.lastVirtualBottomRangeIndex = this.virtualBottomRangeIndex; + this.virtualList = this.realTotalData.slice(this.virtualTopRangeIndex, this.virtualBottomRangeIndex + 1); + } + }, + //重置动态cell模式下的高度缓存数据、虚拟列表和滚动状态 + _resetDynamicListState(resetVirtualList = false) { + this.virtualHeightCacheList = []; + if (resetVirtualList) { + this.virtualList = []; + } + this.virtualTopRangeIndex = 0; + this.virtualPlaceholderTopHeight = 0; + }, + //重置topRangeIndex和placeholderTopHeight + _resetTopRange() { + this.virtualTopRangeIndex = 0; + this.virtualPlaceholderTopHeight = 0; + this._updateVirtualList(); + }, + //检测虚拟列表当前滚动位置,如发现滚动位置不正确则重新计算虚拟列表相关参数(为解决在App中可能出现的长时间进入后台后打开App白屏的问题) + _checkVirtualListScroll() { + if (this.finalUseVirtualList) { + this.$nextTick(() => { + this._getNodeClientRect('.zp-paging-touch-view').then(node => { + const currentTop = node ? node[0].top : 0; + if (!node || (currentTop === this.pagingOrgTop && this.virtualPlaceholderTopHeight !== 0)) { + this._updateVirtualScroll(0); + } + }); + }) + } + }, + //处理使用内置列表时点击了cell事件 + _innerCellClick(item, index) { + this.$emit('innerCellClick', item, index); + } + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-config.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-config.js new file mode 100644 index 0000000..c7b714e --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-config.js @@ -0,0 +1,21 @@ +// [z-paging]处理main.js中的配置信息工具 + +let config = null; +let getedStorage = false; +const storageKey = 'Z-PAGING-CONFIG-STORAGE-KEY' + +function setConfig(value) { + uni.setStorageSync(storageKey, value); +} + +function getConfig() { + if (getedStorage) return config; + config = uni.getStorageSync(storageKey); + getedStorage = true; + return config; +} + +export default { + setConfig, + getConfig +}; diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-constant.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-constant.js new file mode 100644 index 0000000..587c7fb --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-constant.js @@ -0,0 +1,12 @@ +// [z-paging]常量 + +export default { + version: '2.5.7', + delayTime: 100, + errorUpdateKey: 'z-paging-error-emit', + completeUpdateKey: 'z-paging-complete-emit', + cachePrefixKey: 'z-paging-cache', + + listCellIndexKey: 'zp_index', + listCellIndexUniqueKey: 'zp_unique_index' +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-enum.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-enum.js new file mode 100644 index 0000000..17ad63a --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-enum.js @@ -0,0 +1,44 @@ +// [z-paging]枚举 + +export default { + //当前加载类型 0.下拉刷新 1.上拉加载更多 + LoadingType: { + Refresher: 0, + LoadingMore: 1 + }, + //下拉刷新状态 0.默认状态 1.松手立即刷新 2.刷新中 3.刷新结束 + Refresher: { + Default: 0, + ReleaseToRefresh: 1, + Loading: 2, + Complete: 3 + }, + //底部加载更多状态 0.默认状态 1.加载中 2.没有更多数据 3.加载失败 + More: { + Default: 0, + Loading: 1, + NoMore: 2, + Fail: 3 + }, + //@query触发来源 0.用户主动下拉刷新 1.通过reload触发 2.通过refresh触发 3.通过滚动到底部加载更多或点击底部加载更多触发 + QueryFrom: { + UserPullDown: 0, + Reload: 1, + Refresh: 2, + LoadingMore: 3 + }, + //虚拟列表cell高度模式 + CellHeightMode: { + //固定高度 + Fixed: 'fixed', + //动态高度 + Dynamic: 'dynamic' + }, + //列表缓存模式 + CacheMode: { + //默认模式,只会缓存一次 + Default: 'default', + //总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存 + Always: 'always' + } +} \ No newline at end of file diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-interceptor.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-interceptor.js new file mode 100644 index 0000000..d0e9b2b --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-interceptor.js @@ -0,0 +1,48 @@ +// [z-paging]拦截器 + +//拦截&处理@query事件 +function handleQuery(callback) { + try { + setTimeout(function() { + _getApp().globalData.zp_handleQueryCallback = callback; + }, 1); + } catch (e) {} +} + +//拦截&处理@query事件(私有,请勿调用) +function _handleQuery(pageNo, pageSize, from, lastItem){ + const callback = _getApp().globalData.zp_handleQueryCallback; + return callback ? callback(pageNo, pageSize, from, lastItem) : [pageNo, pageSize, from]; +} + +//拦截&处理系统language转i18n local +function handleLanguage2Local(callback) { + try { + setTimeout(function() { + _getApp().globalData.zp_handleLanguage2LocalCallback = callback; + }, 1); + } catch (e) {} +} + +//拦截&处理系统language转i18n local(私有,请勿调用) +function _handleLanguage2Local(language, local){ + const callback = _getApp().globalData.zp_handleLanguage2LocalCallback; + return callback ? callback(language, local) : local; +} + +//获取当前app对象 +function _getApp(){ + // #ifndef APP-NVUE + return getApp(); + // #endif + // #ifdef APP-NVUE + return getApp({ allowDefault: true }); + // #endif +} + +export default { + handleQuery, + _handleQuery, + handleLanguage2Local, + _handleLanguage2Local +}; diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-main.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-main.js new file mode 100644 index 0000000..44e43b7 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-main.js @@ -0,0 +1,423 @@ +// [z-paging]核心js + +import zStatic from './z-paging-static' +import c from './z-paging-constant' +import u from './z-paging-utils' + +import zPagingRefresh from '../components/z-paging-refresh' +import zPagingLoadMore from '../components/z-paging-load-more' +import zPagingEmptyView from '../../z-paging-empty-view/z-paging-empty-view' + +// modules +import commonLayoutModule from './modules/common-layout' +import dataHandleModule from './modules/data-handle' +import i18nModule from './modules/i18n' +import nvueModule from './modules/nvue' +import emptyModule from './modules/empty' +import refresherModule from './modules/refresher' +import loadMoreModule from './modules/load-more' +import loadingModule from './modules/loading' +import scrollerModule from './modules/scroller' +import backToTopModule from './modules/back-to-top' +import virtualListModule from './modules/virtual-list' + +import Enum from './z-paging-enum' + +const systemInfo = uni.getSystemInfoSync(); + +export default { + name: "z-paging", + components: { + zPagingRefresh, + zPagingLoadMore, + zPagingEmptyView + }, + mixins: [ + commonLayoutModule, + dataHandleModule, + i18nModule, + nvueModule, + emptyModule, + refresherModule, + loadMoreModule, + loadingModule, + scrollerModule, + backToTopModule, + virtualListModule + ], + data() { + return { + //--------------静态资源--------------- + base64Arrow: zStatic.base64Arrow, + base64Flower: zStatic.base64Flower, + base64BackToTop: zStatic.base64BackToTop, + + //-------------全局数据相关-------------- + //当前加载类型 + loadingType: Enum.LoadingType.Refresher, + requestTimeStamp: 0, + chatRecordLoadingMoreText: '', + wxsPropType: '', + renderPropScrollTop: -1, + checkScrolledToBottomTimeOut: null, + cacheTopHeight: -1, + + //--------------状态&判断--------------- + insideOfPaging: -1, + isLoadFailed: false, + isIos: systemInfo.platform === 'ios', + disabledBounce: false, + fromCompleteEmit: false, + disabledCompleteEmit: false, + + //---------------wxs相关--------------- + wxsIsScrollTopInTopRange: true, + wxsScrollTop: 0, + wxsPageScrollTop: 0, + wxsOnPullingDown: false, + }; + }, + props: { + //调用complete后延迟处理的时间,单位为毫秒,默认0毫秒,优先级高于minDelay + delay: { + type: [Number, String], + default: u.gc('delay', 0), + }, + //触发@query后最小延迟处理的时间,单位为毫秒,默认0毫秒,优先级低于delay(假设设置为300毫秒,若分页请求时间小于300毫秒,则在调用complete后延迟[300毫秒-请求时长];若请求时长大于300毫秒,则不延迟),当show-refresher-when-reload为true或reload(true)时,其最小值为400 + minDelay: { + type: [Number, String], + default: u.gc('minDelay', 0), + }, + //设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替 + pagingStyle: { + type: Object, + default: function() { + return u.gc('pagingStyle', {}); + }, + }, + //z-paging的高度,优先级低于pagingStyle中设置的height;传字符串,如100px、100rpx、100% + height: { + type: String, + default: u.gc('height', '') + }, + //z-paging的宽度,优先级低于pagingStyle中设置的width;传字符串,如100px、100rpx、100% + width: { + type: String, + default: u.gc('width', '') + }, + //z-paging的背景色,优先级低于pagingStyle中设置的background。传字符串,如"#ffffff" + bgColor: { + type: String, + default: u.gc('bgColor', '') + }, + //设置z-paging的容器(插槽的父view)的style + pagingContentStyle: { + type: Object, + default: function() { + return u.gc('pagingContentStyle', {}); + }, + }, + //z-paging是否自动高度,若自动高度则会自动铺满屏幕 + autoHeight: { + type: Boolean, + default: u.gc('autoHeight', false) + }, + //z-paging是否自动高度时,附加的高度,注意添加单位px或rpx,若需要减少高度,则传负数 + autoHeightAddition: { + type: [Number, String], + default: u.gc('autoHeightAddition', '0px') + }, + //loading(下拉刷新、上拉加载更多)的主题样式,支持black,white,默认black + defaultThemeStyle: { + type: String, + default: u.gc('defaultThemeStyle', 'black') + }, + //z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认为100%,默认为是(当使用内置scroll-view滚动时有效) + fixed: { + type: Boolean, + default: u.gc('fixed', true) + }, + //是否开启底部安全区域适配 + safeAreaInsetBottom: { + type: Boolean, + default: u.gc('safeAreaInsetBottom', false) + }, + //开启底部安全区域适配后,是否使用placeholder形式实现,默认为否。为否时滚动区域会自动避开底部安全区域,也就是所有滚动内容都不会挡住底部安全区域,若设置为是,则滚动时滚动内容会挡住底部安全区域,但是当滚动到底部时才会避开底部安全区域 + useSafeAreaPlaceholder: { + type: Boolean, + default: u.gc('useSafeAreaPlaceholder', false) + }, + //slot="top"的view的z-index,默认为99,仅使用页面滚动时有效 + topZIndex: { + type: Number, + default: u.gc('topZIndex', 99) + }, + //z-paging内容容器父view的z-index,默认为1 + superContentZIndex: { + type: Number, + default: u.gc('superContentZIndex', 1) + }, + //z-paging内容容器部分的z-index,默认为10 + contentZIndex: { + type: Number, + default: u.gc('contentZIndex', 10) + }, + //使用页面滚动时,是否在不满屏时自动填充满屏幕,默认为是 + autoFullHeight: { + type: Boolean, + default: u.gc('autoFullHeight', true) + }, + //是否监听列表触摸方向改变,默认为否 + watchTouchDirectionChange: { + type: Boolean, + default: u.gc('watchTouchDirectionChange', false) + }, + }, + created(){ + if (this.createdReload && !this.refresherOnly && this.auto) { + this._startLoading(); + this._preReload(); + } + }, + mounted() { + this.wxsPropType = u.getTime().toString(); + this.renderJsIgnore; + if (!this.createdReload && !this.refresherOnly && this.auto) { + this.$nextTick(this._preReload); + } + this.finalUseCache && this._setListByLocalCache(); + let delay = 0; + // #ifdef H5 || MP + delay = 100; + // #endif + this.$nextTick(() => { + this.systemInfo = uni.getSystemInfoSync(); + !this.usePageScroll && this.autoHeight && this._setAutoHeight(); + this.loaded = true; + }) + this.updatePageScrollTopHeight(); + this.updatePageScrollBottomHeight(); + this.updateLeftAndRightWidth(); + if (this.finalRefresherEnabled && this.useCustomRefresher) { + this.$nextTick(() => { + this.isTouchmoving = true; + }) + } + this._onEmit(); + // #ifdef APP-NVUE + if (!this.isIos && !this.useChatRecordMode) { + this.nLoadingMoreFixedHeight = true; + } + this._nUpdateRefresherWidth(); + // #endif + // #ifndef APP-NVUE + this.finalUseVirtualList && this._virtualListInit(); + // #endif + // #ifndef APP-PLUS + this.$nextTick(() => { + setTimeout(() => { + this._getCssSafeAreaInsetBottom(() => this.safeAreaInsetBottom && this.updatePageScrollBottomHeight()); + }, delay) + }) + // #endif + }, + destroyed() { + this._offEmit(); + }, + // #ifdef VUE3 + unmounted() { + this._offEmit(); + }, + // #endif + watch: { + defaultThemeStyle: { + handler(newVal) { + if (newVal.length) { + this.finalRefresherDefaultStyle = newVal; + } + }, + immediate: true + }, + autoHeight(newVal) { + this.loaded && !this.usePageScroll && this._setAutoHeight(newVal); + }, + autoHeightAddition(newVal) { + this.loaded && !this.usePageScroll && this.autoHeight && this._setAutoHeight(newVal); + }, + }, + computed: { + finalPagingStyle() { + const pagingStyle = this.pagingStyle; + if (!this.systemInfo) return pagingStyle; + const { windowTop, windowBottom } = this; + if (!this.usePageScroll && this.fixed) { + if (windowTop && !pagingStyle.top) { + pagingStyle.top = windowTop + 'px'; + } + if (windowBottom && !pagingStyle.bottom) { + pagingStyle.bottom = windowBottom + 'px'; + } + } + if (this.bgColor.length && !pagingStyle['background']) { + pagingStyle['background'] = this.bgColor; + } + if (this.height.length && !pagingStyle['height']) { + pagingStyle['height'] = this.height; + } + if (this.width.length && !pagingStyle['width']) { + pagingStyle['width'] = this.width; + } + return pagingStyle; + }, + finalLowerThreshold() { + return u.convertToPx(this.lowerThreshold); + }, + finalPagingContentStyle() { + if (this.contentZIndex != 1) { + this.pagingContentStyle['z-index'] = this.contentZIndex; + this.pagingContentStyle['position'] = 'relative'; + } + return this.pagingContentStyle; + }, + renderJsIgnore() { + if ((this.usePageScroll && this.useChatRecordMode) || !this.refresherEnabled || !this.useCustomRefresher) { + this.$nextTick(() => { + this.renderPropScrollTop = 10; + }) + } + return 0; + }, + windowHeight() { + if (!this.systemInfo) return 0; + return this.systemInfo.windowHeight || 0; + }, + windowBottom() { + if (!this.systemInfo) return 0; + let windowBottom = this.systemInfo.windowBottom || 0; + if (this.safeAreaInsetBottom && !this.useSafeAreaPlaceholder) { + windowBottom += this.safeAreaBottom; + } + return windowBottom; + }, + isIosAndH5() { + // #ifndef H5 + return false; + // #endif + return this.isIos; + } + }, + methods: { + //当前版本号 + getVersion() { + return `z-paging v${c.version}`; + }, + //设置nvue List的specialEffects + setSpecialEffects(args) { + this.setListSpecialEffects(args); + }, + //与setSpecialEffects等效,兼容旧版本 + setListSpecialEffects(args) { + this.nFixFreezing = args && Object.keys(args).length; + if (this.isIos) { + this.privateRefresherEnabled = 0; + } + !this.usePageScroll && this.$refs['zp-n-list'].setSpecialEffects(args); + }, + //使手机发生较短时间的振动(15ms) + _doVibrateShort() { + // #ifdef APP-PLUS + if (this.isIos) { + const UISelectionFeedbackGenerator = plus.ios.importClass('UISelectionFeedbackGenerator'); + const feedbackGenerator = new UISelectionFeedbackGenerator(); + feedbackGenerator.init(); + setTimeout(() => { + feedbackGenerator.selectionChanged(); + }, 0) + } else { + plus.device.vibrate(15); + } + // #endif + // #ifndef APP-PLUS + uni.vibrateShort(); + // #endif + }, + //设置z-paging高度 + async _setAutoHeight(shouldFullHeight = true, scrollViewNode = null) { + let heightKey = 'min-height'; + // #ifndef APP-NVUE + heightKey = 'min-height'; + // #endif + try { + if (shouldFullHeight) { + let finalScrollViewNode = scrollViewNode || await this._getNodeClientRect('.zp-scroll-view'); + let finalScrollBottomNode = await this._getNodeClientRect('.zp-page-bottom'); + if (finalScrollViewNode) { + const scrollViewTop = finalScrollViewNode[0].top; + let scrollViewHeight = this.windowHeight - scrollViewTop; + scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0; + const additionHeight = u.convertToPx(this.autoHeightAddition); + const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px !important'; + this.$set(this.scrollViewStyle, heightKey, finalHeight); + this.$set(this.scrollViewInStyle, heightKey, finalHeight); + } + } else { + this.$delete(this.scrollViewStyle, heightKey); + this.$delete(this.scrollViewInStyle, heightKey); + } + } catch (e) {} + }, + //触发更新是否超出页面状态 + _updateInsideOfPaging() { + this.insideMore && this.insideOfPaging === true && setTimeout(this.doLoadMore, 200) + }, + //清除timeout + _cleanTimeout(timeout) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + return timeout; + }, + //添加全局emit监听 + _onEmit() { + uni.$on(c.errorUpdateKey, () => { + this.loading && this.complete(false); + }) + uni.$on(c.completeUpdateKey, (data) => { + setTimeout(() => { + if (this.loading) { + if (!this.disabledCompleteEmit) { + const type = data.type || 'normal'; + const list = data.list || data; + const rule = data.rule; + this.fromCompleteEmit = true; + switch (type){ + case 'normal': + this.complete(list); + break; + case 'total': + this.completeByTotal(list, rule); + break; + case 'nomore': + this.completeByNoMore(list, rule); + break; + case 'key': + this.completeByKey(list, rule); + break; + default: + break; + } + } else { + this.disabledCompleteEmit = false; + } + } + }, 1); + }) + }, + //销毁全局emit和listener监听 + _offEmit(){ + uni.$off(c.errorUpdateKey); + uni.$off(c.completeUpdateKey); + } + }, +}; diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-mixin.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-mixin.js new file mode 100644 index 0000000..da720f4 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-mixin.js @@ -0,0 +1,22 @@ +// [z-paging]使用页面滚动时引入此mixin,用于监听和处理onPullDownRefresh等页面生命周期方法 + +export default { + onPullDownRefresh() { + if (this.isPagingRefNotFound()) return; + this.$refs.paging.reload(); + }, + onPageScroll(e) { + if (this.isPagingRefNotFound()) return; + this.$refs.paging.updatePageScrollTop(e.scrollTop); + e.scrollTop < 10 && this.$refs.paging.doChatRecordLoadMore(); + }, + onReachBottom() { + if (this.isPagingRefNotFound()) return; + this.$refs.paging.pageReachBottom(); + }, + methods: { + isPagingRefNotFound() { + return !this.$refs.paging; + } + } +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-static.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-static.js new file mode 100644 index 0000000..05f80d5 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-static.js @@ -0,0 +1,13 @@ +// [z-paging]公用的静态图片资源 + +export default { + base64Arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAD1BMVEVHcExRUVFMTExRUVFRUVE9CdWsAAAABHRSTlMAjjrY9ZnUjwAAAQFJREFUWMPt2MsNgzAMgGEEE1B1gKJmAIRYoCH7z9RCXrabh33iYktcIv35EEg5ZBh07pvxJU6MFSPOSRnjnBUjUsaciRUjMsb4xIoRCWNiYsUInzE5sWKEyxiYWDbyefqHx1zIeiYTk7mQYziTYecxHvEJjwmIT3hMQELCYSISEg4TkZj0mYTEpM8kJCU9JiMp6TEZyUmbAUhO2gxAQNJiIAKSFgMRmNQZhMCkziAEJTUGIyipMRjBSZkhCE7KDEFIUmTeGCHJxWz0zXaE0GTCG8ZFtEaS347r/1fe11YyHYVfubxayfjoHmc0YYwmmmiiiSaaaKLJ7ckyz5ve+dw3Xw2emdwm9xSbAAAAAElFTkSuQmCC', + base64ArrowWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVHcEz///////////////////+IGTx/AAAABnRSTlMA/dAkXZOhASU/AAABYElEQVRYw+2YwXLCIBCGsdAHWGbyAKZ4zxi9O017rxLf/1UaWFAgA1m8dcpedNSPf/l/Vh0Ya/Wn6hN0JcGvoCqRM4C8VBFiDwBqqNuJKV0rAnCgy3AUqZE57x0iqTL8Br4U3WBf/YWaIlTKfAcELU/h9w72CSVPa3C3OCDvhpHbRp/s2vq4fHhCeiCl2A3m4Qd71DQR257mFBlMcTlbFnFWzNtHxewYEfSiaLS4el8d8nyhmKJd1CF4eOS0keLMAuSxubLBIeIGQW8YHCFFo7EH9+YDcQt9FMZEswTheaNxTHwHT8SZorJjMrEVwo4Zo0U8HSEyZvJMOg4RjnmmRr8nDYeIz3OMkbfE/QhBo+U9RnZJxjGCRh/WKmHEMWLNkfPKsGh/CWJk1JjG0kcuJggTt34VDP8aWAFhp4nybVb5+9qQhjSkIQ1pSEMa8k+Q5U9rV3dF8MpFBK+/7miVq1/HZ2qmo9D+pAAAAABJRU5ErkJggg==', + base64Flower: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAKlBMVEVHcEzDw8Ovr6+pqamUlJTCwsKenp61tbWxsbGysrLNzc2bm5u5ubmjo6MpovhuAAAACnRSTlMA/P79/sHDhiZS0DxZowAABBBJREFUWMPtl89rE0EUx7ctTXatB3MI1SWnDbUKPUgXqh4ED8Uf7KUVSm3ooVSpSii0Fn/gD4j4o+APiEoVmos9FO2celiqZVgwgaKHPQiCCkv+F99kM7Ozm5kxq1dfD91k9pPve9/3ZjbRNHHok/mKli4eIPNgSuRObuN9SqSEzM20iGnm0yIbqCuV7NSSSIV7uyPM6JMBYdeTOanh/QihJYZsUCSby+VkMj2AvOt0rAeQAwqE3lfKMZVlQCZk1QOCKkkVPadITCfIRNKxfoJI5+0OIFtJx14CMSg1mRSDko7VAfksRQzEbGYqxOJcVTWMCH2I1/IACNW0PWU2M8cmAVHtnH5mM1VRWtwKZjOd5JbF6s1IbaYqaotjNlPHgDAnlAizubTR6ovMYn052g/U5qcmOpi0WL8xTS/3IfSet5m8MEr5ajjF5le6dq/OJpobrdY0t3i9QgefWrxW9/1BLhk0E9m8FeUMhhXal499iD0eQRfDF+ts/tttORRerfp+oV7f4xJj82iUYm1Yzod+ZQEAlS/8mMBwKebVmCVp1f0JLS6zKd17+iwRKTARVg2SHtz3iEbBH+Q+U28zW2Jiza8Tjb1YFoYZMsJyjDqp3M9XBQdSdPLFdxEpvOB37JrHcmR/y9+LgoTlCFGZEa2sc6d4PGlweEa2JSVPoVm+IfGG3ZL037iV9oH+P+Jxc4HGVflNq1M0pivao/EopO4b/ojVCP9GjmiXOeS0DOn1o/iiccT4ORnyvBGF3yUywkQajW4Ti0SGuiy/wVSg/L8w+X/8Q+hvUx8Xd90z4oV5a1i88MbFWHz0WZZ1UrTwBGPX3Rat9AFiXRMRjoMdIdJLEOt2h7jrYOzgOamKZSWSNspOS0X8SAqRYmxRL7sg4eLzYmNehcxh3uoyud/BH2Udux4ywxFTc1xC7Mgf4vMhc5S+kSH3Y7yj+qpwIWSoPTVCOOPVthGx9FbGqrwFw6wSFxJr+17zeKcztt3u+2roAEVgUjDd+AHGuxHy2rZHaa8JMkTHEeyi85ANPO9j9BVuBRD2FY5LDMo/Sz/2hReqGIs/KiFin+CsPsYO/yvM3jL2vE8EbX7/Bf8ejtr2GLN65bioAdgLd8Bis/mD5GmP2qeqyo2ZwQEOtAjRIDH7mBKpUcMoApbZJ5UIxkEwxyMZyMxW/uKFvHCFR3SSmerHyDNQ2dF4JG6zIMpBgLfjSF9x1D6smFcYnGApjmSLICO3ecCDWrQ48geba9DI3STy2i7ax6WIB62fSyIZIiO3GFQqSURp8wCo7GhJBGwuSovJBNjb7kT6FPVnIa9qJ2Ko+l9mefGIdinaMp0yC1URYiwsdfNE45EuA5Cx9EhalfvN5s+UyItm81vaB3p4joniN+SCP7Qc1hblAAAAAElFTkSuQmCC', + base64FlowerWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEX///9HcEz///////////////84chYNAAAABnRSTlP/AGzCOYZj5g1nAAACfklEQVRYw+2YTVPDIBCGtza9Jw25a0bvcax30o73OOr//yvma2F3YWlpPTijXNpAHrK8LLALVPFium2vNIFSbwGKTGQA2GUiHcD29yDNy3sMIdUBQl7r2H8mOEVqAHgPkYZUS6Qc2zYhQqtjyDZEximCZwWZLIBeIgYShs2NzxKpSUehYpMJhURGb+O+w5BpMCAREKPnCDHbIY20SzhM5yxziAXpOiBXydrekT9i5XDEq4NIIHHgyU5mRGqviII4mREJJA4QJzMiILwlRJzpKxJKvCBm8OsBBbLux0tsPl4RKYm5aPu6jw1U4mGxEUR9g8M1PcqBEp/WJliNgYOXueBzS4jZSIcgY5lCtevgDSgyzE+rAfuOTQMq0yzvoGH18qju27Mayzs4fPyMziCx81NJa5RNfW7vPYK9KOfDiVkBxFHG8hAj9txuoBuSWORsFfkpBf7xKFLSeaOefEojh5jz22DJEqMP8fUyaKdQx+RnG+yXMpe8Aars8ueR1pVH/bW3FyyvPRw90upLDHwpgBDtg4aUBNkxRLXMAi03IhcZtr1m+FeI/O/JNyDmmL1djLOauSlNflBpW18RQ2bPqXI22MXXEk75KRHTnkPkYbESbdKP2ZFk0r5sIwffAjy1lx+vx7NLjB6/E7Jfv5ERKhzpN0w8IDE8IGFDv5dhz10s7GFiXRZcUeLCEG5P5nDq9k4PFDcoMpE3GY4OuxuCXhmuyNB6k0RsLIAvqp9NE5r8ZCSS8gxnUp7ODdYhZTqxuiJ9uyJJtPmpqJ7wVj+XVieS903iViHziqAhchLEJAyb7jWU647EpUofQ0ziUuXXXhDddtlllSwjgSQu7r4BRWhQqfDPMVwAAAAASUVORK5CYII=', + base64Success: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVRUVFHcExTU1NRUVFRUVFRUVFOSlSUAAAABnRSTlP/AI6+VySB3ZENAAACcElEQVRYw+2YyYKCMAyGI8hdpdxdZu7gcpdZ7jL6/s8yYheSNi0aPdqbwOffpGmaFOYPD3gj4bisN7vddv17N/JVgxn5x12IWgIaWTuO/IE3PseQbwjGPo2cgRmHFLJwdm/X643zwiqOKPPJ1nj3sjEP2iiifZWj5bhopSyGaEO2HX5fbQJzwJ+W7x/jw5ZFjsEU0PMph9xE8i5EqprKALW95eJQURkgzw98uJ/JvwGecR7bIjWWsUgVrrIfFZ2HlLy3sKETD1mmRLRMRhGVssRa0xJkdn3SpJBymBkM8+pSSDXMDNyDaToVHd2fgpNt0sjwiUZO19+jGQ+gQEg9Oq+bufmAVGihomNmjQG7UG3020vrlm7lkFnKFGU3kZ0KGAdmKe821pipQ+qEKcrZeTL2g5FsUks4cStjEZWwXg0b0n4GxmEpkWwIs5VBynjgK7xZaz1/0D7OxkVuLpsY5BQNFyLS84VBjjbg0iL2r2EQHBOxBhikuUOkdxODVF1cxHoWtPPsiyXO455Iv34hssCO8EV4ZIYTjS8SR4qYSHRiTiYQ4ZFbHi0iIhhBTi6dTCgSWRcnw4h4yGTuyTAiOGBIWGoZTgSHJQl+LcOJ4OCnW6yX2bMnJ9pidCOXtkTkTrIGpYuOynAiOF14SamMiOCk5Ke+mq8BcOrrvym8d0zKIQnWT+M1WwOQNO4fFiWb18hhERxJPx2fblbPHHyC41VyiAtKBUFBIih7JMWVoIQTFIr3lKPN80WvoLSWFPC653ioTZA0I0FrQ7qU6asaK0H7JmkSJa2ooOGVtNUsc3j9FYHkIkJy3SG6VHnfXKXGP9t4N9Q4Ye98AAAAAElFTkSuQmCC', + base64SuccessWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAiVYk6KvDHLfaegAAAo1JREFUWMPtWEtzmzAQNhCTq910ytXpiyvxTNOr60zrayepx9d02gnX4sTm7xcEiJX2gdnkGJ1A4tOnfWqXyeR1vMRYzrcPD9v5h5MBl3/Ldvx4cxIg/FWC8X0xjLjalM54uhhCfCrRuJURX0pi3EmIqZV7O59vrRZmguStHL9b7S7ftfLwOtiZDw7AHMtmquAQ12b5Wwbnordm8g9zLLO49qc/m2n6aKnhwPOGZ08hAiNHhheiHae1lOUPGZpQkPKa3q0mOUjaRzSRaGUjpy/mmWSwySSpllcEteBKAT52KEnSbblA51pJEPxBQoiH1FP4E3s5+FJv07h6/ylD6ui7B+9fq/ehrFB98ghec9EoVtyjK8pqCHLmCBOwMWSCeWFNN4MbPAk55NhsvoFHSSVR0k5TCTTEzlUGcqV/nVp7n9oIVkmtaqbAEqEgfdgHJPwsEAyZ9r4VAZXFjpEwyaw3+H2v42KYxKhs1XvY/gSSGv+IHyUSuHXCeZhLAgVI3EjgSGo1Fb3xO0tGGU9S2/KAIbtjxpJASG73qox6w5LUq0cEOa+iIONIWIilQSQ0pPa2jgaRQAgQP7c0mITRWGxpMAmEQFN2NAQJNCV0mI6GIIEO47hlQ0ORQLd0nL+hoUjg1m6I1TRr8uYEAriBHLcVFQ5UEMiBe3XkTBEG04WXlGKGxPnMS305XQPA1Ocn2JiuAZwE66fxnKwBnDTuXxZTMq85lwW6kt5ndLqZPefiU1yvmktcUSooChJF2aMprhQlnKJQ5FxRKkcVRa+itNYU8Io2oVkY14w0NMWYlqft91Bj9VHq+ca3b43BxjWJmla0sfKohlfTVpPN+93L/yLQ/IjQ/O5Q/VR5HdL4D7mlxmjwVdELAAAAAElFTkSuQmCC', + base64Empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAbUExURdvc3EdwTMLBwcjIyLSzs/Hx8ff39////19dXXz7IJEAAAAFdFJOU/4A6J9QDyyutAAAB5VJREFUeNrtnM1z4jYYxhUHkR4hdu9eU7Z75Ct7jgPbs9ZZmSuTrUWPmXTA186e+LMrf0uWLMtf2WkHXQgzln88et5XeiVMwPQdGrhCrpAr5Aq5Qv4TkJ07OGQFMLp1B4VYCz+kDblDQhJGeH4eEDLBYdLOHwaDWNBPIeHLYJAJ3meQ83IoCMTHDBKOBoKYGOeM8G0gyD0LObnDQB5ZSCtTNCBfsM9AboaBPLCQcDAIM1zht/dQEkMsd1DjI4hpw2YzMtBJeBbydWpCTJs3YDKGX62YgfGoVwi9KwtZJAzcYHHRm7sYCKD390nQSIoO5JGZIEOYxNoZ4+deISYLyeL5hLHbJ2QK98W0kudMgJe9Qh73odhO+KZHyNYGvgQS9gmJKhUigwSj3iBPUhXxePWmxBqHw0Mej9WQ3qILVjLC177yxNxXQ/7uK+Mn1aNVLsGsBTaWrSAPobYl0aUHt2fIs2Rgz7c9QYL0pSTkSzILLFtAJMH1cidN998T9E0/Sg73/pEEwrgkYRh86wlC949gJsR6EobBcz8hHOVgKYi2m6kZtodIkjEQvF3QjbGpmplB4/lRgJhxgRS2N15iijAvPmByDtCxfQhPJ8J4CR82rgCCBILarScw6X0OcMUyYrFVmbxErl0ZacFIoloOLdJAO42qY+NMDss2kKS8xmiZxcCpFKXWvpRGbQqJp5ixyRfJMmR6x0Fk+z29kmgWDYI5ziFbdug/84HxvduhWhLOJ2StPDQrMJPSjNANklh8QhB7dBO0yTGRwn1fkOk8rbQjiB8Ymww+JuiuN0icmSccK4naLMWYa/euL0+m23GyM8kgAc6sYeL4z04Qa4WjGepcKIliO8EUGSk7d9OGWOsoK31OSdy8TQZ59Y/hWbaV1IVs5/Ed6UzGK4nANAJiyGhRsZPUg2yzLe9hLyiJIyCaDU7udC2uy9pnkKvidlBUEltzFAqxRhBrBZm7HfZnjEQI3boqTsJq15PUDEaKZLgiJYc8OZtCtnM/4G93OFYooXpvdy0guwWWNQkEHl/j7Jw1XRmtlS9HYJkSPjk1IUnyyRqUKQn45NSDlP1mcg9i6En1ZU2IADnEtHF1Q+JwIcS/d5YakPuDUamEShGUHHikAz9oQCaE0CsrpYjDBVkEHQYdyK+EkKPhVErxqh1xbJ/oQf4gEeVsOIEc41WJNAwcd9GBfCZJezXsJhAvH+ImEEIOzlwXgpw5wQ0gH3MIOcsiQAahZuSD69/UQyxcQEggiQARQseVFO/ASAMCgM9gjkHZmhLENzi1AOhA7ullkMWUrfHKfpMiDBHtDIx6yCS6jseEnDUe7zcT6DGCtnrIY3olZw1hrPHkfucIAJa1EDu/lsVEyVmGGA67coKijeogFnMxlEaAV5ghRdDm1kDuuatZTJBGgJdOthIzsvZbDWRRuh6ScgR4EQLgagQvRQIxxQ4sxqcR4GE+c4CkjZQQW9YF89Y4OFAjOCki5KmiDxsBL3PlSJWlAFVogaoIePlYi2ClCJAHRa/cmre5eqTii4uvisqQJxqnip6pNd68DhEvyEs5xIyHBNdh4thCKhU++10kD7Gy1Up1A/o56FKuRJQWSFCuf8dpbisxhqHSKlSSgvG7VTaFKO5TzYD5VMPUxEB2YJNiqq3xYJ0KrroH8mq7xpoXqEZgfgNRUQsDtTVvUOk3sLUKbqrBr7YGvkCkQNC/9SA+vTYtvERrxiKEmcogk4ZqCLUd59MIEiFYHlIoxelCaJWDMmtOPIa80XVLbkb6hzaEwwTcPEmV4AIRlBGNIEmuJBFwLAZoHClJ36J8h+wxihpCqJosAnJrSKwEcQOFAFeWN4RQMYc0Ao4Jhg5gpASzyWcDvjpuDIlTkrGGJEro1rHIjHKR3wJCAj+z5oyi11gJBkXy9QFJIiAu78d+pgSjuWhGN0gUAZAcEncSJf4LRrZ8I94WEmcNCJJqBWYjVbE9bg2JxiyrViBWty6QvO56D8jPVWLA4ZX8dfkxvJJPl8t8aCX+pU/Iz1SCf7lc4OBK0OWfQaKLP0TKjj96VvIp+/BDZjwNKF2ItV2vN7sWStAl87oWkm3dZ+k3lEMoYXe8cT1eq2TOePJDD8KfQdxu6iEPxanUZa4HmZRq3dunGsj3BzFq6yD3wnZNX4n2emI2hXyXQpi6RRZdfSgxHNuxVZBFdyVeBPDmCsiksxKUiDAUEKuzkvRUEs0V08pjVyU2/yqFmF2VZGYop3peitdUiQd1pnrL7qTE01tPzE6eaEKm23dQwh2jNlbiay+/245zl94abw45CzNPyqYQ2++kxHGV1crWzg4A2yvR+BY7wziwnRLN7+O36aA54+ZKGjxZYK3txJpxQyUNn5GwtquII4+ACiWtnvawduu1A3SVtH5uhTvAVSpBG7fDYz6RQ+M6JWjmKm6g+RvTla9UMtspu+s+37VbVCupNqPx43CsNawSb1PbtcmDfQWmUILW7rRXSPHtSq5k5ur0a/hb7DQCUiW3G71ejX/wvV1kSoyNbp8Wvyqn1lCIKvl6gNDkNBYzt0GHdr+Pt9xGl1//ncAVcoVcIVfIFXKFXCFXyP8I8i8SyTW4yTz2lwAAAABJRU5ErkJggg==', + base64Error: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAJFBMVEVHcEzo6Oibm5ukpKSbm5uampqbm5ubm5u5ubnn5+fm5ub6+vpGpDPdAAAAC3RSTlMA/v4hb+u20dq8aQhnHL4AAATwSURBVHja7ZvNb+JGGMbdjjdVe3NPodzeMhj1ZMUGujkh28B9wKR7iwwBqafWSbPqsbm0uTWtVlrTS9v0Et9yqLQS/1zHNiTZMMB4bO92d+dRUITt8c/PvPPx2h4URUpKSkpKSkpK6m3K6lFN73Q+S/+es3W3fzabTh2Dl0FAXEM+BgrgeXxRsdILTDU9n7J0vz/+EsCYC9KEiSFc06pf5zouqAkjkGWo0OG5Fq6j2IwZ6I4/4DhyTxc20oUjAj5PRTTrwvGAZ9p+ADzlD4RDctCoLhb7JUP87xeLxS3BZUIQ+YNCFi8wRwc4GIqGRK/GkM+5ILV8kFflOmkkkH/LddJ4c05eSSfSyTvrZPEmnCw+UCeuk84QvTSnUF0uCL68fBle/swF+RL1QZ/EpU6gHtOsAM64pnjPwxgTLsjoBM58ODNaAXYBT5QeGdr0KwcEA8He0TkPBLCjUDNHpG4qlg8eTCzXht1FVd1MxTPHj5LTtUiSrKK+7iDf8wBGxk4If3arLv/HF4Tox0A2nlFIGp+CIA+LzSamgbp4TNvZjECtDAjyMcB5HybLO6NxsRA1vmFCNjguNXDGWygbRPXh/B+zn9zPWK5RCkT18QxA57YgAqE+HGS6/tAoD4JO0ts+M2tbyQJpc95a5oI0xXNhCZGQ/x8E0VSCkUZY6Z6CIE/qdO5eL+yPlW6tMMgefPs3o7Bdt8iguJj4DThlZSY/rJ0yB+RraLDK2jAQCHyr4zIhT9mQ7vowygMZjpgQG+CYUV2E1EWqixyzICr8eFFnBB5ba1Y4IIfeKQvysW7ssZrwQLEFmvCBM2U6oRkdI5Wgm1QnO8RUTDlASoiESIiESMh7BDHKhlhu/LbSNUuEqL3lu1p945vO3BArADiaum7vBGDUKQfSIjBykooyrRPQnTIglHFfSagHeqd4iErwa9duEebpckGQjx/VT4v5fC0XhJHAd1mPRvJAVMZiAeQzTpgHYrPKqkGnUEiX+dCoNS4UgniHMTnUS4iESIiE7IS0x+mnVAidglDwVcmQJpy2WQ8VC4UgogfbA1RE4Nuw3UghEBV2rKl7V5ygAJPSY9KGQbP01mVjA5Fa2f1kQN2U3k+M9POWB8gnJUNMZJioWTMzKwOklyxgDrCXVcMMEF90tXM9C2TiCqmfCdIRi/jeewNpyerKok9WkGuzfCdYC+fXRsmBxxpVGG2zY0ZBbieJKvPrDQce3lxppBhIjGFWGkVoxUEoZt0Mukn2XBQH0bTHZpaMIp2sU/6qasU70W6/eHjM09VmYSc6C6Jpvz+orKvVxot8kL3HkMr9IZ9qeZ2o6RrO9mOI9ufdIR9peZ2gNIW31yC/MpyI9ngUDNIsezPks3vIsWDGdYA7cZa9pbqUVeCr/neiaR3U3R4BfXPg75vwb8I/b7HjxChobDZCO+Ny4wuxxaVxPPowcoNnrzPmzGFlX3RJHz2FafbhJ41n8PLx2DCM7KkwQgpqka1DVzKdJNHfJwBe9l/n0eSZFsIPjVSY8xZKZpSXnogwled98wAx3xRcdBNq1f1fhFVdIcL5tvaDolC7XaqaWStEtLOJHkbhlSauMLrma4yHEa03AVUoIUs/M2NQFkchBZiGUPeKonAnqhLOo4hrKf0WTyZ1FcU0Ki0hVrSr+Mucnvya7jYUKSkpKSkpKSmpD0f/AXq+Umj5XnXDAAAAAElFTkSuQmCC', + base64BackToTop: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAElBMVEVRUVH+/v5HcEyZmZlRUVFRUVGm1ByOAAAABnRSTlPMzADMTZAJBBGsAAAEnElEQVR42t2cS27jMAyGf7/2U+QCQeDsbeQCgZDujaC5/1UmkzaJn+JDFGcw3LdfflKibJkkDnxrL7dbg7sNt6+L4O8OYBM+B0ys+QrGkHZG+OEEQ8g6go8Bx1GIGMdpNOQyIG6XdMgnSPtKhLQDGEZFBgYMkhKFtGBb0EIEjDgFRowoBVaMGAWpMedEfxMiZtwpUsgZCqtlkCNUdpVAWigtCCCDFtLwIWeoreZCWiRYYEKGFEjDg+yRZCUH0iLRAgNyToXUNCRZyMqWhGnUN2IPm3wSlwJ7IUspyCBkIQUZhCykIIeQuRTkEDKXAuM9srrtYbrZN7Y98giZSoFd+t1OxmMITG0dcrSFXFchZ1tIvQZpYWxhBbK3hpQrkMEa0iwh5t4a+QvZvDXyF7J5a+Qv5PPW21/I5623v5DPW29/IaO3Xv5Clrw1y1/Ikrdm+Qs5svw83yNnSJ5BQb4F/F7EIEJSnThGBAXxkFQfLOviQUE8JAUPsosHBfGQfDAtHhREQ1JxIV00KIgmrnRI84S0yAd5BAXxxJUck0f6Qnwr9qmr6xF5xLMjcwn/iudIEAdWnyjkEXlQKZiRVzoqRyLbgeUKKR8Q4alY7cSnoxzSf2ggsqehKr6YVpcXpOd7H93f60cKhOd7Re2LteUF4eLqiVS1mr0ge4io6C2+soaFkJ7MuuuQs1yITEp9hwwKISIpzR2iESKSIoT0rLNwuVHQqoSIpAQJpGce60vIUSdEIuUqgPTsJ5QFZK8UIpBS8iG94GFrDjlrhfCl8CG96Llxmle4kEr6vKWBPIVo9kqDQSRk9/3cWoikcCFPAd33v4dIChPyEvLzBA6RlEYWke4JEUnhKXkLeUEKxRHJFfKCQHGucIW8IdZSRkLeEGMpYyEjiK2UsZARxFTKRMgYYillImQMMZQyFTKB2EmZCplAuFLIHT8TMoWwpQwiIVMIUwqpZP5bp5CCvCTiQKr5f5lCQN+tPCBn2ZvVDFJwIDUP0m1BYAfZYRNSsCB7BqTbhoARePIxtZ9tgwWkoJcwCalmv3MBAemtO4R6dah2HaKQqj8Zvp9sQDjvJ21+SPCBHPJDDk6QITekEV7gqCC19CpKAym9IMfckKv4olMBCeIrWwVEfvkshzQekO9r9P1/ALk+IG1eSPCDiCJfyG+FyU+A6ZCa/piZDinpz7LpkCv5gdkAEshP5emQhv7onw6pGeULyZCSUYiRDAmMkpJkCKs4JhFSq8p8hJBSVbAkhARV6ZUQoisik0FqXTmcDHLVFfbJIEFXoiiCNMpiSxGkVJaNiiBBWQArgTTaUl4JpNQWJUsgQVteXQg+AKkLxQWFGKW+5J2+eVp4S168X3CF1CltCKdTJ8lb84YK2bUBO+wZW0Pqv9nk4tKu49N45NJC5dMM5tLW5tOg59Jq6NM06dL+abFXwr/RkuvTXJwae1abtE/Dt0/ruksTvs84AZ/BCC4jHnyGVfiM3VBQFANEXEah+Ax18RlP4zNox2dkkM/wI58xTn8yDCXGYCDV3W5RGSajtXyGhG1jbpbjzpwGt/0MJft8jqC7iUbQ/QZaxdnKqcIftwAAAABJRU5ErkJggg==', +} diff --git a/src/uni_modules/z-paging/components/z-paging/js/z-paging-utils.js b/src/uni_modules/z-paging/components/z-paging/js/z-paging-utils.js new file mode 100644 index 0000000..7cefcfd --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/js/z-paging-utils.js @@ -0,0 +1,220 @@ +// [z-paging]工具类 + +import zConfig from './z-paging-config' +import zLocalConfig from '../config/index' +import c from './z-paging-constant' + +const storageKey = 'Z-PAGING-REFRESHER-TIME-STORAGE-KEY'; +let config = null; +const timeoutMap = {}; + +/* +当z-paging未使用uni_modules管理时,控制台会有警告:WARNING: Module not found: Error: Can't resolve '@/uni_modules/z-paging'... +此时注释下方try中的代码即可 +*/ +// #ifdef VUE2 +try { + const contextKeys = require.context('@/uni_modules/z-paging', false, /\z-paging-config$/).keys(); + if (contextKeys.length) { + const suffix = '.js'; + config = require('@/uni_modules/z-paging/z-paging-config' + suffix); + } +} catch (e) {} +// #endif + +//获取默认配置信息 +function gc(key, defaultValue) { + if (!config) { + if (zLocalConfig && Object.keys(zLocalConfig).length) { + config = zLocalConfig; + } else { + const tempConfig = zConfig.getConfig(); + if (zConfig && tempConfig) { + config = tempConfig; + } + } + } + if (!config) return defaultValue; + const value = config[_toKebab(key)]; + return value === undefined ? defaultValue : value; +} + + +//获取最终的touch位置 +function getTouch(e) { + let touch = null; + if (e.touches && e.touches.length) { + touch = e.touches[0]; + } else if (e.changedTouches && e.changedTouches.length) { + touch = e.changedTouches[0]; + } else if (e.datail && e.datail != {}) { + touch = e.datail; + } else { + return { + touchX: 0, + touchY: 0 + } + } + return { + touchX: touch.clientX, + touchY: touch.clientY + }; +} + +//判断当前手势是否在z-paging内触发 +function getTouchFromZPaging(target) { + if (target && target.tagName && target.tagName !== 'BODY' && target.tagName !== 'UNI-PAGE-BODY') { + const classList = target.classList; + if (classList && classList.contains('z-paging-content')) { + return { + isFromZp: true, + isPageScroll: classList.contains('z-paging-content-page'), + isReachedTop: classList.contains('z-paging-reached-top') + }; + } else { + return getTouchFromZPaging(target.parentNode); + } + } else { + return { isFromZp: false }; + } +} + +//获取z-paging所在的parent +function getParent(parent) { + if (!parent) return null; + if (parent.$refs.paging) return parent; + return getParent(parent.$parent); +} + +//打印错误信息 +function consoleErr(err) { + console.error(`[z-paging]${err}`); +} + +//延时操作,如果key存在,调用时根据key停止之前的延时操作 +function delay(callback, ms = c.delayTime, key) { + const timeout = setTimeout(callback, ms);; + if (!!key) { + timeoutMap[key] && clearTimeout(timeoutMap[key]); + timeoutMap[key] = timeout; + } + return timeout; +} + +//设置下拉刷新时间 +function setRefesrherTime(time, key) { + const datas = getRefesrherTime() || {}; + datas[key] = time; + uni.setStorageSync(storageKey, datas); +} + +//获取下拉刷新时间 +function getRefesrherTime() { + return uni.getStorageSync(storageKey); +} + +//通过下拉刷新标识key获取下拉刷新时间 +function getRefesrherTimeByKey(key) { + const datas = getRefesrherTime(); + return datas && datas[key] ? datas[key] : null; +} + +//通过下拉刷新标识key获取下拉刷新时间(格式化之后) +function getRefesrherFormatTimeByKey(key, textMap) { + const time = getRefesrherTimeByKey(key); + const timeText = time ? _timeFormat(time, textMap) : textMap.none; + return `${textMap.title}${timeText}`; +} + +//将文本的px或者rpx转为px的值 +function convertToPx(text) { + const dataType = Object.prototype.toString.call(text); + if (dataType === '[object Number]') return text; + let isRpx = false; + if (text.indexOf('rpx') !== -1 || text.indexOf('upx') !== -1) { + text = text.replace('rpx', '').replace('upx', ''); + isRpx = true; + } else if (text.indexOf('px') !== -1) { + text = text.replace('px', ''); + } + if (!isNaN(text)) { + if (isRpx) return Number(uni.upx2px(text)); + return Number(text); + } + return 0; +} + +//获取当前时间 +function getTime() { + return (new Date()).getTime(); +} + +//获取z-paging实例id +function getInstanceId() { + const s = []; + const hexDigits = "0123456789abcdef"; + for (let i = 0; i < 10; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + return s.join('') + getTime(); +} + +//------------------ 私有方法 ------------------------ +//时间格式化 +function _timeFormat(time, textMap) { + const date = new Date(time); + const currentDate = new Date(); + const dateDay = new Date(time).setHours(0, 0, 0, 0); + const currentDateDay = new Date().setHours(0, 0, 0, 0); + const disTime = dateDay - currentDateDay; + let dayStr = ''; + const timeStr = _dateTimeFormat(date); + if (disTime === 0) { + dayStr = textMap.today; + } else if (disTime === -86400000) { + dayStr = textMap.yesterday; + } else { + dayStr = _dateDayFormat(date, date.getFullYear() !== currentDate.getFullYear()); + } + return `${dayStr} ${timeStr}`; +} + +//date格式化为年月日 +function _dateDayFormat(date, showYear = true) { + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + return showYear ? `${year}-${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}` : `${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}`; +} + +//data格式化为时分 +function _dateTimeFormat(date) { + const hour = date.getHours(); + const minute = date.getMinutes(); + return `${_fullZeroToTwo(hour)}:${_fullZeroToTwo(minute)}`; +} + +//不满2位在前面填充0 +function _fullZeroToTwo(str) { + str = str.toString(); + return str.length === 1 ? '0' + str : str; +} + +//驼峰转短横线 +function _toKebab(value) { + return value.replace(/([A-Z])/g, "-$1").toLowerCase(); +} + +export default { + gc, + setRefesrherTime, + getRefesrherFormatTimeByKey, + getTouch, + getTouchFromZPaging, + getParent, + convertToPx, + getTime, + getInstanceId, + consoleErr, + delay +}; diff --git a/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-renderjs.js b/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-renderjs.js new file mode 100644 index 0000000..426748c --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-renderjs.js @@ -0,0 +1,55 @@ +// [z-paging]使用renderjs在app-vue和h5中对touchmove事件冒泡进行处理 + +import u from '../js/z-paging-utils' +const data = { + startY: 0, + isTouchFromZPaging: false, + isUsePageScroll: false, + isReachedTop: true, + isIosAndH5: false +} + +export default { + mounted() { + this._handleTouch(); + // #ifdef APP-VUE + this.$ownerInstance && this.$ownerInstance.callMethod('_checkVirtualListScroll'); + // #endif + }, + methods: { + //接收逻辑层发送的数据 + renderPropIsIosAndH5Change(newVal) { + if (newVal === -1) return; + data.isIosAndH5 = newVal; + }, + //拦截处理touch事件 + _handleTouch() { + if (window && !window.$zPagingRenderJsInited) { + window.$zPagingRenderJsInited = true; + window.addEventListener('touchstart', this._handleTouchstart, { passive: true }) + window.addEventListener('touchmove', this._handleTouchmove, { passive: false }) + } + }, + _handleTouchstart(e) { + const touch = u.getTouch(e); + data.startY = touch.touchY; + const touchResult = u.getTouchFromZPaging(e.target); + data.isTouchFromZPaging = touchResult.isFromZp; + data.isUsePageScroll = touchResult.isPageScroll; + data.isReachedTop = touchResult.isReachedTop; + }, + _handleTouchmove(e) { + const touch = u.getTouch(e); + const moveY = touch.touchY - data.startY; + if (data.isTouchFromZPaging && ((data.isReachedTop && moveY > 0) || (data.isIosAndH5 && !data.isUsePageScroll && moveY < 0))) { + if (e.cancelable && !e.defaultPrevented) { + e.preventDefault(); + } + } + }, + _removeAllEventListener(){ + window.removeEventListener('touchstart'); + window.removeEventListener('touchmove'); + } + } +}; diff --git a/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-wxs.wxs b/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-wxs.wxs new file mode 100644 index 0000000..6566455 --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/wxs/z-paging-wxs.wxs @@ -0,0 +1,342 @@ +// [z-paging]微信小程序、QQ小程序、app-vue、h5上使用wxs实现自定义下拉刷新,降低逻辑层与视图层的通信折损,提升性能 + +var currentDis = 0; +var isPCFlag = -1; +var startY = -1; + +function propObserver(newValue, oldValue, ownerIns, ins) { + var state = ownerIns.getState() || {}; + state.currentIns = ins; + var dataset = ins.getDataset(); + var loading = dataset.loading == true; + if (newValue && newValue.indexOf('end') != -1) { + var transition = newValue.split('end')[0]; + _setTransform('translateY(0px)', ins, false, transition); + state.moveDis = 0; + state.oldMoveDis = 0; + currentDis = 0; + } else if (newValue && newValue.indexOf('begin') != -1) { + var refresherThreshold = ins.getDataset().refresherthreshold; + _setTransformValue(refresherThreshold, ins, state, false); + } +} + +function touchstart(e, ownerIns) { + var ins = _getIns(ownerIns); + var state = {}; + var dataset = {}; + ownerIns.callMethod('_handleListTouchstart'); + if (ins) { + state = ins.getState(); + dataset = ins.getDataset(); + if (_touchDisabled(e, ins, 0)) return; + } + var isTouchEnded = state.isTouchEnded; + state.oldMoveDis = 0; + var touch = _getTouch(e); + var loading = _isTrue(dataset.loading); + state.startY = touch.touchY; + startY = state.startY; + state.lastTouch = touch; + if (!loading && isTouchEnded) { + state.isTouchmoving = false; + } + state.isTouchEnded = false; + ownerIns.callMethod('_handleRefresherTouchstart', touch); +} + +function touchmove(e, ownerIns) { + var touch = _getTouch(e); + var ins = _getIns(ownerIns); + var dataset = ins.getDataset(); + var refresherThreshold = dataset.refresherthreshold; + var isIos = _isTrue(dataset.isios); + var state = ins.getState(); + var watchTouchDirectionChange = _isTrue(dataset.watchtouchdirectionchange); + var moveDisObj = {}; + var moveDis = 0; + var prevent = false; + if (watchTouchDirectionChange) { + moveDisObj = _getMoveDis(e, ins); + moveDis = moveDisObj.currentDis; + prevent = moveDisObj.isDown; + var direction = prevent ? 'top' : 'bottom'; + if (prevent == state.oldTouchDirection && prevent != state.oldEmitedTouchDirection) { + ownerIns.callMethod('_handleTouchDirectionChange', { direction: direction }); + state.oldEmitedTouchDirection = prevent; + } + state.oldTouchDirection = prevent; + } + if (_touchDisabled(e, ins, 1)) { + _handlePullingDown(state, ownerIns, false); + return true; + } + if (!_getAngleIsInRange(e, touch, state, dataset)) { + _handlePullingDown(state, ownerIns, false); + return true; + } + moveDisObj = _getMoveDis(e, ins); + moveDis = moveDisObj.currentDis; + prevent = moveDisObj.isDown; + if (moveDis < 0) { + _setTransformValue(0, ins, state, false); + _handlePullingDown(state, ownerIns, false); + return true; + } + if (prevent && !state.disabledBounce) { + if (isIos) { + ownerIns.callMethod('_handleScrollViewDisableBounce', {bounce: false}); + } + state.disabledBounce = true; + _handlePullingDown(state, ownerIns, prevent); + return !prevent; + } + _setTransformValue(moveDis, ins, state, false); + var oldRefresherStatus = state.refresherStatus; + var oldIsTouchmoving = _isTrue(dataset.oldistouchmoving); + var hasTouchmove = _isTrue(dataset.hastouchmove); + var isTouchmoving = state.isTouchmoving; + state.refresherStatus = moveDis >= refresherThreshold ? 1 : 0; + if (!isTouchmoving) { + state.isTouchmoving = true; + isTouchmoving = true; + } + if (state.isTouchEnded) { + state.isTouchEnded = false; + } + if (hasTouchmove) { + ownerIns.callMethod('_handleWxsPullingDown', { moveDis:moveDis, diffDis:moveDisObj.diffDis }); + } + if (oldRefresherStatus == undefined || oldRefresherStatus != state.refresherStatus || oldIsTouchmoving != isTouchmoving) { + ownerIns.callMethod('_handleRefresherTouchmove', moveDis, touch); + } + _handlePullingDown(state, ownerIns, prevent); + return !prevent; +} + +function touchend(e, ownerIns) { + var touch = _getTouch(e); + var ins = _getIns(ownerIns); + var dataset = ins.getDataset(); + var state = ins.getState(); + if (_touchDisabled(e, ins, 2)) return; + state.reachMaxAngle = true; + state.hitReachMaxAngleCount = 0; + state.disabledBounce = false; + state.fixedIsTopHitCount = 0; + if (!state.isTouchmoving) return; + var oldRefresherStatus = state.refresherStatus; + var oldMoveDis = state.moveDis; + var refresherThreshold = ins.getDataset().refresherthreshold + var moveDis = _getMoveDis(e, ins).currentDis; + if (!(moveDis >= refresherThreshold && oldRefresherStatus === 1)) { + state.isTouchmoving = false; + } + ownerIns.callMethod('_handleRefresherTouchend', moveDis); + state.isTouchEnded = true; + if (oldMoveDis < refresherThreshold) return; + var animate = false; + if (moveDis >= refresherThreshold) { + moveDis = refresherThreshold; + animate = true; + } + _setTransformValue(moveDis, ins, state, animate); +} + +// #ifdef H5 +function isPC() { + if (!navigator) return false; + if (isPCFlag != -1) return isPCFlag; + var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + isPCFlag = agents.every(function(item) { return navigator.userAgent.indexOf(item) < 0 }); + return isPCFlag; +} + +var movable = false; + +function mousedown(e, ins) { + if (!isPC()) return; + touchstart(e, ins); + movable = true; +} + +function mousemove(e, ins) { + if (!isPC() || !movable) return; + touchmove(e, ins); +} + +function mouseup(e, ins) { + if (!isPC()) return; + touchend(e, ins); + movable = false; +} + +function mouseleave(e, ins) { + if (!isPC()) return; + movable = false; +} +// #endif + + +function _setTransformValue(value, ins, state, animate) { + value = value || 0; + if (state.moveDis == value) return; + state.moveDis = value; + _setTransform('translateY(' + value + 'px)', ins, animate, ''); +} + +function _setTransform(transform, ins, animate, transition) { + var dataset = ins.getDataset(); + if (_isTrue(dataset.refreshernotransform)) return; + transform = transform == 'translateY(0px)' ? 'none' : transform; + ins.requestAnimationFrame(function() { + var stl = { 'transform': transform }; + if (animate) { + stl['transition'] = 'transform .1s linear'; + } + if (transition.length) { + stl['transition'] = transition; + } + ins.setStyle(stl); + }) +} + +function _getMoveDis(e, ins) { + var state = ins.getState(); + var refresherThreshold = parseFloat(ins.getDataset().refresherthreshold); + var refresherOutRate = parseFloat(ins.getDataset().refresheroutrate); + var refresherPullRate = parseFloat(ins.getDataset().refresherpullrate); + var touch = _getTouch(e); + var currentStartY = !state.startY || state.startY == 'NaN' ? startY : state.startY; + var moveDis = touch.touchY - currentStartY; + var oldMoveDis = state.oldMoveDis || 0; + state.oldMoveDis = moveDis; + var diffDis = moveDis - oldMoveDis; + if (diffDis > 0) { + diffDis = diffDis * refresherPullRate; + if (currentDis > refresherThreshold) { + diffDis = diffDis * (1 - refresherOutRate); + } + } + diffDis = diffDis > 100 ? diffDis / 100 : diffDis; + currentDis += diffDis; + currentDis = Math.max(0, currentDis); + return { + currentDis: currentDis, + diffDis: diffDis, + isDown: diffDis > 0 + }; +} + +function _getTouch(e) { + var touch = e; + if (e.touches && e.touches.length) { + touch = e.touches[0]; + } else if (e.changedTouches && e.changedTouches.length) { + touch = e.changedTouches[0]; + } else if (e.datail && e.datail != {}) { + touch = e.datail; + } + return { + touchX: touch.clientX, + touchY: touch.clientY + }; +} + +function _getIns(ownerIns) { + var ins = ownerIns.getState().currentIns; + if (!ins) { + ownerIns.callMethod('_handlePropUpdate'); + } + return ins; +} + +function _touchDisabled(e, ins, processTag) { + var dataset = ins.getDataset(); + var state = ins.getState(); + var loading = _isTrue(dataset.loading); + var useChatRecordMode = _isTrue(dataset.usechatrecordmode); + var refresherEnabled = _isTrue(dataset.refresherenabled); + var useCustomRefresher = _isTrue(dataset.usecustomrefresher); + var usePageScroll = _isTrue(dataset.usepagescroll); + var pageScrollTop = parseFloat(dataset.pagescrolltop); + var scrollTop = parseFloat(dataset.scrolltop); + var finalScrollTop = usePageScroll ? pageScrollTop : scrollTop; + var fixedIsTop = false; + var isIos = _isTrue(dataset.isios); + if (!isIos && finalScrollTop == (state.startScrollTop || 0) && finalScrollTop <= 105) { + fixedIsTop = true; + } + var fixedIsTopHitCount = state.fixedIsTopHitCount || 0; + if (fixedIsTop) { + fixedIsTopHitCount ++; + if (fixedIsTopHitCount <= 3) { + fixedIsTop = false; + } + state.fixedIsTopHitCount = fixedIsTopHitCount; + } else { + state.fixedIsTopHitCount = 0; + } + if (!isIos && processTag === 0) { + state.startScrollTop = finalScrollTop || 0; + } + if (!isIos && processTag === 2) { + fixedIsTop = true; + } + return loading || useChatRecordMode || !refresherEnabled || !useCustomRefresher || + ((usePageScroll && useCustomRefresher && pageScrollTop > 5) && !fixedIsTop) || + ((!usePageScroll && useCustomRefresher && scrollTop > 5) && !fixedIsTop); +} + +function _getAngleIsInRange(e, touch, state, dataset) { + var maxAngle = dataset.refreshermaxangle; + var refresherAecc = _isTrue(dataset.refresheraecc); + var lastTouch = state.lastTouch; + var reachMaxAngle = state.reachMaxAngle; + var moveDis = state.oldMoveDis; + if (!lastTouch) return true; + if (maxAngle >= 0 && maxAngle <= 90 && lastTouch) { + if ((!moveDis || moveDis < 1) && !refresherAecc && reachMaxAngle != null && !reachMaxAngle) return false; + var x = Math.abs(touch.touchX - lastTouch.touchX); + var y = Math.abs(touch.touchY - lastTouch.touchY); + var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); + if ((x || y) && x > 1) { + var angle = Math.asin(y / z) / Math.PI * 180; + if (angle < maxAngle) { + var hitReachMaxAngleCount = state.hitReachMaxAngleCount || 0; + state.hitReachMaxAngleCount = ++hitReachMaxAngleCount; + if (state.hitReachMaxAngleCount > 2) { + state.lastTouch = touch; + state.reachMaxAngle = false; + } + return false; + } + } + } + state.lastTouch = touch; + return true; +} + +function _handlePullingDown(state, ins, onPullingDown) { + var oldOnPullingDown = state.onPullingDown || false; + if (oldOnPullingDown != onPullingDown) { + ins.callMethod('_handleWxsPullingDownStatusChange', onPullingDown); + } + state.onPullingDown = onPullingDown; +} + +function _isTrue(value) { + value = (typeof(value) === 'string' ? JSON.parse(value) : value) || false; + return value == true || value == 'true'; +} + +module.exports = { + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + mouseleave: mouseleave, + propObserver: propObserver +} diff --git a/src/uni_modules/z-paging/components/z-paging/z-paging.vue b/src/uni_modules/z-paging/components/z-paging/z-paging.vue new file mode 100644 index 0000000..80e5f7a --- /dev/null +++ b/src/uni_modules/z-paging/components/z-paging/z-paging.vue @@ -0,0 +1,307 @@ + + + + + + + + + + + +