uniapp顶部滑块导航封装和内容块

1.顶栏滑块和swiper 案例:

<template>
	<view class="content">		
		<!-- 顶栏
			触摸变颜色
				changeTab(index)
			~~~~~~~~~~~~~~~~~~~~~~~~
			滑动scroll-view让顶栏跟着动
				:scroll-into-view='scrollIntoIndex'
					scrollIntoIndex为子元素的id值不能为0
				:id="'top'+index"
		-->
		<scroll-view scroll-x="true" class='scroll-content' :scroll-into-view='scrollIntoIndex'>
			<view
				:id="'top'+index"
				class='scroll-item'
				v-for='(item,index) in topBar'
				:key='index'
				@tap='changeTab(index)'
			>

				<text 
					:class='topBarIndex===index? 	
					"f-active-color":"f-color"'
				>{{item.name}}</text>

			</view>
		</scroll-view>
		
		<!-- 滑动栏
			点击scroll-view  切换 swiper-item内容
				@change='onChangeTab' :current="topBarIndex"
				当current改变,触发change事件
			~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			
		-->
		<swiper  @change='onChangeTab' :current="topBarIndex">
			<swiper-item 
				v-for='(item,index) in topBar'
				:key='index'
			>
				<view>{{item.name}}</view>
			</swiper-item>
		</swiper>
	
	</view>
</template>

<script>
	export default {
		data() {
			return {
				//选中的索引
				topBarIndex:0,
				//顶栏跟随的索引id值
				scrollIntoIndex:'top0',
				//顶栏数据
				topBar:[
					{name:'推荐'},
					{name:'运动户外'},
					{name:'服饰内衣'},
					{name:'鞋靴箱包'},
					{name:'美妆个护'},
					{name:'家居数码'},
					{name:'食品母婴'}
				]
			}
		},
		methods:{
			changeTab(index){
				if(this.topBarIndex === index){
					return ;
				}
				// 触摸,变颜色
				this.topBarIndex = index;
				// 滑动scroll-view让顶栏跟着动
				this.scrollIntoIndex = 'top'+index;
			},
			onChangeTab(e){
				// 点击scroll-view  切换 swiper-item内容
				this.changeTab(e.detail.current);
			}
		}
		
		
	}
</script>

<style lang="scss" scoped>
.scroll-content{
	width: 100%; 				//一定要
	height: 80rpx;
	white-space: nowrap;		//一定要,不换行,[不加没有后面内容]
	.scroll-item{
		display: inline-block;	//一定要
		padding:10rpx 30rpx;
		font-size:32rpx;
		.f-active-color{
			color:#1296db;	
			padding:10rpx 0;
			border-bottom:6rpx solid #49BDFB;
		}
	}
}
</style>

2.进阶版-顶栏滑块和swiper的案例

<template>
	<view class="content">	
		<!-- 顶栏
			触摸变颜色
				changeTab(index)
			~~~~~~~~~~~~~~~~~~~~~~~~
			滑动scroll-view让顶栏跟着动
				:scroll-into-view='scrollIntoIndex'
					scrollIntoIndex为子元素的id值不能为0
				:id="'top'+index"
		-->
		<scroll-view scroll-x="true" class='scroll-content' 
		:scroll-into-view='scrollIntoIndex'>
			<view
				:id="'top'+index"
				class='scroll-item'
				v-for='(item,index) in topBar'
				:key='index'
				@tap='changeTab(index)'
			>
				<text :class='topBarIndex===index? "f-active-color":"f-color"'
				>
				{{item.name}}</text>
			</view>
		</scroll-view>
		
		<!-- 滑动栏
			点击scroll-view  切换 swiper-item内容
				@change='onChangeTab' :current="topBarIndex"
				当current改变,触发change事件			
		-->
		<swiper  @change='onChangeTab' 
		:current="topBarIndex" 
		style="background-color: #007AFF;"
		:style="'height:' + clientHeight + 'px;'">
			<swiper-item 
				v-for='(item,index) in newTopBar'
				:key='index'
			>
				
				<!-- <view class='indexData'> 不用了,因为获取不到这个内容了-->
					<!-- 采用这个scroll-view,是为了可以触底加载,不是为了滑动 -->
					<scroll-view scroll-y="true" 
						:style="'height:' + clientHeight + 'px;'"
					>

						<view>这里面放数据</view>
						
					</scroll-view>
										
				<!-- </view> -->				
			</swiper-item>
		</swiper>
	</view>
