Compare commits

...

15 Commits

Author SHA1 Message Date
ihzero 03082a9cdb 修改主页打包 2025-05-28 11:28:43 +08:00
ihzero 6497852f80 修改主页样式 2025-05-28 11:20:33 +08:00
ihzero fcc4e21c36 修改 2024-12-02 22:23:49 +08:00
unknown b55bb1e863 关闭提示 2024-06-04 10:58:11 +08:00
unknown 831808415d 修改提示 2024-06-04 10:55:39 +08:00
unknown e5fea5c439 提示 2024-06-04 10:10:22 +08:00
unknown 614c9fbb6a 提示 2024-06-04 10:06:05 +08:00
unknown 72ac138a46 打包 2024-06-04 09:47:07 +08:00
unknown 34e4f61485 虫情 2024-06-04 09:40:36 +08:00
ihzero 52a1dbdc83 修改bug 2024-06-04 00:27:16 +08:00
ihzero 06d9d03dea 水质,土壤 2024-06-04 00:07:10 +08:00
ihzero c88411f9c2 修改水质设备 2024-05-28 23:11:27 +08:00
ihzero abdb92ee74 基数数据统计 2024-01-31 12:08:12 +08:00
ihzero 156643ea77 打包 2024-01-30 15:25:59 +08:00
ihzero 176abb9c7d 设备管理条件 2024-01-30 15:24:48 +08:00
116 changed files with 4421 additions and 39156 deletions

View File

@ -1,3 +1,3 @@
ENV = 'development'
VUE_APP_BASE_API = 'https://lcny.sk797.cn'
VUE_APP_BASE_API = 'https://lcny-api.peidikeji.cn'

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

