实战二:缓存池

553 阅读4分钟

css

h1,
h2,
h3,
h4,
h5,
h6,
p{
	margin: 0;
	font-weight: normal;
}

a{
	text-decoration: none;
}

ul,li{
	padding: 0;
	margin: 0;
	list-style: none;
}

.wrap{
	position: relative;
	width: 375px;
	height: 667px;
	margin: 100px auto;
	box-shadow: 0 0 5px #999;
}

.header{
	height: 44px;
	background-color: #000;
	text-align: center;
	line-height: 44px;
	color: #fff;
}

.course .loading{
	display: none;
	height: 44px;
	background-color: #eee;
	text-align: center;
	line-height: 44px;
	font-size: 14px;
}

.course .list{
	height: 579px;
	overflow: auto;
}

.course .list-item{
	height: 100px;
	padding: 10px;
	box-sizing: border-box;
	border-bottom: 1px solid #ddd;
}

.course .list-item .inner{
	position: relative;
	height: 100%;
}
/* 企业中布局都是如此:左边图片:宽度141px,绝对定位,相对于上面的inner;top: 0;left: 0; 
* 然后让右边的部分: 宽度195px,padding-left:151px  
*/
.course .list-item .img{
	position: absolute;
	top: 0;
	left: 0;
	width: 141px;
}

.course .list-item .img img{
	width: 100%;
	height: 100%;
}

.course .list-item .info{
	width: 195px;
	padding: 0 0 0 151px;
	box-sizing: border;
}

.course .list-item .info p{
	font-size: 14px;
	margin-top: 7px;
}

.course .list-item .info p.row-2{
	color: green;
}

.course .list-item .info p.row-3{
	color: #999;
}


.footer{
	position: absolute;
	bottom: 0;
	left: 0;
	width: 100%;
	height: 44px;
	border-top: 1px solid #ddd;
	background-color: #fff;
	
}

.footer .btn-item{
	float: left;
	width: 20%;
	height: 100%;
}

.footer .btn-item.cur .page-lk{ /* 因为是一起的,所以.btn-item.cur 中间不能有空格 */
	background-color:#ddd;
	color: #000;
}

.footer .btn-item .page-lk{
	display: block;
	width: 30px;
	height: 30px;
	margin: 7px auto;
	background-color: #000;
	text-align: center;
	line-height: 30px;
	color: #fff;
}





html

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="index.css">
</head>

<body>
	<div class="wrap">
		<div class="header">
			<h3>课程列表</h3>
		</div>
		<div class="course">
			<div class="loading">正在加载中...</div>
			<ul class="list js-list">
			</ul>
		</div>
		<div class="footer">
			<div class="btn-group">
				<div class="btn-item cur">
					<!-- cur不能放到a标签上,会很麻烦  -->
					<a href="javascript:;" class="page-lk">1</a>
				</div>
				<div class="btn-item">
					<a href="javascript:;" class="page-lk">2</a>
				</div>
				<div class="btn-item">
					<a href="javascript:;" class="page-lk">3</a>
				</div>
				<div class="btn-item">
					<a href="javascript:;" class="page-lk">4</a>
				</div>
				<div class="btn-item">
					<a href="javascript:;" class="page-lk">5</a>
				</div>
			</div>
		</div>
	</div>



	<script type="text/html" id="J_itemTpl">
	 <li class="list-item">
        <div class="inner">
     	     <div class="img">
				<img src="http://10.url.cn/qqcourse_logo_ng/ajNVdqHZLLAibZAsw0xhFpUeJmHcOGzXwIMu8d3tz5388Tod9zfTYzKRr3Yum8M4ibBHtXGn3iaH34/356?tp=webp" />
	          </div>
	         <div class="info">
	       <h4>{{classname}}</h4>
	       <p class="row-2">{{name}}老师</p>
	       <p class="row-3">{{watched}}人学习</p>
	         </div>
        </div>
     </li>
	</script>

	<script type='text/javascript' src="./jquery.min.js"></script>
	<script type='text/javascript' src="utils.js"></script>
	<script type="text/javascript" src="./1.js"></script>
</body>

</html>

js