</template>

<script>
	
	export default {
		data() {
			return {
				//选中的索引
				topBarIndex:0,
				//顶栏跟随的索引id值
				scrollIntoIndex:'top0',
				//顶栏数据
				topBar:[
					{name:'推荐'},
					{name:'运动户外'},
					{name:'服饰内衣'},
					{name:'鞋靴箱包'},
					{name:'美妆个护'},
					{name:'家居数码'},
					{name:'食品母婴'}
				],
				// 内容块的高度值
				clientHeight:0,
				// 承载数据
				newTopBar:[]
			}
		},
		
		onReady() {			
			// 获取可视区域的高度
			uni.getSystemInfo({
				success: (res) => {
					console.log(res);
					// ios是--有问题的,下面就兼容
					this.clientHeight = res.windowHeight - uni.upx2px(80)-this.getClientHeight();
				}
			})
		},

		methods:{
			changeTab(index){
				if(this.topBarIndex === index){
					return ;
				}
				// 触摸,变颜色
				this.topBarIndex = index;
				// 滑动scroll-view让顶栏跟着动
				this.scrollIntoIndex = 'top'+index;
			},
			
			onChangeTab(e){
				// 点击scroll-view  切换 swiper-item内容
				this.changeTab(e.detail.current);
			},
			
			//获取可视区域高度【兼容】
			getClientHeight(){
				const res = uni.getSystemInfoSync();
				const system = res.platform;
				if( system ==='ios' ){
					return 44+res.statusBarHeight;
				}else if( system==='android' ){
					// 如果安卓出现bug,就把这个变为0,或者去掉
					return 0;
					// return 48+res.statusBarHeight;
				}else{
					return 0;
				}			
			}
		}	
	}
</script>

<style lang="scss" scoped>
.scroll-content{
	width: 100%; 				//一定要
	height: 80rpx;
	white-space: nowrap;		//一定要,不换行,[不加没有后面内容]
	.scroll-item{
		display: inline-block;	//一定要
		padding:10rpx 30rpx;
		font-size:32rpx;
		.f-active-color{
			color:#1296db;	
			padding:10rpx 0;
			border-bottom:6rpx solid #49BDFB;
		}
	}
}
</style>

3.最终版-原装不动的版本+下拉加载[有数据的]

