学习JavaScript第二节

BOM操作

也就是操作浏览器相关的内容!比如可视窗口、滚动条、弹出框!

获取浏览器窗口尺寸

  • window.innerWidth:获取可视窗口宽度
    • 返回值:可视窗口宽度
  • window.innerHeight:获取可视窗口高度
    • 返回值:浏览器可视窗口的高度

浏览器的弹出层

  • window.alert('value'):执行函数,弹出提示框
  • window.confirm('value') 询问框
    • 返回值:确定true,取消false
  • window.prompt('value')输入框
    • 返回值:确定输入的东西,取消null

开启和关闭标签页

  • window.open('地址/url'):开启新页面,跳转的地址为输入的地址
  • window.close():关闭当前页面
<body>
<button id="on"></button>
<button id="off"></button>
<script>
on.colok=function(){
window.open('yue18.com')
}
off.colok=function(){
window.close()
}
<script>
</body>

浏览器常见==事件==

检测并触发事件

  • window.onload = function(){}:资源加载完毕后,执行函数
window.onload = function(){
待执行的代码
}
  • window.onresize = function(){}:可视尺寸改变后,执行函数
window.onresize = function(){
待执行的代码
}
  • window.onscroll = function(){}:滚动条位置改变后,执行函数
window.onscroll = function(){
待执行的代码
}

浏览器的历史记录操作

  • window.history.back():回退页面
  • window.history.forward():前进页面

浏览器卷去的尺寸

有滚动条时,页面隐藏的部分尺寸

  • document.documentElement.scrollTop document.body.scrollTop:卷去的高度
    • 返回值:隐藏的高度
//页面有<!DOCTYPE html>
let scroHei = document.documentElement.scrollTop;
//页面没有<!DOCTYPE html>
let scroHei = document.body.scrollTop;
  • document.documentElement.scrollLeftdocument.body.scrollLeft:卷去的宽度
    • 返回值:隐藏的宽度
//页面有<!DOCTYPE html>
let scroWid = document.documentElement.scrollLeft;
//页面没有<!DOCTYPE html>
let scroWid = document.body.scrollLeft;
  • 卷去的高度/宽度 兼容写法
let height = document.documentElement.scrollTop || document.body.scrollTop
let Width = document.documentElement.scrollLeft || document.body.scrollLeft

浏览器滚动到

  • window.scrollTo(left,top)瞬间移动到可视窗口位置

    • left 浏览器卷去的宽度, top 浏览器卷去的高度 ,
  • window.scrollTo({left:, top:,behavior:}):属性,实现平滑滚动

    window.scrollTo({
    left:xx,
    top:yy,
    behavior:'smooth' //方式为平滑滚动
    })

定时器

开启定时器

  • setInterval(函数,时间):间隔定时器(按照指定周期,去执行指定代码,单位为毫秒):
setInterval(function(){
// 要执行的代码
},1000)
  • setTimeout(函数,时间):延时定时器(在固定的时间毫秒后,执行一次代码):
setTimeout(function(){
// 要执行的代码
},1000)

定时器返回值

  • 返回一个数字,表示页面中第几个定时器,不区分定时器种类,用于关闭定时器
let timeclock =setInterval(函数,时间);

关闭定时器

  • clearInterval(要关闭的定时器返回值)clearTimeout(要关闭的定时器返回值)不区分定时器类型
let i = 0;
let timeclock = setInterval(function(){
console.log(i++);
},1000);
//滑动滚动条时,停止计时
window.onscroll = function(){
clearInterval(timeclock); //停止计时
}
//改变可视窗口大小时,停止计时
window.onresize = function(){
clearTimeout(timeclock); //停止计时
}

DOM操作

什么是DOM

DOM:文档对象模型。

DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。目的其实就是为了能让js操作html元素而制定的一个规范。

DOM就是由节点组成的。

解析过程

HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的属性

DOM树(一切都是节点)

DOM的数据结构如下:

img

上图可知,在HTML当中,一切都是节点:(JS操作HTML,就是操作节点!也就是操作HTML标签)

  • 元素节点:HMTL标签。
  • 文本节点:标签中的文字(比如标签之间的空格、换行)
  • 属性节点::标签的属性。

整个html文档就是一个文档节点。所有的节点都是Object。

DOM可以做什么

  • 获取对象(元素节点)
  • 设置元素的属性值
  • 设置元素的样式
  • 动态创建和删除元素
  • 事件的触发响应:事件源、事件、事件的驱动程序