// 在ajax里请求数据, 把已请求过的数据暂时保存到缓存池里面,当缓存池存在这批数据时,就直接调这批数据,不再去请求ajax
//这样大大降低了服务器的压力并且提高了速度
// 比如说 访问浏览器时最开始速度较慢,再点击时速度变快了 
window.onload = function () {
    init();
}
function init() {
    initCourseList();
}
var initCourseList = (function () {
    var oBtnGroup = document.getElementsByClassName('btn-group')[0],
        oBtnItems = document.getElementsByClassName('btn-item'),
        oList = document.getElementsByClassName('js-list')[0],
        oTpl = document.getElementById('J_itemTpl').innerHTML,
        loading = document.getElementsByClassName('loading')[0],
        page = 0,
        t = null, //计时器
        cache = {};  //设置一个缓存


    function init() {
        getAjaxCourses(page);
        bindEvent();
    }

    function bindEvent() {
    addEventListener('click', btnClick); //事件监听函数: 'click':描述事件名称的字符串。 btnClick;描述了事件触发后执行的函数
    }

    function btnClick(e) {
        var e = e || window.event, //兼容
            tar = e.target || e.srcElement, //兼容
            oParent = tar.parentNode,  //点击a标签时 找到相应的上边的父极
            className = oParent.className,
            thisIdx = -1;

        if (className === 'btn-item') {  //如果className 等于 上边父级的时候
            // console.log(tar.innerHTML);


thisIdx = Array.prototype.indexOf.call(oBtnItems, oParent); //存储各个按钮所在父级的下标位置
// indexOf 当前的下标,indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
//找到当前点击的btn-item的下标,那么就用这种方式:第一个参数填入所有btn-item的集合,第二层填入当前点击的a外层的btn-item元素
           
            var len = oBtnItems.length,
                item;

            page = thisIdx;

            if (cache[page]) {   //如果缓存池存在则去缓存池里面找,如果不存在再去请求ajax的数据
                getCacheCourse();
            } else {
                getAjaxCourses();
            }

            for (let i = 0; i < len; i++) {
                item = oBtnItems[i];   //遍历整个按钮
                item.className = 'btn-item';  //让所有的按钮重新赋值为 'btn-item'
            }
            oParent.className = 'btn-item cur';  //当前的标签变为'btn-item cur'  结合css就能让按钮变灰    
        }
    }

    function getAjaxCourses() {
        ajaxReturn({
            url: APIs.getCourses,
            data: {
                page: page        // 对应第48行的    page = thisIdx;   
            },
            success: function (data) {
                cache[page] = data;  //数据缓存在缓存池里面

                loading.style.display = 'block'; //改变display:none 让原本隐藏的loading显现出来
                //   console.log(data);  //接口返回的数据为data
                t = setTimeout(function () {
                    render(data);
                    loading.style.display = 'none';
                }, 500)    //延时500ms
            },
            error: function () {
                console.log('获取数据失败');
            }
        })
    }

    function getCacheCourse() {
        var data = cache[page];
        render(data);
    }

    function render(data) { //渲染
        var list = ' ',  //接受所有的数据
            len = data.length,
            item;

        for (var i = 0; i < len; i++) {
            item = data[i];
            list += setTplToHTML(oTpl, regTpl, {
                folder: item.folder,
                classname: item.classname,
                name: item.name,
                watched: item.watched
            });
            oList.innerHTML = list;
        }
    }

    return function () {
        init();
    }
})();

var APIs = {
    getCourses: 'http://study.jsplusplus.com/Lfcourses/getCourses' //这个api需要一个数据pages,点第几页就是第几页

}

// 分装AJAX
function ajaxReturn(opt) {
    $.ajax({
        url: opt.url,   //url是我们要配置的
        type: 'POST',    //采取哪种形式: post方式
        dataType: 'JSON',     //数据类型用json形式
        data: opt.data,     // data接收一个对象
        timeout: 10000,      //超时的时间:10万毫秒
        success: opt.success,  //成功的回调函数
        error: opt.error,  //也是一个函数
    })

}

最终效果:

总结

难点、新收获的知识点