<template>
	<view class="content">
		<!-- 推荐的有IndexSwiper,Recommend[蓝底板块],Card[-文字-],LikeList[猜你喜欢]-->		
		<!-- <IndexSwiper></IndexSwiper>
		<Recommend></Recommend>
		<Card cardTitle='猜你喜欢'></Card>
		<LikeList></LikeList> -->
		
		<!-- 运动户外即其他板块 的有 Bannar , Icons , Hot[热销爆品] , Shop[推荐店铺] , LikeList[为您推荐{跟猜你喜欢一样}] -->
		<!-- <Banner></Banner>
		<Icons></Icons>
		<Card cardTitle='热销爆品'></Card>
		<Hot></Hot>
		<Card cardTitle='推荐店铺'></Card>
		<Shop></Shop>
		<Card cardTitle='为您推荐'></Card>
		<LikeList></LikeList> -->
		
		<!-- 顶栏
			触摸变颜色
				changeTab(index)
			~~~~~~~~~~~~~~~~~~~~~~~~
			滑动scroll-view让顶栏跟着动
				:scroll-into-view='scrollIntoIndex'
					scrollIntoIndex为子元素的id值不能为0
				:id="'top'+index"
		-->
		<scroll-view scroll-x="true" class='scroll-content' :scroll-into-view='scrollIntoIndex'>
			<view
				:id="'top'+index"
				class='scroll-item'
				v-for='(item,index) in topBar'
				:key='index'
				@tap='changeTab(index)'
			>
				<text :class='topBarIndex===index? "f-active-color":"f-color"'>{{item.name}}</text>
			</view>
		</scroll-view>
		
		<!-- 滑动栏
			点击scroll-view  切换 swiper-item内容
				@change='onChangeTab' :current="topBarIndex"
				当current改变,触发change事件			
		-->
		
		<swiper  @change='onChangeTab' 
		:current="topBarIndex" 
		:style="'height:' + clientHeight + 'px;'">
			<swiper-item 
				v-for='(item,index) in newTopBar'
				:key='index'
			>
				
				<!-- <view class='indexData'> 不用了,因为获取不到这个内容了-->
				
				<!-- 采用这个,是为了可以触底加载,不是为了滑动 -->
				<scroll-view 
					scroll-y="true" 
					:style="'height:' + clientHeight + 'px;'"
					@scrolltolower='loadMore(index)'
				>

					<block v-if='item.data.length>0'>
						<block v-for='(k,i) in item.data' :key='i'>
							
							<IndexSwiper v-if='k.type==="swiperList"' :dataList='k.data'></IndexSwiper>
							
							<template v-if='k.type==="recommendList"' >
								<Recommend :dataList='k.data'></Recommend>
								<Card cardTitle='猜你喜欢'></Card>
							</template>
							
							<Banner v-if='k.type==="bannerList"' :dataList='k.imgUrl'></Banner>
							
							<template v-if='k.type==="iconsList"' >
								<Icons :dataList='k.data'></Icons>
								<Card cardTitle='热销爆品'></Card>
							</template>
							
							<template v-if='k.type==="hotList"' >
								<Hot :dataList='k.data'></Hot>
								<Card cardTitle='推荐店铺'></Card>
							</template>
							
							<template v-if='k.type==="shopList"' >
								<Shop :dataList='k.data'></Shop>
								<Card cardTitle='为您推荐'></Card>
							</template>
							
							<LikeList v-if='k.type==="likeList"' :dataList='k.data'></LikeList>
							
						</block>
					</block>
					<block v-else>
						暂无数据...
					</block>
					
					<!-- 上拉加载的 -->
					<view class='load-text f-color'>
						{{item.loadText}}
					</view>
				</scroll-view>
										
				<!-- </view> -->
				
			</swiper-item>
		</swiper>
	
	</view>
</template>