一整套操作文档流相关内容的属性和方法!比如操作元素,修改样式、属性、位置、添加事件等!

一、获取元素

选中对应元素,注意下面有点是返回元素,有个是返回伪数组

根据元素选择器获取元素

  • document.getElementById('id名称'):获取文档流==id==对应的一个元素
    • 返回值:是个元素,有对应元素,没有null
  • document.getElementsByClassName('类名'):获取文档流所有==类名==对应的元素
    • 返回值:必然是个伪数组,有多少获取多少,没有空的伪数组
    • 伪数组不可以通过数组的方式操控
  • document.getElementsByTagName('标签名'):获取文档流所有==标签名==对应的元素
    • 返回值:必然是个伪数组,有多少获取多少,没有空的伪数组

根据选择器获取元素

选择器:CSS中选择元素的方式、元素选择器、关系选择器、属性选择器、伪选择器!

  • document.querySelector('选择器')选择器可以是id标签,获取对应的第一个元素
    • 返回值:是个元素,有对应元素,没有null
  • document.querySelectorAll('选择器')选择器可以是id标签,获取所有对应的元素
    • 返回值:必然是个伪数组,有多少获取多少,没有空的伪数组

伪数组的特点

  1. 伪数组拥有数组的属性

    • 具有 length 属性,但length属性不是动态的,不会随着成员的变化而变化,不能修改长度

    • 按索引方式储存数据,可以遍历数组!

    • 不具有数组的push(), forEach()等方法?

    • 伪数组本质是一个 Object,而真实的数组是一个 Array。

      • 伪数组的原型 Object.prototype 通过改变原型指向可以将伪数组转为真数组

二、操作元素

操作元素,在选中元素后,还可以继续选择元素内的内容,并且可以修改标签、内容、属性等!

1. 操作元素的==内容==

操作元素内的文本内容
  • 元素.innerText:获取文本内容
    • 返回值:标签内包裹的文本内容!
  • 元素.innerText='新内容':设置新文本内容
<body>
<button>操作内容</button>
<div>
<p>这是初始文本</p>
</div>

<script>

//注意
//获取元素,当获取的<p>元素,改为<div>元素是,会把<p>当作内容一起修改!
let ele = document.querySelector('p');
let btn = document.querySelector('button')

//注意
//获取文本内容,并打印
console.log(ele.innerText) //打印为这是初始文本

//给按钮绑定点击事件,文档流中每个元素都可以看成是一个变量,对这些变量,可以操作
//点击按钮时,更改文本内容
btn.onclick = function(){

//注意,设置内容,就是通过赋值!
ele.innerText = '这是修改后的文本内容'
}
</script>
</body>
操作元素内的超文本内容

操作元素超文本内容,可以让标签结构一起改变!

  • 元素.innerHTML:获取超文本内容
    • 返回值:标签内包裹的元素!文本内容</closing tag>
  • 元素.innerHTML='新内容':设置新的超文本,可以放HTML标签!
<body>
<button>操作内容</button>
<div>
<p>这是初始文本</p>
</div>

<script>
//获取元素,改为<div>元素时,会把<p>当作内容一起修改!
let ele = document.querySelector('div');
let btn = document.querySelector('button')

//获取文本内容,并打印
console.log(ele.innerHTML) //打印为<p>这是初始文本</p>
//给按钮绑定点击事件,文档流中每个元素都可以看成是一个变量,对这些变量,可以操作
btn.onclick = function(){

//点击按钮时,更改文本内容
ele.innerHTML = '<span>这是修改后的文本内容</span>'
}
</script>
</body>

2. 操作元素的==属性==

属性分为原生属性、自定义属性,原生就是元素自带的属性,自定义就是自己随便写的!

操作原生属性
  • 元素.属性名:获取对应元素的属性值
    • 返回值:对应属性的值!
  • 元素.属性名='属性值':设置属性值
<body>
<button>操作属性</button>
<div id="box">div标签</div>
<input type="password">

<script>
let box = document.querySelector('div');
let inp = document.querySelector('input');
let btn = document.querySelector('button');

