移动端原生实现列表列固定横向滚动功能

功能介绍:

在移动端开发中,会用到列表作为信息展示方式,一般希望上下滚动时,可以固定表头,左右滚动时,可以固定最左列。

需求:

1、列表可以使用数组循环遍历;
2、上下滚动时,可以固定表头在最顶端显示;
3、左右滚动时,可以固定左边一列或多列可以固定显示;
4、列表的列宽允许在数组中设置;

思路:

1、页面使用四个dom元素分别存储四种元素:

1)固定在左上角,完全不参与滚动表头元素;
2)固定在顶部,只允许左右滚动表头元素;
3)固定在左侧,只允许上下滚动列元素;
4)右下角,左右上下均可随意滚动列元素;

2、表头数组与列表数据数组之间互相联系,表头属性可以控制列表列排序、列表宽度、是否为固定列等;

3、四个dom之间增加联动,使用@scroll、scrollLeft、scrollTop;

示意图:

列表固定滚动布局图

实现代码:

html代码:

<div class="table-box">
	<div class="listFlexSty">
		<div class="fixedHeadBox" :style="{width: fixedWid}">
			<div
				class="thClass"
				v-for="(item, index) in fixedHead"
				:key="index"
				:style="{width: item.width, justifyContent:item.name === '名称'?'flex-start':'',padding:item.name === '名称'?'0 10px':''}"
				@click="thItemClick(item)">
				<div>{{item.name}}</div>
				<div class="playIconSty">
					<div class="topArrow"></div>
					<div class="bottomArrow"></div>
				</div>
			</div>
		</div>
		<div
			class="nomalHeadBox"
			style="
				 {
					width: 'calc(100% - ' + fixedWid + ')';
				}
			">
			<div ref="nomalHeadBox" @scroll="scrollHList">
				<div class="thClass" :style="{width: nomalWid}">
					<div
						class="thClass"
						v-for="(item, index) in nomalHead"
						:key="index"
						:style="{width: item.width,padding:item.name === '折扣偏差'?'0 10px':''}"
						@click="thItemClick(item)">
						<div>{{item.name}}</div>
						<div class="playIconSty">
							<div class="topArrow"></div>
							<div class="bottomArrow"></div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div style="height: calc(100% - 40px); overflow: auto" id="dataBodyId">
		<div v-show="tBodyData.length!==0" class="listFlexSty">
			<div class="fixedListBox" :style="{width: fixedWid}">
				<div ref="fixedListBox" @scroll="scrollFList">
					<div class="rLineSty" v-for="(item, index) in tBodyData" :key="index">
						<div
							v-for="(it, inx) in fixedHead"
							:key="inx"
							:style="{width: it.width, justifyContent:it.name === '名称'?'flex-start':'',padding:it.name === '名称'?'0 10px':''}"
							class="thClass">
							<span v-if="it.prop === 'storeName' || it.prop === 'curDiscount'"
								>{{item[it.prop]}}</span
							>
							<span
								v-if="it.prop === 'orderAmount' || it.prop === 'diffAmount'"
								v-format="'#,##0.##'"
								>{{item[it.prop]}}</span
							>
							<span v-if="it.prop === 'completionRate'">{{item[it.prop]}}%</span>
							<span
								v-if="it.prop === 'yearEarlier'"
								:class="item[it.prop]<0?'downArrow':item[it.prop]>0?'upArrow':''"
								>{{item[it.prop]}}%</span
							>
							<span v-if="it.prop === 'diffDiscount'"
								>{{item[it.prop]>0?'+':''}}{{item[it.prop]}}</span
							>
						</div>
					</div>
				</div>
			</div>
			<div
				class="nomalListBox"
				ref="nomalListBox"
				:style="{width: 'calc(100% - '+fixedWid+')'}"
				@scroll="scrollList">
				<div
					class="rLineSty"
					:style="{width: nomalWid}"
					v-for="(item, index) in tBodyData"
					:key="index">
					<div
						v-for="(it, inx) in nomalHead"
						:key="inx"
						:style="{width: it.width,padding:it.name === '折扣偏差'?'0 10px':''}"
						class="thClass">
						<span v-if="it.prop === 'storeName' || it.prop === 'curDiscount'"
							>{{item[it.prop]}}</span
						>
						<span v-if="it.prop === 'orderAmount' || it.prop === 'diffAmount'" v-format="'#,##0.##'"
							>{{item[it.prop]}}</span
						>
						<span v-if="it.prop === 'completionRate'">{{item[it.prop]}}%</span>
						<span
							v-if="it.prop === 'yearEarlier'"
							:class="item[it.prop]<0?'downArrow':item[it.prop]>0?'upArrow':''"
							>{{item[it.prop]}}%</span
						>
						<span v-if="it.prop === 'diffDiscount'"
							>{{item[it.prop]>0?'+':''}}{{item[it.prop]}}</span
						>
					</div>
				</div>
			</div>
		</div>
		<div v-show="tBodyData.length>0 && !finished" class="bottomTip" @click="moreLoad">
			<span style="color: #999999">展开查看更多</span>
			<van-icon name="arrow-down" color="#999999" />
		</div>
		<div v-show="tBodyData.length>0 && finished" class="bottomTip">
			<span style="color: #999999">已加载完全部数据</span>
		</div>
		<div v-show="tBodyData.length===0" class="noData">暂无数据</div>
	</div>
</div>

js代码:

