1.瀑布流
又称为瀑布流式布局,是一种比较流行的网站页面布局。
视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,不断加载数据块并附加至当前尾部。
优点:
① 有效降低页面复杂度,节省了空间,不再需要臃肿复杂的页码导航连接或按钮;
② 对触屏设备来说,交互方式更符合直觉,尤其在移动应用的交互环境中,降低了操作精准度要求;
③ 更高的参与度,以上两点所带来的的交互便捷性,可以使用户将注意力更多的集中在内容而不是操作上。
说明事项:
① 通常瀑布流对于元素的高度并没有限制,但是为了便于计算,很多时候瀑布流元素的宽度要求相同;
② 瀑布流的页面元素,第一行元素正常排列;
③ 从第二行元素开始,每一个元素都依次排在当前高度最矮的元素列下面;
④ 瀑布流可以做到无限滚动,永远加载不完。
2.瀑布流案例
<html lang="en">
<head>
<meta charset="UTF-8">
<title>无限瀑布流</title>
<style>
*{margin: 0;padding: 0;}
.containerBox{
margin: 0 auto; /*div容器不设置宽高,由内容撑开,居中显示*/
padding: 0;
position: relative; /*所有瀑布流内容相对div容器进行定位*/
}
.picDiv{
float: left;
cursor: pointer;
}
.picDiv:hover img{
box-shadow: 0 0 10px orangered;
transform:translate(1px,-6px);
}
img{
margin: 10px;
padding: 10px;
border: 1px solid hotpink;
border-radius: 5px;
box-shadow: 0 0 5px darkorange;
transition: all .3s;
}
/*也可以通过“picDiv”设置边框格式,但通过”img“设置的好处在于
“picDiv”的宽度就是包含了所有占用空间,这样便于布局尺寸计算!*/
</style>
</head>
<body>
<div class="containerBox"></div>
<script>
// <!--模拟后台获取数据(JSON字符串)-->
var dataStr='{"picName":["vogue01.jpg","vogue02.jpg","vogue03.jpg","vogue04.jpg","vogue05.jpg","vogue06.jpg","vogue07.jpg","vogue08.jpg","vogue09.jpg","vogue10.jpg","vogue11.jpg","vogue12.jpg","vogue13.jpg","vogue14.jpg","vogue15.jpg","vogue16.jpg","vogue17.jpg","vogue18.jpg","vogue19.jpg","vogue20.jpg","vogue21.jpg","vogue22.jpg","vogue23.jpg","vogue24.jpg","vogue25.jpg","vogue26.jpg","vogue27.jpg","vogue28.jpg","vogue29.jpg"]}';
// 将JSON字符串转换成js对象
var jsPicObj=JSON.parse(dataStr);
var containerBox=document.querySelector(".containerBox");
// ① 获取div元素,使用“for”循环将图片内容添加到容器中,
// ② 将“for”循环封装成函数
function catchPics() {
for (var i=0;i<jsPicObj.picName.length;i++){
var waterFallPic=jsPicObj.picName[i];
var picDiv=document.createElement('div');
// 使用“innerHTML”属性将图片添加至各个div中,
// innerHTML的value使用<img/>标签,通过<img/>的“src”属性引用图片(需拼接图片地址)
picDiv.innerHTML='<img src="Images/WaterFall/'+waterFallPic+'"/>';
containerBox.appendChild(picDiv);
// picDiv.setAttribute("float","left"); //使用“setAttribute”方法无效??
// picDiv.style.cssFloat='left';
picDiv.className='picDiv';
}
}
// 构建瀑布流布局
// ③ 将整个构建过程封装成函数
function creatWaterFall() {
// 在“containerBox”没有设置“width”属性值的情况下,默认占据整个页面宽度,
// 此时通过margin属性设置div居中没有效果,通过“picDiv”的宽度设置“containerBox”的宽度。
// ① 获取图片元素,通过图片元素的宽度属性计算“containerBox”的宽度,有了width属性值margin居中设置才有效果。
var picDivCol=document.querySelectorAll('.picDiv');
var singleWidth=picDivCol[0].clientWidth;
var bodyWidth=document.documentElement.clientWidth||document.body.clientWidth; //兼容考虑
var rowPicNum=Math.floor(bodyWidth/singleWidth);
containerBox.style.width=singleWidth*rowPicNum+'px';
// ② 使用 for循环从第二行开始将图片依次逐一放到当前累计高度最小的一列后面
var columnHeightArr=[];
for (var j=0;j<picDivCol.length;j++){
if (j<rowPicNum){
// 第一行图片按正常流排列,将每一列的高度以数组的形式保存
columnHeightArr.push(picDivCol[j].clientHeight);
}else {
// 从第二行开始每个图片设置绝对定位,通过“style.top/left”属性将其放置在指定位置
picDivCol[j].style.position='absolute';
// Math.min()方法内部需要的是数字类型,通过apply()方法调用Math。
var shortHeight=Math.min.apply(null,columnHeightArr);
var shortHeightIndex=columnHeightArr.indexOf(shortHeight);
// 以累计高度最小的列元素的左定位作为第“j”个图片的left位移,其当前累计高度作为第“j”个图片的top位移。
picDivCol[j].style.left=picDivCol[shortHeightIndex].offsetLeft+'px';
picDivCol[j].style.top=columnHeightArr[shortHeightIndex]+'px';
// 每放置一个图片后,需要将该图片的高度累加到当前列的累计高度上
columnHeightArr[shortHeightIndex]=picDivCol[j].clientHeight+shortHeight;
}
}
}
catchPics();
// 由于构建瀑布流过程中需要用到图片的数据信息,如果执行函数时图片尚未加载完成会导致异常,
// 而 onload事件是图片内容加载完成后才会触发
window.onload=function () {
creatWaterFall();
}
// 设置无限瀑布流
// 基本思路:当图片集合中的最后一张图片即将出现在可视区域时,进行瀑布流重复加载
window.onscroll=function () {
var picDivCol=document.querySelectorAll('.picDiv'); //能不能与构建函数中的声明合并为一个??
var maxIndex=picDivCol.length-1;
var checkDist=picDivCol[maxIndex].offsetTop;
var scrollDist=document.documentElement.scrollTop||document.body.scrollTop;
var bodyHeight=document.documentElement.clientHeight;
if (checkDist<=scrollDist+bodyHeight){
catchPics();
creatWaterFall(); //首次加载已经获取图片数据,不再需要通过 onload事件
}
}
/* 无限瀑布流设置的另外一种书写方式:
function trigger() {
var picDivCol=document.querySelectorAll('.picDiv');
var maxIndex=picDivCol.length-1;
var checkDist=picDivCol[maxIndex].offsetTop;
var scrollDist=document.documentElement.scrollTop||document.body.scrollTop;
var bodyHeight=document.documentElement.clientHeight;
if (checkDist<=scrollDist+bodyHeight){
return true;
}
}
window.onscroll=function () {
if (trigger()){
catchPics();
creatWaterFall();
}
}*/
</script>
</body>
</html>
3.知识碎片
① setAttribute()方法用于设置元素的属性,不能直接设置样式,而 style属性才用于直接操作css样式,
用法区别比较如下:
picDiv.setAttribute("style", "float:left");
picDiv.style.cssFloat="left";
picDiv.style.setProperty("float", "left");
② clientWidth、clientHeight,分别表示元素节点可见部分的宽度和高度,以clientWidth为例进行说明,
element.clientWidth的值包括padding,但不包括滚动条、border和 margin,
document.clientWidth与 window.innerWidth减去滚动条宽度的值相等。
③ offsetWidth、offsetHeight,分别表示元素节点的水平宽度和高度,
element.offsetWidth的值包括padding、滚动条、border。
④ Math.min.apply()方法,由于Math相关方法的参数都要求是数值型数据,
而apply()方不仅可以改变函数的用着,并且要求的参数是数组类型。
⑤ window.onload,对依赖图片的相关计算或函数,通过onload事件进行加载,
避免执行时依赖的图片资源还没有加载完成导致函数执行失败。
4.阶乘求和(递归函数)
<script>
// 3)将 for循环封装为一个函数,
// 通过定义函数的参数与循环次数的关系,达到动态计算的目的。
function sumFactorial(y) {
var sum=0;
// 2)使用 for循环创建可以计算多个连续数字的阶乘并求和。
for (var i=0;i<y;i++){
// 1)创建求单个数字阶乘的递归函数。
function factorial(x) {
if (x <=1){
return 1;
}else {
return x*factorial(x-1);
}
}
sum+=factorial(y-i);
console.log((y-i)+"!="+factorial(y-i));
}
console.log("1!到"+y+"!之和:"+sum);
}
// 调用外部函数,传入实参。
sumFactorial(10);
</script>
5.事件代理(DOM冒泡事件)
<body>
<div>
<ul>ul元素
<li>第一个li</li>
<li>第二个li</li>
<li>第三个li</li>
</ul>
</div>
<script>
var ul=document.querySelector('ul');
ul.style.cursor='pointer';
ul.addEventListener("click", function () {
var text=event.target.firstChild.nodeValue;
console.log("本次点击的是"+text);
})
</script>
</body>