36439
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -66,10 +66,10 @@ export default {
},
},
isEdit() {
return !!this.$listeners.onEdit && checkPermission(this.editAuth)
return (!!this.$listeners.onEdit && checkPermission(this.editAuth)) || (!!this.$listeners.onEdit && this.editAuth.length==0)
},
isDel() {
return !!this.$listeners.onDel && checkPermission(this.delAuth)
return (!!this.$listeners.onDel && checkPermission(this.delAuth)) || (!!this.$listeners.onDel && this.delAuth.length==0)
},
columsList() {
const arr = []

View File

@ -3,9 +3,17 @@
<view class="bg-white p-30rpx">
<view class="flex justify-between items-center">
<view class="text-32rpx">全市数据统计</view>
<u-button size="mini" v-auth="['endpoint.town_street.base_statistics_edit']" @click="cityEditShow = true"></u-button>
<u-button
size="mini"
v-auth="['endpoint.town_street.base_statistics_edit']"
@click="cityEditShow = true"
>编辑</u-button
>
</view>
<view class="grid grid-cols-2 mt-20rpx" v-auth="['endpoint.town_street.base_statistics']">
<view
class="grid grid-cols-2 mt-20rpx"
v-auth="['endpoint.town_street.base_statistics']"
>
<CountItem
v-for="(item, i) in showCityList"
:key="i"
@ -88,7 +96,29 @@
@onEdit="handleEdit"
:colums="baseTableColums"
:data="currentData"
:editAuth="['endpoint.town_street.edit']"
>
<template v-slot:extends="{ data }">
<view class="w-full">
<view v-for="(item, i) in formtExtends(data)" :key="i">
<view class="flex items-center">
<view class="flex-1 flex-center">
{{ item.name }}
</view>
<view class="flex-1">
<u-cell-item
v-for="(va, ii) in item.value"
:key="ii"
:title="va.year"
:value="va.value"
:arrow="false"
></u-cell-item>
</view>
</view>
<u-line></u-line>
</view>
</view>
</template>
</BaseTablePopup>
</view>
</template>
@ -98,6 +128,8 @@ import cuPopup from '@/components/cu-popup/index.vue'
import CountEdit from './components/town-count-edit.vue'
import BaseTablePopup from '@/components/base-table/popup.vue'
import CityEdit from './components/town-city-edit'
import checkPermission from '@/utils/permission.js'
import { concat } from 'lodash-es'
const filterCityCount = [
'city_data_chart_nongye',
'city_data_chart_yuye',
@ -105,6 +137,28 @@ const filterCityCount = [
'city_data_chart_lingye',
'city_data_chart_activity',
]
const defaultData = {
chart_nongye: {
label: '统计数据-农业',
unit: '万元',
},
chart_yuye: {
label: '统计数据-渔业',
unit: '万元',
},
chart_xumuye: {
label: '统计数据-畜牧业',
unit: '万元',
},
chart_lingye: {
label: '统计数据-林业',
unit: '万元',
},
chart_activity: {
label: '统计数据-其他',
unit: '万元',
},
}
const baseTableColums = [
{
title: '街镇名称',
@ -130,6 +184,10 @@ const baseTableColums = [
title: '街镇描述',
dataIndex: 'description',
},
{
title: '统计数据',
dataIndex: 'extends',
},
]
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'
export default {
@ -147,20 +205,23 @@ export default {
(item) => !filterCityCount.includes(item.slug)
)
},
options() {
return [
{
text: '编辑',
style: {
backgroundColor: '#007aff',
},
permission: ['endpoint.town_street.edit'],
},
].filter((e) => checkPermission(e.permission))
},
},
data() {
return {
baseTablePopupShow: false,
baseTableColums,
cityItemShow: false,
options: [
{
text: '编辑',
style: {
backgroundColor: '#007aff',
},
},
],
cityList: [],
cityEditShow: false,
dataList: [],
@ -184,6 +245,48 @@ export default {
this.getCityData()
},
methods: {
isObject(val) {
return Object.prototype.toString.call(val) === '[object Object]'
},
isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]'
},
formtExtends({ value }) {
const defaultObj = value
const tempData = Object.keys(defaultObj).reduce((pre, cur) => {
const currentData = defaultData[cur]
const obj = {
name: currentData.label,
unit: currentData.unit,
slug: cur,
}
const extend = defaultObj[cur]
if (this.isObject(extend) || this.isArray(extend)) {
const temp = []
if (Object.keys(extend).length === 0) {
temp.push({
value: '',
year: null,
})
}
for (const key in extend) {
temp.push({
value: extend[key],
year: key,
})
}
return concat(pre, {
...obj,
isMore: true,
value: temp,
})
}
}, [])
return tempData ?? []
},
handleEdit(e) {
this.currentData = e
this.baseTablePopupShow = false

View File

@ -443,11 +443,38 @@
},
},
onLoad() {
this.getSupplier();
this.getProject();
this.queryDataList();
this.getDeviceTypes();
this.getAgriculturalBasic();
},
methods: {
getSupplier(){
this.$http.get('/api/keywords',{params:{
type_key:'device-supplier'
}}).then(({data})=>{
this.supplierlist=data.data.map(e=>{
return {
label:e.name,
value:e.key
}
})
console.log(this.supplierlist);
})
},
getProject(){
this.$http.get('/api/keywords',{params:{
type_key:'device-project'
}}).then(({data})=>{
this.projectlist=data.data.map(e=>{
return {
label:e.name,
value:e.key
}
})
})
},
queryBtn(){
this.list = [];
this.queryDataList(true);

View File

@ -219,7 +219,7 @@ export default {
},
async getData() {
if (!this.filterParmas.device_id) {
this.$u.toast('没有关联基地')
// this.$u.toast('')
this.loadingType = 0
return (this.chartData = { series: [] })
}
@ -239,15 +239,19 @@ export default {
xAxis.push(key)
seriesData.push(resData[key])
})
const max = Math.max(...seriesData)
if (max > 5) {
let maxN = Math.ceil(max / 5) * 5
maxN = maxN === 0 ? 5 : maxN
this.opts.yAxis.data[0].max = maxN
} else {
this.opts.yAxis.splitNumber = max
}
// const max = Math.max(seriesData)
// console.log(seriesData);
// if (max > 5) {
// let maxN = Math.ceil(max / 5) * 5
// maxN = maxN === 0 ? 5 : maxN
// console.log(maxN);
// this.opts.yAxis.data[0].max = 100
// this.opts.yAxis.data[0].min = 0
// } else {
// console.log(max);
// this.opts.yAxis.splitNumber = max
// }
let res = {
categories: xAxis,

View File

@ -150,8 +150,8 @@ export default {
async getData(e) {
if (!e.device_id) {
this.mescroll.endByPage(0, 0)
return this.$u.toast('没有关联基地')
// this.$u.toast('')
return
}
try {
const { data } = await http.get(

View File

@ -8,20 +8,26 @@
></image>
</view>
<view class="content-box">
<view
class="menus-section"
v-for="(menu, index) in menus"
:key="index"
>
<view class="title-t" v-if="menu.parent && menu.children.length>0"
<view class="menus-section" v-for="(menu, index) in menus" :key="index">
<view class="title-t" v-if="menu.parent && menu.children.length > 0"
>{{ menu.parent }}-{{ menu.label }}</view
>
<view class="title-t" v-if="!menu.parent && menu.children.length>0">{{ menu.label }}</view>
<view class="title-t" v-if="!menu.parent && menu.children.length > 0">{{
menu.label
}}</view>
<view class="menu-ul">
<view class="menu-li" v-for="(cdm, i) in menu.children" :key="i">
<view class="menu_item" @click="linknavFn(cdm)">
<view class="icon"></view>
<view class="name">{{ cdm.label }}</view>
<view class="menu_item_content">
<view class="icon">
<image
class="icon_img"
v-if="cdm.icon"
:src="require(`@/static/img/${cdm.icon}`)"
></image>
</view>
<view class="name">{{ cdm.label }}</view>
</view>
</view>
</view>
</view>
@ -44,36 +50,43 @@ export default {
label: '气象监测',
url: '/pages/index/meteorological',
permission: 'endpoint.weather.index',
icon: 'moon-cloudy-line.png',
},
{
label: '智能监控',
url: '/pages/index/monitor',
permission: 'endpoint.camera.index',
icon: 'live-line.png',
},
{
label: '土壤监控',
url: '/pages/index/soil-monitoring',
permission: 'endpoint.soil.index',
icon: 'map-pin-range-line.png',
},
{
label: '水质监控',
url: '/pages/index/water-quality',
permission: 'endpoint.water.index',
icon: 'contrast-drop-line.png',
},
{
label: '昆虫性诱监测',
url: '/pages/index/insect-monitors',
permission: 'endpoint.insect.index',
icon: 'bug-line.png',
},
{
label: '虫情监测',
url: '/pages/index/pests',
permission: 'endpoint.worm_statics.index',
icon: 'bug-2-line.png',
},
{
label: '杀虫灯检测',
url: '/pages/index/insecticidal-lamp',
permission: 'endpoint.insecticidal_lamp.index',
icon: 'alarm-warning-line.png',
},
],
},
@ -85,16 +98,19 @@ export default {
label: '城镇数据',
url: '/pages/basics/town-base',
permission: 'endpoint.town_street.index',
icon: 'building-4-line.png',
},
{
label: '基地数据',
url: '/pages/basics/basics-base',
permission: 'endpoint.agricultural_basic.index',
icon: 'home-4-line.png',
},
{
label: '基地概况',
url: '/pages/basics/profile',
permission: 'endpoint.agricultural_base_overview.index',
icon: 'home-3-line.png',
},
],
},
@ -106,11 +122,13 @@ export default {
label: '城镇农作物',
url: '/pages/crop/town-crop',
permission: 'endpoint.town_crops.index',
icon: 'plant-line.png',
},
{
label: '基地农作物',
url: '/pages/crop/basics-crop',
permission: 'endpoint.crops.index',
icon: 'leaf-line.png',
},
],
},
@ -122,11 +140,13 @@ export default {
label: '城镇产量',
url: '/pages/yield/town-yield',
permission: 'endpoint.town_crops_output.index',
icon: 'box-1-line.png',
},
{
label: '基地产量',
url: '/pages/yield/basics-yield',
permission: 'endpoint.crops_output.index',
icon: 'instance-line.png',
},
],
},
@ -138,26 +158,31 @@ export default {
label: '稻虾价格',
url: '/pages/estate/estate-price',
permission: 'endpoint.rice_shrimp_prices.index',
icon: 'price-tag-3-line.png',
},
{
label: '稻虾每周价格',
url: '/pages/estate/estate-week-price',
permission: 'endpoint.rice_shrimp_weekly_prices.index',
icon: 'price-tag-2-line.png',
},
{
label: '稻虾产业',
url: '/pages/estate/estate-industry',
permission: 'endpoint.rice_shrimp_industries.index',
icon: 'collage-line.png',
},
{
label: '稻虾流向',
url: '/pages/estate/estate-flows',
permission: 'endpoint.rice_shrimp_flows.index',
icon: 'flow-chart.png',
},
{
label: '大宗物资',
url: '/pages/estate/estate-materiels',
permission: 'endpoint.materiels.index',
icon: 'shopping-basket-2-line.png',
},
],
},
@ -168,11 +193,13 @@ export default {
label: '设备管理',
url: '/pages/device/index',
permission: 'endpoint.device.index',
icon: 'robot-2-line.png',
},
{
label: '警报明细',
url: '/pages/device/warning',
permission: 'endpoint.warnings.index',
icon: 'feedback-line.png',
},
],
},
@ -181,10 +208,12 @@ export default {
},
computed: {
...mapGetters(['userInfo']),
menus(){
return this.filterAsyncRoutes(this.menuList, this.userInfo?.permissions_slug ?? [])
}
menus() {
return this.filterAsyncRoutes(
this.menuList,
this.userInfo?.permissions_slug ?? []
)
},
},
onLoad() {},
methods: {
@ -222,11 +251,11 @@ export default {
.banner-section {
.banner_img {
width: 100%;
height: 280rpx;
height: 427rpx;
}
}
.index-page {
background-color: #f8f8f8;
background-color: #EEEBFE;
.content-box {
padding-top: 30rpx;
padding-bottom: 150rpx;
@ -239,7 +268,7 @@ export default {
.title-t {
margin-bottom: 24rpx;
padding: 0 10rpx;
font-size: 28rpx;
font-size: 34rpx;
font-weight: bold;
}
}
@ -251,16 +280,40 @@ export default {
text-align: center;
padding: 0 10rpx;
margin-bottom: 18rpx;
.menu_item {
background-color: #fff;
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.15);
min-height: 90rpx;
border-radius: 8rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10rpx 15rpx;
height: 100%;
padding-top: 100%;
position: relative;
.menu_item_content {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 24%;
.icon {
width: 40rpx;
height: 40rpx;
.icon_img {
width: 100%;
height: 100%;
}
}
.name{
font-size: 24rpx;
margin-top: 14rpx;
}
}
}
}
}

View File

@ -149,7 +149,8 @@ export default {
},
async getData(e) {
if (!e.device_id) {
return this.$u.toast('没有关联基地')
// this.$u.toast('')
return
}
try {
const { data } = await http.get(

View File

@ -193,7 +193,8 @@ export default {
this.chatList = []
if (!this.filterParmas.device_id){
this.loadingType = 0
return this.$u.toast('没有关联基地')
// this.$u.toast('')
return
}
const { data } = await http.get('/api/monitoring-data', {
params: this.filterParmas,

View File

@ -415,7 +415,8 @@
let _data = data.data;
if(_data.length==0){
this.loadingType = 0
return this.$u.toast('没有关联基地');
// this.$u.toast('');
return
}
for(let item of _data){
item['label'] = item.name;

View File

@ -544,7 +544,8 @@ export default {
let _data = data.data
if(_data.length==0){
this.loading = 'nomore'
return this.$u.toast('没有关联基地')
// this.$u.toast('')
return
}
for (let item of _data) {
item['label'] = item.name

View File

@ -186,6 +186,25 @@
/>
</view>
</view>
<!-- PH -->
<view class="chart_section" v-if="chart_ph.isShow">
<view class="top_box">
<view class="tit">PH<text class="unit"></text></view>
<view class="name">{{addressName}}</view>
</view>
<view class="mb-20rpx">
<u-line></u-line>
</view>
<view class="cart_box">
<qiun-data-charts
v-if="loadingType!=0"
:loadingType="loadingType"
type="area"
:opts="opts"
:chartData="chart_ph"
/>
</view>
</view>
</template>
</view>
<!-- 设置预警值 -->
@ -270,6 +289,7 @@
chart_k:{},//
chart_n:{},//
chart_p:{},//
chart_ph:{},//ph
//
q_start_time:'',
q_end_time:'',
@ -303,6 +323,7 @@
n:'磷',
p:'钾',
k:'氮',
ph:'PH'
},
keyToUnit:{
temperature:'℃',
@ -311,6 +332,7 @@
n:'mg/kg',
p:'mg/kg',
k:'mg/kg',
ph:''
},
numberToString:{
1:'',
@ -444,7 +466,8 @@
let _data = data.data;
if(_data.length==0){
this.loadingType = 0
return this.$u.toast('没有关联基地');
// this.$u.toast('');
return
}
for(let item of _data){
@ -622,6 +645,7 @@
//end n
//start p
let res6 = {
isShow:!!chartInfo.p,
categories: chartInfo.p.categories,
series: [
{
@ -634,6 +658,23 @@
this.chart_p = JSON.parse(JSON.stringify(res6));
//end p
//start ph
let res7 = {
isShow:!!chartInfo.ph,
categories: chartInfo.ph?.categories,
series: [
{
name:'PH',
legendShape:'circle',
data: chartInfo.ph?.data,
}
]
};
this.chart_ph = JSON.parse(JSON.stringify(res7));
//end ph
}
}).catch(()=>{

View File

@ -164,6 +164,24 @@
/>
</view>
</view>
<!-- 氨氮 -->
<view class="chart_section" v-if="chart_nh3n">
<view class="top_box">
<view class="tit">氨氮<text class="unit">mg/L</text></view>
<view class="name">{{ addressName }}</view>
</view>
<view class="mb-20rpx">
<u-line></u-line>
</view>
<view class="cart_box">
<qiun-data-charts
:loadingType="loadingType"
type="area"
:opts="opts"
:chartData="chart_nh3n"
/>
</view>
</view>
<!-- PH -->
<view class="chart_section" v-if="chart_ph">
<view class="top_box">
@ -237,6 +255,7 @@
</view>
<scroll-view class="scroll-y" scroll-y="true">
<view class="form_cont">
<u-form v-for="(info, k) in formInfo" :key="k">
<view class="title2 u-border-bottom">{{ keyToName[k] }}</view>
<u-form-item
@ -334,6 +353,7 @@ export default {
chart_conductivity: {}, //
chart_chlorine: {}, //
chart_oxygen: {}, //
chart_nh3n: {}, //
chart_ph: {}, //PH
chart_temperature: {}, //
chart_turbidity: {}, //
@ -368,6 +388,7 @@ export default {
conductivity: '电导率',
chlorine: '氯',
oxygen: '氧气',
nh3n: '氨氮',
ph: 'PH',
turbidity: '浊度',
},
@ -376,6 +397,7 @@ export default {
conductivity: 'us/cm',
chlorine: 'mg/L',
oxygen: 'mg/L',
nh3n: 'mg/L',
ph: '',
turbidity: 'NTU',
},
@ -514,7 +536,8 @@ export default {
let _data = data.data
if (_data.length == 0) {
this.loadingType = 0
return this.$u.toast('没有关联基地')
// this.$u.toast('')
return
}
for (let item of _data) {
item['label'] = item.name
@ -677,6 +700,23 @@ export default {
}else{
this.chart_oxygen = null
}
//start nh3n
if (chartInfo.nh3n) {
let res7 = {
categories: chartInfo.nh3n.categories,
series: [
{
name: '氨氮',
legendShape: 'circle',
data: chartInfo.nh3n.data,
},
],
}
this.chart_nh3n = JSON.parse(JSON.stringify(res7))
}else{
this.chart_nh3n = null
}
//end
//start PH
if (chartInfo.ph) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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