<script>
	import IndexSwiper from '@/components/index/IndexSwiper.vue'
	import Recommend from '@/components/index/Recommend.vue'
	import Card from '@/components/common/Card.vue'
	import LikeList from '@/components/common/LikeList.vue'
	
	import Banner from '@/components/index/Banner.vue'
	import Icons from '@/components/index/Icons.vue'
	import Hot from '@/components/index/Hot.vue'
	import Shop from '@/components/index/Shop.vue'
	export default {
		components:{
			IndexSwiper,
			Recommend,
			Card,
			LikeList,
			Banner,
			Icons,
			Hot,
			Shop
		},
		data() {
			return {
				//选中的索引
				topBarIndex:0,
				//顶栏跟随的索引id值
				scrollIntoIndex:'top0',
				//顶栏数据
				topBar:[
					// {name:'推荐'},
					// {name:'运动户外'},
					// {name:'服饰内衣'},
					// {name:'鞋靴箱包'},
					// {name:'美妆个护'},
					// {name:'家居数码'},
					// {name:'食品母婴'}
				],
				// 内容块的高度值
				clientHeight:0,
				// 承载数据
				newTopBar:[]
			}
		},
		
		onReady() {
			
			/* 获取节点的信息
			如果这个元素内的是组件或者是渲染的话,是获取不到这个节点的!!这是一个坑
			所以这个就不用了
			*/
			// const query = uni.createSelectorQuery().in(this);
			// query.select('.indexData').boundingClientRect(data => {
			// 	// console.log(data); //得到这个节点的信息
			// 	this.clientHeight = 3000
			// }).exec();
			
			// 获取可视区域的高度
			uni.getSystemInfo({
				success: (res) => {
					// console.log(res);
					// ios是--有问题的,下面就兼容
					this.clientHeight = res.windowHeight - uni.upx2px(80)-this.getClientHeight();
				}
			})
		},
		
		onLoad() {
			this.__init()
		},
		methods:{
			changeTab(index){
				if(this.topBarIndex === index){
					return ;
				}
				// 触摸,变颜色
				this.topBarIndex = index;
				// 滑动scroll-view让顶栏跟着动
				this.scrollIntoIndex = 'top'+index;
				
				//每一次滑动请求不同的数据==》赋值first
				if( this.newTopBar[this.topBarIndex].load  ==='first'){
					this.addData();
				}
			},
			onChangeTab(e){
				// 点击scroll-view  切换 swiper-item内容
				this.changeTab(e.detail.current);
			},
			__init(){
				uni.request({
					url:'http://192.168.0.5:3000/api/index_list/data',
					success: (res) => {
						let data = res.data.data;
						// console.log(data)
						// topBar数据
						this.topBar = data.topBar;	
						// 首页数据的
						this.newTopBar = this.initData(data);
						// console.log(this.newTopBar)
					}
				})
			},
			// 转变请求过来的数据(这里是根据顶栏多少个,就多少个数组)
			initData(res){
				let arr = [];
				for(let i =0;i<this.topBar.length;i++){
					let obj = {
						data:[],
						load:"first", //这个是为了数据不重复加载
						loadText:"上拉加载更多..."
					}
					//获取首次数据
					if(i==0){
						obj.data = res.data;
					}
					arr.push(obj)
				}
				return arr;
			},
			//获取可视区域高度【兼容】
			getClientHeight(){
				const res = uni.getSystemInfoSync();
				const system = res.platform;
				if( system ==='ios' ){
					return 44+res.statusBarHeight;
				}else if( system==='android' ){
					// return 48+res.statusBarHeight;
					return 0;
				}else{
					return 0;
				}			
			},
			//滑动不同板块--请求不同数据
			addData(callback){
				//拿到索引
				let index = this.topBarIndex;
				//拿到id
				let id = this.topBar[index].id;
				//请求不同的板块的数据下拉刷新的
				let page = Math.ceil(this.newTopBar[index].data.length / 5) + 1; 
				//请求不同的数据
				uni.request({
					url:`http://192.168.0.5:3000/api/index_list/${id}/data/${page}`,
					success: (res) => {
						// 这个是为了滑动到没有接口的,抑制不会报错
						if(res.statusCode != 200){
							return;
						}else{
							let data = res.data.data;
							this.newTopBar[index].data = [...this.newTopBar[index].data,...data];
						}
					}
				})
				/*当请求结束后,重新赋值, 为了数据不重复加载
				this.newTopBar[index].data = [...this.newTopBar[index].data,...data];
				因为这个,每次滑动,都会重复加载数据的
				*/
				this.newTopBar[index].load='last';
				
				//上拉加载的
				if(typeof callback==='function'){
					callback();
				}
			},
			
			//上拉加载更多
			loadMore(index){
				
				this.newTopBar[index].loadText = '加载中...';
				//请求完数据 ,文字提示信息又换成【上拉加载更多...】
				this.addData(()=>{
					this.newTopBar[index].loadText = '上拉加载更多...';
				})
			}
		}	
	}
</script>

<style lang="scss" scoped>
.scroll-content{
	width: 100%; 				//一定要
	height: 80rpx;
	white-space: nowrap;		//一定要,不换行,[不加没有后面内容]
	.scroll-item{
		display: inline-block;	//一定要
		padding:10rpx 30rpx;
		font-size:32rpx;
		.f-active-color{
			color:#1296db;	
			padding:10rpx 0;
			border-bottom:6rpx solid #49BDFB;
		}
	}
}
</style>

最终版后端的数据:

