前端小白系列(3)—— 分页

篇幅较长,废话不多说,直接开讲。

分页效果的具体思路可以参考博主的另一篇文章《分页效果实现》,其实最主要的思想就是在JS中传参进行递归,这点非常重要,有了这个思路其他代码便好写了。当然,这也只是提供一个参考方法。

上最终效果图

PC端

 

博主写分页功能的思路是先在HTML中写好a标签,然后写相关的样式和布局,再删掉HTML中的a标签,利用JS去动态生成。

按这个思路来走。先贴上最终的HTML代码

<!-- Part one     Pagination -->
		<section id="page-stage">
			<div class="show">
				<p class="page-num">- 1 -</p>
			</div>

			<div class="pagination-wrap">
				<nav class="pagination"></nav>
			</div>
		</section>
page-stage是展示整个分页效果的区域,show则是点击页数按钮后显示内容(此处只是改变page-num的 值以做模拟)的地方,pagination-wrap是包裹页数按钮的区域,pagination里则会生成作为按钮显示的a标签。


LESS的代码

/* --------------------- 分 页 ------------------------ */
#page-stage{
	/* 1.宽度设为百分比,流式布局,自适应宽度
	   2.配合left和margin-left实现居中*/
	width: 90%; 
	position: absolute;
	left: 50%;
	margin-left: -45%;
	display: none;
	.show{
		height: 80%;
		margin-top: .3rem;
		background: -webkit-linear-gradient(left top,@red,@orange,@yellow,@green,@blue,@indigo,@violet);
		background: linear-gradient(left top,@red,@orange,@yellow,@green,@blue,@indigo,@violet);
		/*opacity的兼容IE写法*/
		opacity: .7;
		filter: alpha(opacity=70);
		border-radius: .15rem;
		box-shadow: 0 0 2rem white inset;
		.page-num{
			position: relative;
			top: 45%;
			text-align: center;
			font-size: 40px;
			color: lighten(@red,20%);
		}
	}
	.pagination-wrap{
/*-------根据内容自适应调整宽度的盒子,因宽度不明,需利用translate来居中----------*/
		display: inline-block;
		position: absolute;
		left: 50%;
		-webkit-transform: translate(-50%,.2rem);
		        transform: translate(-50%,.2rem);
/*------------------------------------------------------------------------------*/
	}
}
/* 大页面时的分页,即@media (min-width: 768px)时,采用flex布局,要注意浏览器兼容 */
	#page-stage{
		height: 3.5rem;
		.pagination-wrap .pagination{
			/* width设为100%以通过内容撑开父级 */
			width: 100%;
			height: .4rem;
			/*flexbox需添加浏览器前缀*/
			display: -webkit-box;
			display: -ms-flexbox;
			display: flex;
			-ms-flex-pack: distribute;
			    justify-content: space-around;
	        -webkit-box-align: center;
	            -ms-flex-align: center;
	                align-items: center;
			padding: 0 .08rem;
			background-color: rgb(91,137,150);
			border-radius: 5px;
			box-shadow: 3px 5px 1px rgb(61,101,111);
			a{
				height: .25rem;
				line-height: .25rem;
				padding: 0 .1rem;
				/* margin-right需设置合适值,否则文字会溢出 */
				margin-right: .08rem;
				box-shadow: 2px 3px 1px rgb(128,176,188);
				font-size: 16px;
				border-radius: 5px;
				/* transition需添加前缀 */
				-webkit-transition: 0.2s;
				transition: 0.2s;
				/* 此处调用设置按钮的mixin */
				.btnColor(black,rgb(158,206,220));
				&:hover{
					color: white;
					background-color: rgb(185,222,232);
				}
				&:last-child{
					margin-right: 0;
				}
			}
		}
	}