//获取文本内容,并打印
console.log(box.id); //打印为box
//给按钮绑定点击事件,文档流中每个元素都可以看成是一个变量,对这些变量,可以操作
btn.onclick = function(){

//点击按钮时,修改ID值,修改type值,还可以修改很多属性!
box.id = 'haha';
inp.type = 'radio'
}
</script>
</body>
操作自定义属性
  • 元素.getAttribute('属性名'):获取属性值
    • 返回值:属性名对应的属性值!
  • ``元素.setAttribute(‘属性名’,’新属性值’)`:修改属性值
  • 元素.removeAttribute('属性名'):删除属性

以上对属性的操作,一般不用于对类名和样式的修改!

3. 操作元素==类名==

  • 元素.className:获取元素类名
    • 返回值:class的值,就是类名
  • 元素.className='新类名':设置新类名,就是赋值!

4. 操作元素==行内样式==

  • 元素.style.样式名:获取样式的值,注意当样式名带有中划线时,改为驼峰命名法!
    • 返回值:样式的值
  • 元素.style.样式名 = '样式值'
<body>
<button>操作样式</button>
<div style="width:100px; height:100px; background-color:pink">div标签</div>

<script>
let box = document.querySelector('div');
let btn = document.querySelector('button');

//获取文本内容,并打印
console.log(box.style.backgroundColor); //打印为pink

//点击按钮时,
btn.onclick = function(){
box.style.width = '200px';
box.style.height = '300px';
box.style.backgroundColor = 'skyblue';
}
</script>
</body>

这个方法只能获取,行内样式!

5. 获取元素==非行内样式==

  • window.getComputedStyle(元素).样式名:可以获取非行内样式,或行内样式,但不能设置样式值
案例:回到顶部

确认需求:

  1. 滚动条超过临界点,顶部通知隐藏,且按钮显示,否则顶部通知显示,按钮隐藏!
  2. 点击按钮,滚动条滚回到顶部!
//布局结构
//一个顶部通栏标签,一个按钮标签
//让页面的大小超过可视窗口高度
//设置顶部通栏超过可视窗口时,隐藏
//设置按钮,默认为隐藏,顶部通栏超过可视窗口时,显示

代码逻辑
//给浏览器绑定滚动事件,实时获取浏览器卷去的高度
//判断卷去的高度,决定显示还是隐藏
//给回到顶部按钮绑定滚动事件

<style>
body{
margin: 0px;
height: 2000px;
}
.header{
width: 100%;
height: 20px;
text-align:center;
background-color: pink;
transition: top 0.5s linear;
}
button{
width: 68px;
height: 20px;
background-color: pink;
fot-size: 16px;
color: #000;
text-align:center;
position: fixed;
right: 20px;
bottom: 100px;
display: none;
}


</style>

<body>
<div class="header">顶部通栏</div>
<button>顶部</button>


<script>
let box = document.querySelector('div');
let btn = document.querySelector('button');

//滚动滚动条时,超过一定高度,显示按钮
window.onscroll = function(){
let height = document.documentElement.scrollTop || document.body.scrollTop;
if(height>40){
btn.style.display = 'block';
}else{
btn.style.display = 'none';
}
}

//点击按钮时,
btn.onclick = function(){
window.scrollTo({
left: 0,
top: 0,
behavior: 'smooth' //方式为平滑滚动
})

}
</script>
</body>
案例:全选
  • 确认需求:
    (当选项被全部选中后,全选按钮也自动被勾上,否则不被自动勾上
    全选按钮被选中时,全部选项也自动被勾上,当全选按钮选中状态被去掉,全部选项自动清空!)

    1. 全选按钮点击时,根据自身状态决定所有选项按钮状态
    2. 点击每个选项按钮的时候,根据所有所有选中按钮状态决定全选按钮状态
  • 结构:
    一个全选按钮,若干选项

  • 代码逻辑:

    1. 给全选按钮绑定点击事件

      • 拿到自己的选中状态
      • 给所有选项按钮设置选中状态
    2. 给每个选项按钮绑定点击事件

      • 判断是不是所有按钮都是选中的

      • 根据判断结果给全选按钮设置选中状态

        <!DOCTYPE html>
        <html lang="en">
        <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>全选按钮</title>
        <style>
        *{
        margin: 0px;
        padding: 0px;
        }
        .box{
        width: 100px;
        padding:20px;
        border: 1px solid pink;
        margin: 30px auto;
        border-radius: 5px;
        }
        hr{
        margin: 10px 0;
        }
        </style>
        </head>
        <body>
        <div class="box">
        全选 : <input type="checkbox"/><br/>
        <hr/>
        <input type="checkbox"/> 选项一 <br/>
        <input type="checkbox"/> 选项二 <br/>
        <input type="checkbox"/> 选项三 <br/>
        <input type="checkbox"/> 选项四 <br/>
        </div>
        <script>
        //1. 获取元素
        let allBtn = document.querySelector('input');
        let items = document.querySelectorAll('input:nth-child(n+2)');
        //2. 给全选按钮添加事件
        allBtn.onclick = function(){
        //2-1. 拿到自己的选中状态
        console.log(allBtn.checked);

        //2-2. 把自己的选中状态复制给每一个按钮
        for(let i=0;i<items.length;i++){
        items[i].checked = allBtn.checked;
        }
        }
        //3. 用数组存放选项的状态值
        let arr = [];
        //3-1. 给每个选项绑定点击事件
        for(let j=0;j<items.length;j++){
        items[j].onclick = function(){

        //3-2. 点击时,把对应按钮的状态存放到数组中
        arr[j]= items[j].checked;

        //3-3. 当全部按钮都被选中时,让全选按钮也被选中
        if(arr[0]===true && arr[1]===true && arr[2]===true && arr[3]===true){
        allBtn.checked = true;
        }else{
        allBtn.checked = false;
        }
        }
        console.log(arr[j]);
        }
        </script>
        </body>
        </html>

        或者把JS代码改成这样

        <script>
        //1. 获取元素
        let allBtn = document.querySelector('input');
        let items = document.querySelectorAll('input:nth-child(n+2)');
        //2. 给全选按钮添加事件
        allBtn.onclick = function(){
        //2-1. 拿到自己的选中状态
        console.log(allBtn.checked);

        //2-2. 把自己的选中状态复制给每一个按钮
        for(let i=0;i<items.length;i++){
        items[i].checked = allBtn.checked;
        }
        }
        //添加个数组存放,每个选中的值,添加变量,存放全部按钮都被选中的值
        let arr = [];
        let jieguo;
        for(let j=0;j<items.length;j++){
        //给每个按钮添加点击事件
        items[j].onclick = function(){
        //每个值,都被按顺序记录在数组中
        arr[j]= items[j].checked;
        //每次点击,就判断所有按钮的值,是否被选中,并把全选的结果存放在一个变量中
        for(let i=0;i<items.length;i++){
        if(arr[i]===true){
        jieguo = true;
        }else{
        jieguo = false;
        break;
        }
        }
        //每次点击,就判断是否全选,如果全选,则让全选按钮也被选中
        if(jieguo===true){
        allBtn.checked = true;
        }else{
        allBtn.checked = false;
        }
        }
        console.log(arr[j]);
        }
        </script>

        换一种写法JS代码,最简洁优雅的写法!

        <script>
        //1. 获取元素
        let allBtn = document.querySelector('input');
        let items = document.querySelectorAll('input:nth-child(n+2)');
        //2. 给全选按钮添加事件
        allBtn.onclick = function(){
        //2-1. 拿到自己的选中状态
        console.log(allBtn.checked);

        //2-2. 把自己的选中状态复制给每一个按钮
        for(let i=0;i<items.length;i++){
        items[i].checked = allBtn.checked;
        }
        }
        //3. 循环拿到每一个选项按钮,添加点击事件,每点一次,判断是否全选
        for(let i = 0; i<items.length; i++){
        //3-1. 给每一个按钮添加点击事件
        items[i].onclick = function(){
        //3-2. 定义假设变量,假设所有按钮都是被选中的,就可以在下面的if语句中少写个else{}
        let flag = true;

        //3-3. 通过循环来验证我们的假设
        for(let j = 0; j<items.length; j++){
        if(items[j].checked === false){
        //只要有一个未被选中,就记录总的为未被选中,并退出循环
        flag = false;
        break;
        }
        console.log(items[j].checked);
        }
        console.log(flag);
        //4. 把全部按钮被选中的结果,赋值给全选按钮,传达胜利的消息!
        allBtn.checked = flag;
        }
        }
        </script>
  • 重点注意:

    • for(){}用于循环时,可以看成,把里面的代码复制了几份!并且当借助循环变量,来操作时,可以看成是,里面的代码,借了一组等差值!
    • 点击事件,是当元素被选中时,才执行函数内的代码!
    • 逻辑简化,条件语句中,当值有两种结果,可以预设一种结果,只判断另一种情形就可以了!记得加上及时退出循环!
    • 当判断的值,与赋值相等时,可以不用判断,直接赋值就行!
    • 编程就像在浮冰上过河,挑选合适的落脚点,有条理性的到达终点!而我追求简洁优雅!
    • 拿到一个需求时,分析清楚里面的内容结构、样式布局、代码逻辑,并按内容结构去拆解代码逻辑,当此内容发生什么,然后此内容发生什么!或者其它内容发生什么!

案例:选项卡
确认需求:

  1. 点击哪一个按钮,其它按钮全部回归原始,当前高亮!
  2. 点击哪一个按钮,其它盒子全部隐藏,当前索引对应盒子显示!

布局结构:

  1. 三个表示按钮的盒子,横向排列,初始一个高亮!
  2. 三个显示内容的盒子,在同一位置不同层级排列,初始一个显示!

代码逻辑:

  1. 每一个按钮盒子绑定一个点击事件,
  2. 点击任意按钮时
    • 所有按钮盒子取消高亮状态
    • 所有内容盒子隐藏
  3. 点击任何一个按钮盒子
    • 当前按钮盒子高亮
    • 当前索引对应内容盒子显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>选项卡</title>
<!--取消样式-->
<style>
* {
margin: 0px;
padding: 0px;
}

ul, ol, li {
list-style: none;
}

.box {
width: 600px;
height: 400px;
border: 3px solid pink;
margin: 50px auto;
display: flex;
flex-direction: column;
}

.box > ul {
height: 60px;
display: flex;
}

.box > ul > li {
flex: 1;
color: #fff;
background-color: skyblue;
font-size: 30px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
/* cursor : 网页浏览时用户鼠标指针的样式或图形形状。
属性值:
default:默认光标(通常是一个箭头)
auto:默认,浏览器设置的光标
crosshair:光标为十字线
pointer:光标为一只手
move:光标为某对象可移动
text:光标指示文本
wait:光标指示程序正在忙(通常是一只表或者一个沙漏) */
}

.box > ul > li.bgColor {
background-color: orange;
}

.box ol {
flex: 1;
position: relative;
}

.box > ol > li {
width: 100%;
height: 100%;
background-color: purple;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 100px;

position: absolute;
left: 0px;
right: 0px;

display: none;
}

.box > ol > li.dspFlex {
display: flex;
}

#red {
background-color: rgb(211, 93, 93);
}

#green {
background-color: greenyellow;
}

#blue {
background-color: blueviolet;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li class="bgColor">1</li>
<li>2</li>
<li>3</li>
</ul>
<ol>
<li id="red" class="dspFlex">1</li>
<li id="green">2</li>
<li id="blue">3</li>
</ol>
</div>
<script>
//1.获取元素
let btns = document.querySelectorAll('ul > li');
let tabs = document.querySelectorAll('ol > li');

//2.利用循环给每个按钮添加点击事件,可以使用for代替,就是给每个按钮添加点击事件!
btns.forEach(function(item,index){

item.onclick = function(){

//2-1. 先取消全部内容的样式,给btns和tabs里面的全部内容取消类名
btns.forEach(function(t,i){
t.className = '';
tabs[i].className = '';
})

//2-2. 再单独添加当前元素的样式,给当前按钮添加背景className = 'bgColor'和索引对应内容添加className = 'dspFlex'类名
item.className = 'bgColor';
tabs[index].className = 'dspFlex';
}
})

</script>
</body>
</html>

利用for循环实现上述的JS代码!

<script>
//1.获取元素
let btns = document.querySelectorAll('ul > li');
let tabs = document.querySelectorAll('ol > li');

//2.给每个按钮添加点击事件
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function(){

//2-1. 先取消所有按钮和内容的样式
for (let j = 0; j < btns.length; j++) {
btns[j].className = '';
tabs[j].className = '';
}
//2-2. 再单独添加样式!
btns[i].className = 'bgColor';
tabs[i].className = 'dspFlex'
}

}
</script>

总结:分析需求的内容和样式,以及排版,再分析每个内容对应的事件,与其它内容的关系,以及实现逻辑!
最开始的样子,最接近原始,就是所有按钮标签都一样,没有内容!默认选中第一个标签,默认为显示第一个内容!按钮变化的是颜色,内容变化的是是否显示!
在CSS代码中,规定变化前的样式,规定变化后的样式,通过JS来操作元素类名className,从而间接实现,样式变化!就不用元素行内样式,去添加样式的值了!
思维框架,还是要结构层面分析,样式层面分析,代码逻辑分析,再总体相互间关系,再每个元素的关系!

DOM操作(下)

节点操作

  • 创建节点

    • 用JS代码,创建一个内容,不再是页面上已经出现的内容!
      • 语法:document.createElement(‘标签名称’)
      • 作用:创建一个指定的标签元素
      • 返回值:一个创建好的元素节点
  • 插入节点

    • 把创建好的一个节点,插入到一个已经存在的结构内
      • 语法一:父节点.appendChild(子节点)
      • 作用:把子节点放到父节点的内部,并且放到最后的位置

      • 语法二:父节点.insertBefore(要插入的子节点,某一已存在的子节点)
      • 作用:把子节点放在父节点的内部,放在指定位置,插入在已存在子节点前
  • 删除节点

    • 把已存在的节点,移除
      • 语法一:父节点.removeChild(子节点)
      • 作用:从父节点下,删除一个子节点
      • 语法二:节点.remove()
      • 作用:直接删除节点
  • 替换节点

    • 语法一:父节点.replaceChild(要换上的子节点,要换下的子节点)
    • 作用:在该父节点内,用换上节点,替换掉换下节点
  • 克隆节点

    • 把节点复制一份下来
    • 语法:节点.cloneNode(是否克隆后代节点),括号内填true或false!
    • 作用:把该节点复制一份一模一样的内容
    • 返回值:克隆好的节点
    • 不克隆后代时,只能克隆标签,克隆后代时,可以克隆子节点和标签内的内容!

总结:元素内分为标签、属性、内容等,创建节点,只有一对标签,用操作元素的方法,预赋元素内容,属性!
想插入、删除、替换和克隆节点时,先获取元素!再操作元素!有了这些操作,那么可以随意在页面中生成内容了,动态的修改页面内容!

获取元素尺寸

元素尺寸,也就是元素的盒子模型中的尺寸,content、padding、border、mangar中content的尺寸!

  • 语法:元素.offsetHeight
  • 语法:元素.offsetWidth
  • 作用:元素content+padding+border区域的尺寸
  • 语法:元素.clientHeight
  • 语法:元素.clientwidth
  • 作用:元素content+padding区域的尺寸

案例

动态渲染数据,通过代码,把已知的数据渲染成表格显示在页面上!利用刚学的插入节点!
需求分析:分析已知数据的内容,与表格中的内容对应关系,利用循环快速添加

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态渲染页面</title>
<style>
div{
position: relative;
left: 10%;
top: 50%;
margin: 50px auto;
}
table{
border-collapse: collapse;
border: 2px solid yellowgreen;
border-radius: 20px;

}
th,td{
height: 20px;
width: 100px;
border: 1px solid burlywood;
font-size: 16px;
text-align: center;
padding: 10px 40px;
color: white;
background-color: skyblue;
}
button{
position: relative;
left: 10px;
font-size: 16px;
color: white;
background-color: skyblue;
border: 2px solid orangered;
cursor: pointer;
border-radius: 5px;

}
</style>
</head>
<body>
<div>
<table>
<thead>
<tr><th>ID</th><th>姓名</th><th>年龄</th></tr>
</thead>
<tbody>

</tbody>
<tfoot>
<tr><td colspan="3"><button>生成数据</button></td></tr>
</tfoot>
</table>
</div>

<script>
//提前准备好数据
let users = [
{id: 1, name: '前端小灰狼', age: 28 },
{id: 2, name: '前端小灰', age: 27 },
{id: 3, name: '前端小', age: 26 },
{id: 4, name: '前端', age: 25 },
{id: 5, name: '前', age: 24 },
]
//1. 添加按钮,去触发增加数据
let bnt = document.querySelector('button');
let tbody = document.querySelector('tbody');

//2. 给按钮绑定事件
bnt.onclick = function(){

//3.forEach循环,users有多少个数据,就循环多少遍
users.forEach(function(item){
//3-1. 每次循环时,添加一个行标签,创建一行!
let tr = document.createElement('tr');

//3-2. 让这一行填充数据,for/in循环,把对象转换成数组,遍历对象的键值对
for(let i in item){

//3-2-1. 每循环一次,创建一个单元格,并把对象的键值赋到单元格的内容
let td = document.createElement('td');
td.innerText = item[i];

//3-2-2. 把单元格,插入到一行里!循环多少次,一行就有多少个单元格
tr.appendChild(td);
}
//4. 让这一行,插入到表格里!
tbody.appendChild(tr);
})
}
</script>
</body>
</html>

总结:这种页面上展示的内容来源于其它地方,可以拓展数据来源于服务器,数据来源于用户填写,数据来源于其它网页,其中比较关键的是数据类型的转换,不同数据怎么处理,才能满足我想展示的要求,什么样的数据才能使用什么方法,函数!
本例题思路简单,拓展的重难点是数据从哪儿来?是什么类型?可以采取什么方法实现!