欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

仿百度新闻首页

程序员文章站 2022-06-30 20:42:33
...

偶尔在网上看到百度新闻的效果很炫、就自己粗略的仿制一下效果、效果地址:http://news.baidu.com/n?cmd=1&class=reci#0

先说下思路:1、我们可以发现 里面所有的块是由一个个小的单元组成的、最大的总共两个 有四个小单元加间距组成  横着和竖着的是由两个小单元组成

2、这些大的单元 总数是固定的 (这些大的多了也会不怎么美观) 所有单元的位置都是随机的

3、当滚动鼠标的时候  所有单元的位置会再一次的随机分配、窗口大小改变的时候 会重新计算基本单元的 宽度  当点击导航的时候会重新加载数据

4、我设计的 每一排可放的 小单元的个数是可变的 (可选参数  默认为6个) 这里我们设计的 总共有四排 (这样做 主要是想 整个页面是一屏 不会出现滚动条是最好)

5、首先计算出 小单元的数量 (4*你传的个数) 然后根据 我们放这些 单元的盒子 的宽度  计算出单元的宽度 和 高度(默认为宽度的65%) 同事计算出总数的坐标(这里的坐标是以可以放多少个小单元的数量为准的 )

这里是关键  是后面怎么使用这些坐标  而且是随机的    我的思路如下(有更好的思路欢迎交流):

1、我是用两个对象 一个是保存单元总数的对象(包含每个坐标的信息)如下图:

仿百度新闻首页


一个是保存上面对象 key值得数据:

仿百度新闻首页

这个数组  主要是用来去随机数的  然后根据随机数 对应的值 去取上面对象里面的 值  ( 这个值就包含我们需要的 坐标)


2、第二点就是怎么取坐标值  因为我们要把我们的每一个单元 全部都放在 我们的盒子里面  而且刚好占满我们的 盒子 不多不少 当然也不能重叠、因此先放最小的肯定是不行的因为我们的位置是随机的,因此我们先把大一点的单元搞定  

3、我们每次在取坐标的时候  我们要判断(最小的单元就不需要了 随便放)这个单元的类型 然后它占的坐标全部从我们上面的辅助的数组中清空(这里注意:不能把这个位置删掉,还记得我们第一张图上面的index属性吗? 如果删掉就会找不到对应的值了 使用数组的splice方法把对应的值为空就可以了 后面 我们做一下判断 如果为空 就重新取值就好了)

基本上就是这三点核心 其它的我们来看代码吧(这个效果图不好放  大家有兴趣复制一下 看下效果):

html:

<div class="box">
		
		<ul class="naver">

			<li class="naver-l active">导航一</li>
			<li class="naver-l">导航二</li>
			<li class="naver-l">导航三</li>
			<li class="naver-l">导航四</li>
			<li class="naver-l">导航五</li>

		</ul>

		<div class="container" style="height: 500px">
			

			
		</div>

	</div>

css:

*{margin:0;padding:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-o-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}body,html{width:100%;overflow-x:hidden;color:#4d4d4d;font:14px/1.5 "Helvetica Neue",Helvetica,Arial,"Microsoft Yahei","Hiragino Sans GB","Heiti SC","WenQuanYi Micro Hei",sans-serif}body{-webkit-tap-highlight-color:rgba(255,0,0,0.5);-webkit-font-smoothing:antialiased;background-color:#fff}a{text-decoration:none}img{display:block;width:100%;vertical-align:middle}ul,li{list-style:none}.box{width:80%;overflow:hidden;margin:20px auto}.naver{width:100%;height:60px;padding:1px}.naver .naver-l{float:left;height:100%;line-height:58px;margin:0 1px;padding:0px 15px;font-size:16px;font-family:500;cursor:pointer}.naver .naver-l:hover{background-color:#ccc}.naver .naver-l.active{background-color:pink}.container{width:100%;overflow:hidden;clear:both;position:relative;margin-top:20px}.c-item{position:absolute;overflow:hidden;-webkit-transition:all 1s;-o-transition:all 1s;-moz-transition:all 1s;transition:all 1s;cursor:pointer;font-size:24px}.c-item .item-m{font-size:18px;width:100%;height:100%;position:absolute;left:0px;top:-100%;background-color:#000;filter:Alpha(opacity=70);-moz-opacity:.7;opacity:.7;color:#fff;-webkit-transition:all .2s;-o-transition:all .2s;-moz-transition:all .2s;transition:all .2s}.c-item:hover .item-m{top:0px}
/*# sourceMappingURL=nav-list.css.map */

javascript:

1、方法的调用:

new NavList({

	container: document.querySelector(".container"),//放小单元的盒子

	navigation: document.querySelectorAll(".naver-l"),//导航栏

	adaptation: true,//是否自适应屏幕大小

	line_num: 7,//每行显示的小单元个数
});
2、方法的思路:首先:根据页面大小 创建我们所需要的 各种单元的集合对象 append 进入页面中 可以给一个初始的left and top (不然的话 后面 计算left top的时候 就没有动画效果了);其次就是为 改变每一单元的属性值了

3、javascript代码 (有点长  不好的地方希望多交流):

;(function(win,doc){

	var NavList;

	NavList = (function(){

		function NavList(options){

			this._pNode = options['container'] || '',//盒子元素

			this._adaptation = options['adaptation'] || true,//是否自适应

			this._navigation = options['navigation'] || '',

			this._line_num = options['line_num'] || 6,//每一行展示 单元的数量  默认为四行

			this._offset = 5,//单元之间的间距

			this._minUnit = '',//储存最小单元的width height

			this._w_Unit = '',//储存 width*2的单元

			this._h_Unit = '',//储存 height*2的单元

			this._w_h_Unit = '',//储存 height*2 width*2 的单元

			this._unit_obj = [],//储存所有单元的info  

			this._unit_dom = [],//储存创建好的dom 元素

			this._unit_pos = '',//储存每个小单元的坐标

			this._pos_arr = [],//用于计算的每个小单元的坐标

			this._pos_value = '',//创建dom节点的时候 获取到的每个坐标值

			this._unit_pos_obj = '',//储存每个小单元的坐标

			this._pNode_width = '',//盒子的宽度

			this._count = 0,

			this.init();//页面初始化
		}

		return NavList.prototype.init = function(){

			var _pNode = this._pNode;

			if(!_pNode || _pNode.nodeType != 1 ) return false;

			if( this._adaptation ) {

				this.addEvent(win,"resize",this.pnodeResizeHandler,false);
			}

			if( !!this._navigation ){

				Array.prototype.forEach.call(this._navigation,(item)=>{

					this.addEvent(item,"click",this.navClickHandler,false);
				})
			}

			this.addEvent(win,"mousewheel",this.mouseWheelHandler,false);

			/**
			 * 功能页面初始化  如果是开发的话  我们也可以在初始化的时候加载数据  然后再初始化页面
			 */
			
			this.dataInitHandler();

			console.log("NavList 初始化完成");
		},
		NavList.prototype.showDomHandler = function(_obj,i){

			if(!_obj) return false;

			this._unit_dom.push( this.singleDom( {

				"name": "div",
				"cl": _obj[i]['type'] == 'm' ? "c-item c-itme_m" : ( _obj[i]['type'] == 'w' ? "c-item c-itme_w" : (_obj[i]['type'] == 'h' ? "c-item c-itme_h" : "c-item c-itme_wh") ),
				"attr": {
					"style": `height: ${_obj[i]['height']}px;width: ${_obj[i]['width']}px;background-color: ${this.getColorHandler()};left: 45%;top: 0px;`,
				}
			} ) )


			this._unit_dom[i].appendChild( this.singleDom( {

				"name": "span",
				"_html": "这是一个元素" + i
			} ) )

			this._unit_dom[i].appendChild( this.singleDom( {

				"name": "div",
				"cl": "item-m",
				"_html": "这是一个元素" + i + "的子元素"
			} ) )


			this._pNode.appendChild( this._unit_dom[i] );
		},
		NavList.prototype.randomSortHandler = function(_arr){

			var _len = _arr.length,_random;

			if(_len == 0) return false;

			_random = parseInt( Math.random()*(_len-1) );

			this._pos_arr.push( _arr[_random] );

			_arr.splice(_random,1)

			arguments.callee.call(this,_arr);

		},
		NavList.prototype.changePosHandler = function(_pos_arr){

			/**
			 * 在创建dom 之前对 this._unit_pos 坐标 和 this._unit_obj 进行随机排序
			 */
			var _this = this;
			
			this._pos_arr = [];
						
			this.randomSortHandler(_pos_arr);

			this._pos_arr.forEach( function(item,index){

				_this._unit_pos_obj[item]['index'] = index;

			} )
		},
		NavList.prototype.createDomHandler = function(_pos_arr){

			var _obj = this._unit_obj,_this = this;

			this.changePosHandler(_pos_arr);

			for(let i=0,len=_obj.length;i<len;i++){

				this.showDomHandler(_obj,i);

			}

			setTimeout(()=>{

				try {

					this.changeUnitHandler(this);

				} catch(e) {

					alert("哎呀 发生错误了 我要重新加载数据了");
					
					this.dataInitHandler();

				}

			}, 25)


		},
		NavList.prototype.dataInitHandler = function(){

			this._pNode.innerHTML = '';

			this._unit_dom = [];

			this._unit_pos = [];

			this._unit_obj = [];

			/**
			 * 获取 页面的width  
			 * 
			 * 计算 我们空间内可以放的 色块的个数
			 *
			 * 调整 我们的距离 width
			 */
			var _pNode = this._pNode,_pNode_width = _pNode.offsetWidth,_single_w = _pNode_width/this._line_num - this._offset;

			this._minUnit = {

				type: "m",

				width: parseInt(_single_w),

				height: parseInt((_single_w*0.65)),
			}

			/**
			 * 基础单元出来之后 获取所有类型的单元
			 */
			
			this._w_Unit = {

				type: "w",

				width: this._minUnit['width']*2 + this._offset,

				height: this._minUnit['height']
			}

			this._h_Unit = {

				type: "h",

				width: this._minUnit['width'],

				height: this._minUnit['height']*2 + this._offset
			}

			this._w_h_Unit = {

				type: "wh",

				width: this._minUnit['width']*2 + this._offset,

				height: this._minUnit['height']*2 + this._offset
			}

			/**
			 * 我们这里默认的是四行  可以传参数 但是不能低于四行 总共 this._line_num * 4 个小单元
			 *
			 * 减去 2*4 - 6*2  剩下的小单元为  this._line_num * 4 - 20;
			 */
			
			var _unc = this._line_num * 4 - 2*4 - 6*2;
			
			for(let i=0;i<4;i++){

				if( i < 2 ){

					this._unit_obj.push( this._w_h_Unit );

					this._unit_obj.push( this._w_Unit );

				}

				this._unit_obj.push( this._h_Unit );

			}

			while(_unc--){

				this._unit_obj.push( this._minUnit );
			}

			// console.log(this._unit_obj);
			

			/**
			 * 所有单元出来之后 先获得我们所有的坐标点  然后创建dom结构
			 */
			
			this.getPositionHandler();

			var _arr = this._unit_pos,_pos_arr = [];

			for(let i=0,len=_arr.length;i<len;i++){

				_pos_arr[i] = _arr[i];
			}
			
			this.createDomHandler(_pos_arr);
			

			// console.log(this._w_h_Unit);
		},
		NavList.prototype.getPositionHandler = function(){

			var _num = this._line_num,_obj = {},_left,_top = this._offset,_line = '0',_arr = [],_index = 0;//默认的为4行

			for(let i = 1; i<= 4; i++){

				_line = i + '';

				_left = 0;

				_top = (this._offset + this._minUnit['height'])*(i-1);

				for(let j=0;j<_num;j++){

					_left = ( this._minUnit['width'] + this._offset )*j;

					_arr.push(_line+_left);

					_obj[_line+_left] = {"left": _left,"top": _top,"index": _index++,"_line": _line};//保存每一个坐标
				}
			}

			this._unit_pos_obj = _obj;

			this._unit_pos = _arr;

			console.log(_arr);

			// console.log(_obj);

		},
		NavList.prototype.pnodeResizeHandler = function(_this,el){

			clearTimeout(_this._resize_timer);

			_this._resize_timer = setTimeout(function(){

				_this.dataInitHandler();

			}, 200)

		},
		NavList.prototype.changeUnitHandler = function(_this,type){

			/**
			 * type = true  则改变 小单元的值
			 */
			
			var _c_items = _this._pNode.querySelectorAll(".c-item"),_arr = _this._unit_pos,_pos_arr = [];

			_this._count = 0;

			for(let i=0,len=_arr.length;i<len;i++){

				_pos_arr[i] = _arr[i];
			}

			_this.changePosHandler(_pos_arr);

			Array.prototype.forEach.call(_c_items,function(item,index){

				_this.getRandomHandler( _this._unit_obj[index]['type'] );

				item.style.top = _this._pos_value['top'] + "px";

				item.style.left = _this._pos_value['left'] + "px";
			})

		},
		NavList.prototype.mouseWheelHandler = function(_this,el){

			/**
			 * 打乱 单元的位置
			 */
			
			try {

				_this.changeUnitHandler(_this);

			} catch(e) {

				alert("哎呀 发生错误了 我要重新加载数据了");
				
				_this.dataInitHandler();

			}
			

		},
		NavList.prototype.navClickHandler = function(_this,el){

			var _cl_name = el.className;

			if(_cl_name.indexOf("active") != -1) return false;

			el.parentNode.querySelector(".active").className = _cl_name;

			_cl_name += " active";

			el.className = _cl_name;

			/**
			 * 这里改变 单元的值 同时重新 计算坐标
			 */
			_this.dataInitHandler();


		},
		NavList.prototype.getRandomHandler = function(_type){

			var _len = this._pos_arr.length,_obj3,_obj1,_obj2,_random,_pos,_index3,_index1,_index2;

			if(!_len) return false;

			_random = this._count++;

			if(this._count == _len){

				this._count = 0;
			}

			/**
			 * 在这里  我们要判断 以下几点
			 *
			 * 1、this._pos_arr[_random] 不能为空
			 */

			_pos = this._pos_arr[_random];

			if(!_pos){

				arguments.callee.call(this,_type);

				return false;
			}

			_pos = this._unit_pos_obj[_pos];//获取到当前值

			/**
			 * 解决 双层高的 不会跑到最下面
			 */
			if( _type == "h" || _type == "wh"){

				if(_pos['_line'] == "4"){

					arguments.callee.call(this,_type);

					return false;
				}
			}

			/**
			 * 2、判断 _type 同事判断 改坐标点的 后一个 下一个 对角的 坐标是否 都是存在的  有一个不存在 就重新取值
			 *
			 */

			_obj1 = this._unit_pos_obj[_pos['_line'] + (_pos['left'] + this._minUnit['width'] + this._offset)];

			_obj2 = this._unit_pos_obj[parseInt(_pos['_line']) + 1 + '' + _pos['left']];

			_obj3 = this._unit_pos_obj[parseInt(_pos['_line']) + 1 + '' + (_pos['left'] + this._minUnit['width'] + this._offset)];

			if( _type == "w"){

				if(!_obj1){

					arguments.callee.call(this,_type);

					return false;

				}else{

					_index1 = _obj1['index'];//这个其实是不准确的

					if(!this._pos_arr[_index1]){

						arguments.callee.call(this,_type);

						return false;

					}else{

						this._pos_arr.splice(_index1,1,'');
					}

				}

			}

			if(_type == "h"){

				if(!_obj2){

					arguments.callee.call(this,_type);

					return false;

				}else{

					_index2 = _obj2['index'];

					if(!this._pos_arr[_index2]){

						arguments.callee.call(this,_type);

						return false;
					}else{

						this._pos_arr.splice(_index2,1,'');
					}
				}
			}

			if(_type == "wh"){

				if(!_obj1 || !_obj2 || !_obj3){

					arguments.callee.call(this,_type);

					return false;

				}else{

					_index1 = _obj1['index'];
					_index2 = _obj2['index'];
					_index3 = _obj3['index'];

					if(!this._pos_arr[_index1] || !this._pos_arr[_index2] || !this._pos_arr[_index3]){

						arguments.callee.call(this,_type);

						return false;

					}else{

						this._pos_arr.splice(_index3,1,'');
						this._pos_arr.splice(_index2,1,'');
						this._pos_arr.splice(_index1,1,'');
					}
				}
			}

			this._pos_arr.splice(_random,1,'');
 
			this._pos_value = _pos;

		},
		NavList.prototype.getColorHandler = function(){

			return "#" + parseInt( Math.random()*16 ).toString(16) + parseInt( Math.random()*16 ).toString(16) + parseInt( Math.random()*16 ).toString(16);
		},
		NavList.prototype.singleDom = function(options){
			/**
			 * name 必填  否则报错
			 */
			var el,attr = options["attr"],type = options["type"],init = options["init"];

			if(!options || !options["name"]) throw new Error("options is error");

			el = doc.createElement(options["name"]);

			el.className = options["cl"] || '';

			el.innerHTML = options["_html"] || '';

			if(attr){

				// attr.forEach(function(item,index){

				// 	el.setAttribute(item["key"], item["value"]);

				// })
				
				for(var key in attr){

					el.setAttribute(key,attr[key]);
				}
			}
			

			if(type){

				this.addEvent(el,type,options["handler"],false);

			}

			return el;
		},
		NavList.prototype.addEvent = function(el, eType, handle, bol){

			console.log(el);

			if(el.addEventListener){           //如果支持addEventListener

		        el.addEventListener(eType, handle.bind(null,this,el), bol);

		    }else if(el.attachEvent){          //如果支持attachEvent

		        el.attachEvent("on"+eType, handle.bind(null,this,el));

		    }else{                                  //否则使用兼容的onclick绑定

		        el["on"+eType] = handle.bind(null,this,el);

		    }
		},
		NavList;

	})(),

	win.NavList = NavList;

})(window,document)