//后端:首次推荐--第一次触底的数据
router.get('/api/index_list/1/data/2', function(req, res, next) {
	res.json({
		code:"0",
		data:[
			{
				type: "likeList",
				data: [{
						id: 1,
						imgUrl: "../../static/images/commodity/commodity1.jpg",
						name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
						pprice: "299",
						oprice: "659",
						discount: "5.2"
					}
				]
			}
		]
	})
})

// 后端:首页数据--推荐
router.get("/api/index_list/data", function(req, res, next) {
	res.send({
		"code": 0,
		"data": {
			topBar: [{
					id: 1,
					name: '推荐'
				},
				{
					id: 2,
					name: '运动户外'
				}
			],
			data: [{
					type: "swiperList",
					data: [{
							imgUrl: '../../static/images/swiper/swiper1.jpg'
						}
					]
				},
				{
					type: "recommendList",
					data: [{
							bigUrl: "../../static/images/children/Children.jpg",
							data: [{
									imgUrl: "../../static/images/children/Children1.jpg"
								},
							]
						},
						{
							bigUrl: "../../static/images/Furnishing/Furnishing.jpg",
							data: [{
								imgUrl: "../../static/images/Furnishing/Furnishing1.jpg"
								}
							]
						}
					]
				},
				{
					type: "likeList",
					data: [{
							id: 1,
							imgUrl: "../../static/images/commodity/commodity1.jpg",
							name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
							pprice: "299",
							oprice: "659",
							discount: "5.2"
						}
					]
				}
			]
		}
	})
});

// 后端:首页数据--运动户外
router.get('/api/index_list/2/data/1', function(req, res, next) {
	res.json({
		code: "0",
		data: [{
				type: "bannerList",
				imgUrl: "../../static/images/banner1.jpg"
			},
			{
				type: "iconsList",
				data: [{
						imgUrl: "../../static/images/icon/icons1.png",
						name: "运动户外"
					},
					{
						imgUrl: "../../static/images/icon/icons2.png",
						name: "运动户外"
					},
					{
						imgUrl: "../../static/images/icon/icons3.png",
						name: "运动户外"
					},
					{
						imgUrl: "../../static/images/icon/icons8.png",
						name: "运动户外"
					}
				]
			},
			{
				type: "hotList",
				data: [{
						id: 1,
						imgUrl: "../../static/images/hot/hot1.jpg",
						name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
						pprice: "299",
						oprice: "659",
						discount: "5.2"
					},
					{
						id: 2,
						imgUrl: "../../static/images/hot/hot2.jpg",
						name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
						pprice: "299",
						oprice: "659",
						discount: "5.2"
					}
				]
			},
			{
				type: "shopList",
				data: [{
						bigUrl: "../../static/images/shop/shop.jpg",
						data: [{
								id: 1,
								imgUrl: "../../static/images/shop/shop1.jpg",
								name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
								pprice: "299",
								oprice: "659",
								discount: "5.2"
							},
							{
								id: 2,
								imgUrl: "../../static/images/shop/shop2.jpg",
								name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
								pprice: "299",
								oprice: "659",
								discount: "5.2"
							},
							{
								id: 3,
								imgUrl: "../../static/images/shop/shop3.jpg",
								name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
								pprice: "299",
								oprice: "659",
								discount: "5.2"
							},
							{
								id: 4,
								imgUrl: "../../static/images/shop/shop4.jpg",
								name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
								pprice: "299",
								oprice: "659",
								discount: "5.2"
							}
						]
					}
				]
			},
			{
				type: "likeList",
				data: [{
						id: 1,
						imgUrl: "../../static/images/commodity/commodity1.jpg",
						name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
						pprice: "299",
						oprice: "659",
						discount: "5.2"
					},
					{
						id: 2,
						imgUrl: "../../static/images/commodity/commodity2.jpg",
						name: "大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008大姨绒毛大款2020年必须买,不买你就不行了,爆款疯狂GG008",
						pprice: "299",
						oprice: "659",
						discount: "5.2"
					}
				]
			}
		]
	})
});``
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端_蜡笔小新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值