data(){
	return {
		// 下面是首页底部列表数据相关字段
		tHeadData: [
			{ name: '名称', prop: 'storeName', width: '100px', isfixed: true },
			{ name: '总业绩(元)', prop: 'orderAmount', width: '80px' },
			{ name: '平均折扣', prop: 'curDiscount', width: '80px' },
			{ name: '同比', prop: 'yearEarlier', width: '60px' },
			{ name: '完成率', prop: 'completionRate', width: '80px' },
			{ name: '缺口(元)', prop: 'diffAmount', width: '100px' },
			{ name: '折扣偏差', prop: 'diffDiscount', width: '80px' }
		],
		tBodyData: [],
		fixedHead: [],
		nomalHead: [],
		fixedWid: '',
		nomalWid: ''
	}
},

methods: {
	// 列表数据相关
	initData() {
		this.fixedHead = this.tHeadData.filter(item => {
			return item.isfixed;
		});
		this.nomalHead = this.tHeadData.filter(item => {
			return !item.isfixed;
		});
		this.initSize();
	},
	initSize() {
		let fwid = 0;
		let nwid = 0;
		this.fixedHead.forEach(item => {
			// 此处以px单位为例
			const len = item.width.length - 2;
			const width = item.width.substring(0, len) - 0;
			fwid += width;
		});
		this.nomalHead.forEach(item => {
			const len = item.width.length - 2;
			const width = item.width.substring(0, len) - 0;
			nwid += width;
		});
		this.fixedWid = fwid + 'px';
		this.nomalWid = nwid + 'px';
	},
	// 首页下方数据列表联动相关
	scrollHList() {
		this.$refs.nomalListBox.scrollLeft = this.$refs.nomalHeadBox.scrollLeft;
	},
	scrollFList() {
		this.$refs.nomalListBox.scrollTop = this.$refs.fixedListBox.scrollTop;
	},
	scrollList() {
		this.$refs.fixedListBox.scrollTop = this.$refs.nomalListBox.scrollTop;
		this.$refs.nomalHeadBox.scrollLeft = this.$refs.nomalListBox.scrollLeft;
	}
}


css代码:

.table-box {
	width: 100%;
	height: calc(100% - 80px);
	overflow: hidden;
}
.listFlexSty {
	display: flex;
}
.fixedHeadBox {
	height: 40px;
	line-height: 40px;
	color: #333333;
	font-size: 12px;
}
.nomalHeadBox {
	height: 40px;
	line-height: 40px;
	overflow: hidden;
	color: #333333;
	font-size: 12px;
}
.fixedListBox {
	height: 100%;
	overflow: hidden;
	color: #666666;
	font-size: 12px;
}
.nomalListBox {
	height: 100%;
	overflow: auto;
	color: #666666;
	font-size: 12px;
}
.thClass {
	display: flex;
	align-items: center;
	justify-content: flex-end;
}
.rLineSty {
	height: 34px;
	padding: 10px 0;
	display: flex;
}
.rLineSty > div {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	overflow: hidden;
}

/* 隐藏滚动条 */
/* 隐藏右边表格头部滚动条 */
.nomalHeadBox > div {
	overflow: auto;
	height: calc(100% + 10px);
}
/* 隐藏左边列表滚动条 */
.fixedListBox > div {
	overflow: auto;
	height: 100%;
	width: calc(100% + 10px);
}
.noDataNew {
	height: calc(100% - 40px);
	display: flex;
	align-items: center;
	justify-content: center;
	color: #999;
	font-size: 12px;
}

效果图:

列表固定滚动

注意: 代码里的方法thItemClick是列排序功能,与此文章无关,实现代码未贴出,除此之外,其他未贴出的代码均与此文章所讲功能无关,忽略即可。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现列表内容自动向上滚动的效果,可以使用原生的JavaScript来操作DOM元素和定时器。 首先,可以通过getElementById或querySelector等方法获取到包含列表内容的元素。 然后,通过获取元素的高度、内容等信息来判断是否需要滚动。 接着,可以利用定时器setInterval来不断改变元素的scrollTop属性值,实现滚动效果。 具体步骤如下: 1. 首先,获取到包含列表内容的元素: ```javascript var listContainer = document.getElementById("listContainer"); //或者使用querySelector根据CSS选择器选择元素: var listContainer = document.querySelector("#listContainer"); ``` 2. 判断是否需要滚动,比如当元素内容的高度大于元素本身的高度时才需要滚动: ```javascript if(listContainer.scrollHeight > listContainer.clientHeight){ // 需要滚动,执行后续操作 } ``` 3. 设置定时器,不断改变元素的scrollTop属性值,实现滚动效果: ```javascript var isScrolling = true; // 表示是否正在滚动 setInterval(function(){ if(isScrolling){ listContainer.scrollTop += 1; // 每次滚动1个像素,可根据需要调整滚动速度 if(listContainer.scrollTop === (listContainer.scrollHeight - listContainer.clientHeight)){ listContainer.scrollTop = 0; // 滚动到底部后,回到顶部 } } }, 50); // 每50毫秒滚动一次,可根据需要调整滚动速度 ``` 4. 可以添加一些事件来控制滚动的开始和停止,比如鼠标进入和离开时暂停和恢复滚动效果: ```javascript listContainer.onmouseover = function(){ isScrolling = false; // 鼠标进入时停止滚动 } listContainer.onmouseout = function(){ isScrolling = true; // 鼠标离开时恢复滚动 } ``` 以上就是用原生JavaScript实现列表内容自动向上滚动效果的基本步骤。根据具体需求,还可以进行一些定制和调整,比如添加缓动效果、点击按钮控制滚动等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值