仿百度新闻首页
偶尔在网上看到百度新闻的效果很炫、就自己粗略的仿制一下效果、效果地址: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)
上一篇: Python的一些基础知识(一)