1.e.srcElement: 事件.源(它的意思就是:当前事件的源
ie支持e.srcElement,firefox 支持e.target。

  1. parentNode 属性可返回某节点的父节点: oParent = tar.parentNode

  2. setTimeout() 是属于 window 的方法,该方法用于在指定的毫秒数后调用函数或计算表达式。在setTimeout 函数之中设置 loading.style.display = 'none';
    在setTimeout之前设置 loading.style.display = 'block';
    这样就能达到等待画面的效果

JS步骤

1. 获取事件元素

oBtnItems = document.getElementsByClassName('btn-item'), :
不能用qs: oBtnItems = document.querySelector('.btn-item'), 因为它是所有类名为btn-item 的元素(类名为btn-item 的类名元素有五个),
只有 oBtnItems = document.getElementsByClassName('btn-item') [0] , 后面有[0],即代表第一个btn-item 元素时, 才能用qs

2.设置点击函数

  1. 只调用 addEventListener('click', btnClick);上面包裹的函数 即可,它自会主动执行 btnClick, 如果调用 btnGroup 会出现错误:Uncaught TypeError: Cannot read property 'target' of undefined

  2. 该种方法(点击事件:click(e); 然后获取点击事件的源tar = e.target || e.srcElement)的优点: 可以使点击哪里, console.log(tar); 就能输出哪里

  3. 因为按钮是a标签, 所以点击按钮时 oParent.className的值为它上面的btn-item

   4.  需要设置 if(className === 'btn-item'){ } 不然点击别的地方会出现问题

   5.  创建一个item,遍历时存储每个按钮: item = oBtnItems[i]; 然后更改按钮的类名以及结合css: 就能改变样式 item.className = 'btn-item'; 这也说明了 DOM对象即 oBtnItems[i] 是引用值

3.设置AJAX以及 getAJAX函数

    1. 填写AJAX函数 里面存储AJAX对象: $. ajax({ })
    1. 填写APIs对象,里面存储网址
    1. 填写 getAJAX函数, 它里面 就是AJAX函数: ajaxReturn({}) 这里面是对象:填写了url: 获取APIs的地址、data:获取页面数据page、成功函数、失败函数,基本都是AXAJ对象里面的一些东西
    1. 第三步的页面数据还没解决: 在 btnClick函数里面 填写 thisIdx = Array.prototype.indexOf.call ( oBtnItems, oParent ); 即thisIdx存储各个按钮所在父级的下标 (index) 位置
      然后再 page = thisIdx; 来存储点击的页面,从而让第三部得知点击的页面是哪个,从而给出相应的数据
    1. indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置:如str.indexOf("welcome"):'welcome' 在字符串str中首次出现的位置
      thisIdx = Array.prototype.indexOf.call ( oBtnItems, oParent ); 找到当前按钮 oBtnItems的下标(index下标 从0开始)
  • 6.在success函数中填写 setTimeout( function(){ },500 ) setTimeout() 是属于 window 的方法,该方法用于在指定的毫秒数后调用函数或计算表达式。 function(){} 内更改loading的样式

    1. 在btnClick()内填写getAjaxCourses ( ) ;

4.设置渲染函数render

  1. 在 getAjaxCourses()的success内填写 render(data); 此时的模板render()接收到了data数据

  2. list = ' ', 再接收穿过来的数据 list += setTplToHTML(oTpl, regTpl, { …… classname: item.classname, …… }); 括号内的参数即为: 模板名称 (text/html 那个) 、 正则 、 对象

  3. 模板的父类ul 接收全部模板数据: oList.innerHTML = list;
    这样就完成了页面渲染

5.设置缓存池

1.声明缓存 var cache = {} ;
2.删除btnClick()内的getAjaxCourses ( ) , 同时在里面 填写:

if (cache[page]) {  
                getCacheCourse();
            } else {
                getAjaxCourses();
            }

该语句意思为:如果缓存池存在则去缓存池里面找,如果不存在再去请求ajax的数据

  1. 在 success 里面保存语句 : cache[page] = data;

4.设置缓存池函数

function getCacheCourse() {
     var data = cache[page];
     render(data);
 }