/*小页面时的按钮*/
	#page-stage{
		height: 3rem;
		margin-top: .2rem;
		/* 将包裹层做成一个按钮的形状,不需要另外在HTML里写多一个button */
		.pagination-wrap{
			width: 1rem;
			height: .4rem;
			cursor: pointer;
			background: linear-gradient(black,white);
			background: -webkit-linear-gradient(black,white);
			box-shadow: 0 0 25px white;
			.pagination{
				/*设置bottom为100%,使整个列表能放在按钮上方*/
				position: absolute;
				bottom: 100%;
				display: none;
			    a{
					/* 将按钮分列展示,因页面宽度不够而放弃flex布局 */
					display: block;
					width: 1rem;
					height: .25rem;
					line-height: .25rem;
					font-size: 16px;
					text-align: center;
					font-size: 16px;
					/* outline效果与border类似 */
					outline: 1px solid white;
					border-radius: 5px;
					.btnColor(black,rgb(158,206,220));
					&:hover{
						color: white;
						background-color: rgb(185,222,232);
					}
				}
			}
			/*因为按钮是一个包裹层,所以利用伪元素为按钮添加内容,设置好定位将内容居中于按钮*/
			&::before{
				content: "Pages";
				font-size: 26px;
				color: darken(aqua,10%);
				position: absolute;
				top: 50%;
				left: 50%;
				-webkit-transform: translate(-50%,-50%);
				        transform: translate(-50%,-50%);
			}
			&:hover{
				box-shadow: 0 0 25px black;
				&::before{
					color: lighten(aqua,10%);
				}
			}
		}
	}
一个看起来很简单的效果,其实CSS写起来也不容易。因为需要做响应式,基本上就是两套不同的解决方案了,所以我们需要在尽量不增加多余HTML代码的情况下,尽量利用有限的资源,去找出两者的异同,将相同的代码共用,不同的地方才写进媒体查询的代码之中。

博主写LESS的时候其实也花了些时间,别看CSS简单,写起来可能会让你很头疼。上面LESS的代码有做了基本的注释,可以帮助大家理解,重点说说一些值得说的。

比如,博主一开始没给pagination写包裹层,然后想让其根据内容(a标签)来自适应自身宽度,结果一番挣扎后才放弃抵抗,加多了个包裹,并设置pagination的宽度100%来撑开父元素,才实现了想要的效果。

还有就是在小页面时,博主希望pagination能显示在包裹层的上方,一开始直接想到的是margin-top:负值来写,但这样便写死了,而pagination里的a标签个数是不固定的,后来才利用了bottom:100%这个小技巧。

所以CSS简不简单可不是自己觉得就算的,亲自去实践下才有切身体会。


好了,讲完LESS是时候见见我们的老朋友JS了。

让我们再来回忆下一些编写准则:尽量少全局;不必要的变量或函数私有化;代码兼容;模块化……

大家应尽可能的去接近这些准则(博主个人愚见)。


分页的JS交互主要是通过点击事件来触发相关元素的展示和隐藏。

先补上两个和分页有关的函数,封装在了全局的一个变量中

/*
		作用:根据参数创建内容为相关数字的按钮
		参数:obj,父级元素名称
		      ctx,按钮内容,可分为数字和文字两种
		      num, 多少个按钮
		      link,链接的页面
	*/
	createPageBtn : function(obj,ctx,num,link) {
		var obj = obj || document,
			aPage = null,
			link = link || null;
		if(typeof ctx === "number") {
			for (var i = ctx; i <= num + ctx - 1; i++) {
				aPage = document.createElement("a");
				aPage.setAttribute("href","#" + i);
				aPage.appendChild(document.createTextNode(i));
				obj.appendChild(aPage);
			}
		} else if(typeof ctx === "string") {
			aPage = document.createElement("a");
			aPage.setAttribute("href","#" + link);
			aPage.appendChild(document.createTextNode(ctx));
			obj.appendChild(aPage);
		}
	},

	/*
		作用:分页功能里的回调函数。分页的点击事件的相关内容处理
		参数:点击的页面的href值
	*/
	showPageContent : function(index) {
		var oPageNum = myFn.getByClass("page-num")[0];
		oPageNum.innerHTML = "-" + index + "-";
	}
按照程序跑的流程来展示下分页的代码。页面加载完毕会执行分页效果的加载(还需通过点击导航的分页按钮才能进行显示),其中component.pagination便是利用component中提供的接口去调用里面的函数的,体现了模块化和私有化的思想。

window.onload = function() {
	component.navbar();
	component.pagination({
		id : "page-stage",
		num : 10,
		now : 1,
		callBack : function(num) {
			myFn.showPageContent(num);
		}
	});
}
上面的函数传参了个对象,送进了下面这个函数

