320 lines
8.1 KiB
Vue
320 lines
8.1 KiB
Vue
<template>
|
||
<view class="page-container">
|
||
|
||
<scroll-view
|
||
scroll-y
|
||
class="list-scroll"
|
||
@scrolltolower="loadMore"
|
||
:style="{ height: scrollHeight + 'px' }"
|
||
lower-threshold="50"
|
||
scroll-with-animation
|
||
>
|
||
<view
|
||
v-for="(item, index) in listData"
|
||
:key="index"
|
||
:class="['list-item', { 'list-item-disabled': item.online === '离线' }]"
|
||
@tap="item.online !== '离线' && onItemTap(item)"
|
||
>
|
||
<view class="item-title">
|
||
<view class="title-text">{{ item.title }}</view>
|
||
<text :class="['tag','tag-status',{'tag-manual':item.status==='手动模式'}]" v-if="item.status">{{ item.status }}</text>
|
||
<text :class="['tag','tag-online',{'tag-offline':item.online==='离线'}]" v-if="item.online">{{ item.online }}</text>
|
||
</view>
|
||
|
||
<view class="item-subtitle">
|
||
{{ item.subtitle }}
|
||
</view>
|
||
|
||
<view class="item-tags">
|
||
<text class="tag tag-temp1">温度1: {{ item.temp1 }}℃</text>
|
||
<text class="tag tag-temp2">温度2: {{ item.temp2 }}℃</text>
|
||
<text class="tag tag-temp3">温度3: {{ item.temp3 }}℃</text>
|
||
<text class="tag tag-temp4">温度4: {{ item.temp4 }}℃</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="isLoading" class="loading-more">
|
||
<uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons>
|
||
<text>加载中...</text>
|
||
</view>
|
||
<view v-else-if="noMore" class="no-more">没有更多数据了</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
listData: [],
|
||
page: 1,
|
||
pageSize: 6,
|
||
isLoading: false,
|
||
noMore: false,
|
||
total: 20, // 模拟总条数
|
||
scrollHeight: 0
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.getListData()
|
||
// 计算滚动区域高度(适配不同设备,兼容rpx/px转换)
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
// 80rpx转px:适配不同屏幕密度,避免高度计算偏差
|
||
const topHeight = 80 * (systemInfo.windowWidth / 750)
|
||
this.scrollHeight = systemInfo.windowHeight - topHeight
|
||
},
|
||
onReady() {
|
||
// 页面渲染完成后再确认高度,避免小程序端高度计算不准
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
const topHeight = 80 * (systemInfo.windowWidth / 750)
|
||
this.scrollHeight = systemInfo.windowHeight - topHeight
|
||
},
|
||
methods: {
|
||
// 模拟获取列表数据
|
||
getListData(isRefresh = false) {
|
||
if (isRefresh) {
|
||
this.page = 1
|
||
this.noMore = false
|
||
this.listData = []
|
||
}
|
||
|
||
if (this.isLoading || this.noMore) return
|
||
|
||
this.isLoading = true
|
||
|
||
// 模拟接口请求
|
||
setTimeout(() => {
|
||
const start = (this.page - 1) * this.pageSize
|
||
const end = this.page * this.pageSize
|
||
const newData = []
|
||
|
||
for (let i = start; i < end && i < this.total; i++) {
|
||
// 新增:给每条数据加唯一id,优化v-for的key
|
||
newData.push({
|
||
id: `item-${i}`,
|
||
title: `设备名称${i + 1}`,
|
||
subtitle: `设备编号:SN-${10000 + i}`,
|
||
status: i % 2 === 0 ? "自动模式" : "手动模式",
|
||
online: i % 3 === 0 ? "在线" : "离线",
|
||
temp1: Math.floor(Math.random() * 51), // 0-50随机温度
|
||
temp2: Math.floor(Math.random() * 51),
|
||
temp3: Math.floor(Math.random() * 51),
|
||
temp4: Math.floor(Math.random() * 51)
|
||
})
|
||
}
|
||
|
||
this.listData = isRefresh ? newData : [...this.listData, ...newData]
|
||
this.page++
|
||
this.isLoading = false
|
||
|
||
if (this.listData.length >= this.total) {
|
||
this.noMore = true
|
||
}
|
||
}, 0)
|
||
},
|
||
// 加载更多(防抖:避免快速上拉重复触发)
|
||
loadMore() {
|
||
if (!this.isLoading && !this.noMore) {
|
||
// 延迟触发,避免滚动到底部瞬间多次调用
|
||
setTimeout(() => {
|
||
this.getListData()
|
||
}, 100)
|
||
}
|
||
},
|
||
// 点击列表项
|
||
onItemTap(item) {
|
||
uni.showToast({
|
||
title: `点击了:${item.title}`,
|
||
icon: 'none'
|
||
})
|
||
},
|
||
// 下拉刷新(可选)
|
||
onPullDownRefresh() {
|
||
this.getListData(true)
|
||
setTimeout(() => {
|
||
uni.stopPullDownRefresh()
|
||
}, 1000)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 适配小程序/H5的盒模型,避免padding导致宽度溢出 */
|
||
page {
|
||
box-sizing: border-box;
|
||
}
|
||
.page-container {
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
background: radial-gradient(circle at top left, #E8F4F8 40%, #F8FCFE 100%);
|
||
}
|
||
|
||
.list-scroll {
|
||
/* 把背景色改为透明,才能透出背景渐变 */
|
||
background-color: transparent;
|
||
border-radius: 8rpx;
|
||
overflow: hidden;
|
||
margin-top: 10rpx;
|
||
/* 新增:H5端避免滚动条样式不一致 */
|
||
scrollbar-width: thin;
|
||
}
|
||
/* H5端滚动条样式优化(可选) */
|
||
.list-scroll::-webkit-scrollbar {
|
||
width: 4rpx;
|
||
}
|
||
.list-scroll::-webkit-scrollbar-thumb {
|
||
background-color: #e0e0e0;
|
||
border-radius: 2rpx;
|
||
}
|
||
|
||
.list-item {
|
||
padding: 14rpx 30rpx;
|
||
/* 移除border-bottom,改为margin-top,并且把列表项背景设为半透明白色 */
|
||
margin-bottom: 20rpx;
|
||
background-color: rgba(255, 255, 255, 0.85);
|
||
border-radius: 12rpx;
|
||
/* 新增:点击态样式,双端统一 */
|
||
transition: all 0.2s ease;
|
||
box-shadow: 8rpx 5rpx 10rpx #999;
|
||
}
|
||
.list-item:active {
|
||
background-color: rgba(255, 255, 255, 0.95);
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.item-title {
|
||
font-size: 28rpx;
|
||
line-height: 52rpx;
|
||
font-weight: bolder;
|
||
color: #333;
|
||
/* 核心:flex布局,让文字和标签在同一行 */
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
.title-text {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
/* 在线标签样式 */
|
||
.tag-online {
|
||
font-size: 20rpx;
|
||
border-radius: 4rpx;
|
||
background-color: #f0f9eb;
|
||
color: #67c23a;
|
||
white-space: nowrap;
|
||
line-height: 30rpx;
|
||
/* 兜底:如果flex失效,用margin-left:auto强制居右 */
|
||
margin-left: auto;
|
||
display: inline-block; /* 确保样式生效 */
|
||
}
|
||
.tag-status.tag-manual {
|
||
background-color: #dde3f6;
|
||
color: #7491ef;
|
||
}
|
||
/* 离线:深灰色系 */
|
||
.tag-offline {
|
||
background-color: #f2f2f2;
|
||
color: #c5c3c3;
|
||
}
|
||
.item-subtitle {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 52rpx;
|
||
display: block;
|
||
}
|
||
|
||
.item-tags {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
flex-wrap: wrap; /* 新增:标签过多时换行,避免溢出 */
|
||
margin: 14rpx 0;
|
||
}
|
||
|
||
.tag {
|
||
font-size: 22rpx;
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 4rpx;
|
||
display: inline-block; /* 修复H5端padding不生效问题 */
|
||
}
|
||
.tag-status {
|
||
background-color: #f8f1f1;
|
||
color: #e66060;
|
||
margin-left: 20rpx;
|
||
font-weight: lighter;
|
||
line-height: 30rpx;
|
||
padding: 4rpx 6rpx;
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
.tag-temp1 {
|
||
background-color: #e8f4ff;
|
||
color: #409eff;
|
||
}
|
||
|
||
.tag-temp2 {
|
||
background-color: #fdf4e4;
|
||
color: #f5961d;
|
||
}
|
||
|
||
.tag-temp3 {
|
||
background-color: #f4f4f5;
|
||
color: #909399;
|
||
}
|
||
|
||
.tag-temp4 {
|
||
background-color: #e7faf4;
|
||
color: #1bd1a7;
|
||
}
|
||
|
||
.loading-more {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 30rpx;
|
||
color: #999;
|
||
font-size: 26rpx;
|
||
gap: 10rpx;
|
||
margin-top: 20rpx;
|
||
background-color: rgba(255, 255, 255, 0.85);
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.no-more {
|
||
/* 核心:flex布局实现居中 */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* 占满滚动容器剩余高度,保证垂直居中 */
|
||
min-height: 200rpx; /* 最小高度,避免内容太少时不居中 */
|
||
/* 文字样式保留 */
|
||
color: #999;
|
||
font-size: 26rpx;
|
||
/* 可选:增加上下内边距,视觉更舒适 */
|
||
padding: 30rpx 0;
|
||
margin-top: 20rpx;
|
||
background-color: rgba(255, 255, 255, 0.85);
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
/* 新增:禁用状态样式 */
|
||
.list-item-disabled {
|
||
/* 文字置灰 */
|
||
color: #999;
|
||
/* 禁用光标 */
|
||
cursor: not-allowed;
|
||
/* 背景色变浅,视觉区分 */
|
||
background-color: #fafafa;
|
||
/* 可选:添加透明度 */
|
||
opacity: 0.7;
|
||
}
|
||
|
||
/* 禁用状态下的子元素也置灰 */
|
||
.list-item-disabled .tag {
|
||
color: #ccc;
|
||
background-color: #f8f8f8;
|
||
}
|
||
</style> |