/*------------------------------------------------- 分页 -----------------------------------------------------*/ 
	var pagination = function(opt) {
		if(!opt.id) {return;}
		else {
			var allNum = opt.num || 5,
				nowNum = opt.now || 1,
				callBack = opt.callBack || function() {};

			var	showPage = (function() {
				var doc = document,
					oStage = doc.getElementById(opt.id),
					oPagination = myFn.getByClass("pagination",oStage)[0],
					oPageList = doc.createDocumentFragment(); //添加按钮的片段
					
				/*
					分页思路:1.最重要的思想是传递点击的当前页面的页数进行函数递归
						  2.通过当前页和总页数的相互关系来创造相应按钮,并给href赋值
				*/
				if(nowNum >= 4 && allNum >= 6) { //创建首页按钮条件:当前页大于3,总页数大于5
					myFn.createPageBtn(oPageList,"首页",1,1);
				}
				if(nowNum >= 2) { //创建上一页条件;当前页大于1
					myFn.createPageBtn(oPageList,"上一页",1,nowNum - 1);
				}
				if(allNum <= 5) { //总页数小于5,则直接创建相应按钮数
					myFn.createPageBtn(oPageList,1,allNum);
				} else { //总页数大于5则分以下情况
					if(nowNum < 3) { //当前页为1或2时,保持按钮仍为1-5
						myFn.createPageBtn(oPageList,1,5);
					} else if(nowNum > allNum - 3) { //当前页为总页数-1或总页数-2时,保持总页数-4至总页数
						myFn.createPageBtn(oPageList,allNum - 4,5);
					} else { //其他情况则让当前页的按钮处于中间
						myFn.createPageBtn(oPageList,nowNum - 2,5);
					}
				}
				if(nowNum < allNum) { //创建下一页条件:当前页小于总页数
					myFn.createPageBtn(oPageList,"下一页",1,nowNum + 1);
				} 
				if(nowNum <= allNum - 3 && allNum >= 6) { //创建尾页条件:当前页小于总页数-2,总页数大于5
					myFn.createPageBtn(oPageList,"尾页",1,allNum);
				}
				
				oPagination.appendChild(oPageList);

				callBack(nowNum); //执行回调函数

				//按键点击
				var clickBtn = (function() {
					var allBtn = oPagination.getElementsByTagName("a"),
						len = allBtn.length;
					for (var i = 0; i < len; i++) {
						myFn.addHandler(allBtn[i],"click",function() {
							var newNum = parseInt(this.getAttribute("href").substring(1)); //获取点击页的href的数值

							oPagination.innerHTML = ""; //清空按钮
							//重新传参来递归
							pagination({
								id : "page-stage",
								num : allNum,
								now : newNum, //传入新的当前页
								callBack : callBack
							})
						})
					}
				})()
			})() //shouPage
		}
	} //pagination

重要的地方都做了注释,逻辑也不难理解,需注意的是函数最后的重新传参来进行递归处理,这样便可以通过判断点击的按钮来重新生成新的显示的页数,还有就是点击后的内容展示是通过callback来实现的。

当然,只是上面这些还不够,毕竟我们还要写响应式的小页面点击事件,这又是另一回事了。

上一篇文章中,我们通过onresize事件来判断页面大小,而分页效果的小页面事件处理当然也离不开它。

window.onresize = function() {
	var oEleWidth = Math.floor(document.documentElement.clientWidth); //获取屏幕宽度
	if(oEleWidth < 768) {
		component.navbar.resNavbar.showNavbar();
		component.pagination.resPage.showResPage();
	} else {
		component.navbar();
		component.navbar.resNavbar.hideNavbar();
		component.pagination.resPage.hideResPage();
	}
}

其中的component.pagination的相关函数便是和分页响应式有关的。因为都是属于分页的功能,博主便将响应式的处理写成了pagination的一个属性。

//因为是属于分页功能里的响应式按钮事件,所以封装成pagination的子对象。将共用的变量直接拿出来,通过this来引用
	pagination.resPage = {
		oPagination : myFn.getByClass("pagination")[0],
		oPageWrap : myFn.getByClass("pagination-wrap")[0],
		showResPage : function() {
			var oPagination = this.oPagination;
			oPagination.style.display = "none";
			this.oPageWrap.onclick = function() {
				oPagination.style.display = (myFn.getStyle(oPagination,"display") === "none") ? "block" : "none";
			}
		},
		hideResPage : function() {
			this.oPageWrap.onclick = function(){return;};
			this.oPagination.style.cssText = "display: -webkit-box;display: -ms-flexbox;display: flex;";
		}
	}
当页面从小页面转回大页面时,不仅需要换回原先的样式,还得把一些点击事件给取消掉(return;),才不会出现大页面的点击也会触发相关样式改变。


不知看到这里的你是否有些懵圈了呢?很正常,因为上面可能就只是95.27%的代码,你可能需要去http://github.com/Lagre 的componentDemo项目中找那剩下的代码,以帮助你理清思路。


分页到此就结束啦,希望大家多加练习,巩固好自己的编程技能和思维。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值