Skip to content

1-11数组综合案例 ​

本页对应 第一章JavaScript基础,共 5 段视频,约 52 分钟。

学习目标 ​

  • 能够使用“声明空字符串 → 循环拼接标签字符串 → 插入指定容器”的步骤,用 JavaScript 动态生成多个 DOM 元素。
  • 能够通过循环连续弹出 4 次输入框,将用户输入转换为数字并按顺序存入数组。
  • 能够根据数组数据渲染柱形图,正确设置每个柱子的高度、提示文本、数值文本和季度标签。
  • 能够使用数组 sort() 实现升序与降序排序,并说明其会修改原数组,且能据此获取数组最大值和最小值。
  • 能够描述选择排序的基本步骤,并使用双重循环与变量交换手写完成数组排序。

知识点 ​

数组是什么:先理解“一个变量装多个值” ​

为什么需要:保存一个同学姓名可以用一个变量,保存全班姓名再用一个个变量就很麻烦。数组的作用就是“在单个变量名下存储多个数据”,它属于引用数据类型。
怎么想:把数组看成一排有编号的格子,格子按顺序存放数据,每个格子叫数组单元,也叫数组元素。
怎么做:用 [] 表示数组,元素之间用英文逗号分隔。
易错点:数组元素可以是任意数据类型;逗号必须是英文逗号;数组按顺序存储,编号从 0 开始。

定义数组:空数组与非空数组 ​

为什么需要:有时先准备空数组,等用户输入或循环时再追加;有时一开始就有数据。
怎么想:let classes = [] 是空数组;let classes = ['小明', ...] 是非空数组。
怎么做:

html
<script>
  // 1. 语法,使用 [] 来定义一个空数组
  // 定义一个空数组,然后赋值给变量 classes
  // let classes = []

  // 2. 定义非空数组
  let classes = ['小明', '小刚', '小红', '小丽', '小米']
</script>

易错点:不要写成中文逗号;数组里每一项称为数组单元/元素;空数组不是没有变量,而是变量里装了一个空集合。

访问数组和数组索引:用编号取数据 ​

为什么需要:存数据不是目的,关键是要能随时访问某个数据。
怎么想:JavaScript 给每个数组单元编号,称为索引值或下标,从 0 开始。图中【小明】索引为 0,【小红】索引为 2。
怎么做:语法是 数组名[下标]。

数组索引示意图

html
<script>
  // 数组: 可以单个变量下存储多个数据
  // 1. 声明数组
  let names = ['小明', '小刚', '小红', '小丽', '小米']
  // let names = ['小明', '小刚', true, '小丽', 1]
  console.log(names)
  // 1.1 数组是按照顺序来存储的,每个数据都有自己的编号
  // 1.2 编号是从0开始的, 0 1 2 3... 也称为 索引 或者 下标
  // 1.3 数组里面可以存放任意的数据类型

  // 2. 数组取值  数组名[下标]
  console.log(names[0])  // '小明'
  console.log(names[1])  // '小刚'
  console.log(names[2])  // '小红'
  console.log(names[3])  // '小丽'
  console.log(names[4])  // '小米'
</script>

易错点:第一个元素是 [0],不是 [1];访问不存在的索引返回 undefined;数组单元可以是字符串、数字、布尔值等混合类型。

html
<script>
  // 6. 数组单值类型可以是任意数据类型

  // a) 数组单元值的类型为字符类型
  let list = ['HTML', 'CSS', 'JavaScript']
  // b) 数组单元值的类型为数值类型
  let scores = [78, 84, 70, 62, 75]
  // c) 混合多种类型
  let mixin = [true, 1, false, 'hello']
</script>

遍历数组:用循环访问每个元素 ​

为什么需要:数组元素多时,不可能一个个 console.log。遍历就是把数组中每个数据都访问到。
怎么想:索引从 0 开始,循环变量 i 也从 0 开始;结束条件用 arr.length,不要写死数字。
怎么做:

html
<script>
  let arr = ['迪丽热巴', '古力娜扎', '佟丽丫丫', '玛尔扎哈', '哈尼克孜']
  // console.log(arr[0])
  // console.log(arr[1])
  // console.log(arr[2])
  // console.log(arr[3])
  // 遍历数组: 把数组里面的数据每个都会访问到
  // for (let i = 0; i < 4; i++) {
  //   // console.log(i)  数组名[索引号]
  //   console.log(arr[i])
  // }

  // 1. 数组的长度 数组.length 
  // console.log(arr.length)  // 4
  for (let i = 0; i < arr.length; i++) {
    console.log(arr[i])
  }
  // 2. 数组里面的数据也称为 数组元素
</script>

易错点:循环条件写 i <= arr.length 会多访问一次,得到 undefined;数组长度是 arr.length,不是 arr.length()。转写稿中的手风琴案例也是先准备图片地址数组,再循环拼接字符串生成多个标签,说明遍历数组常和“批量生成结构”一起用。

查询和修改数组:查不到是 undefined,改不存在会增长度 ​

为什么需要:实际使用中既要读取某个元素,也要改某个元素。
怎么想:查询用 数组[索引];修改用 数组[索引] = 新值。
怎么做:

数组增删改查示意图

html
<script>
  // 1. 查询数组元素
  let arr = ['迪丽热巴', '古丽扎娜']
  console.log(arr[0]) //  '迪丽热巴'
  console.log(arr[1]) //  '古丽扎娜'
  console.log(arr[2]) //  undefined

  // 2. 修改数组元素   数组[索引] = 新值
  arr[1] = '佟丽丫丫'
  // console.log(arr)
  arr[3] = '古丽扎娜'  // 如果索引号不存在,则是增加数组元素 (不提倡)
  console.log(arr)
  console.log(arr.length)  // 4 修改了数组长度
</script>

易错点:查询不到返回 undefined;给不存在的索引赋值会新增元素并改变长度,初学阶段应尽量避免。

新增元素:push 末尾加,unshift 开头加 ​

为什么需要:用户输入、循环生成数据时,经常要往数组里追加元素。
怎么想:末尾追加用 push,开头追加用 unshift;它们都会修改原数组。
怎么做:

数组新增元素示意图

javascript
// 数组新增元素
// 1. 可以向数组的末尾新增1个或者多个数组元素 数组.push(元素1...元素n)
let arr = ['迪丽热巴']
// console.log(arr.push('佟丽丫丫'))  // 返回的是新数组的长度 2
// arr.push('佟丽丫丫', '古丽扎娜')
// console.log(arr)  // 修改原数组

// 2. 可以向数组的开头增加1个或者多个数组元素 数组.unshift(元素1,...元素n)
// console.log(arr.unshift('佟丽丫丫'))  // 返回的是新数组的长度 2
arr.unshift('佟丽丫丫', '古丽扎娜')
console.log(arr) // 修改原数组

易错点:push/unshift 返回的是新长度,不是新数组;它们修改原数组。转写稿柱形图案例中,用户输入四次后把数据依次 push 进数组,就是为了后面按顺序渲染柱子。

删除元素:pop 删末尾,shift 删开头 ​

为什么需要:数组元素需要动态减少。
怎么想:删最后一个用 pop(),删第一个用 shift(),都修改原数组。
怎么做:

数组删除元素示意图

javascript
<script>
  // 删除元素
  // 1. 删除数组中的最后一个元素  数组.pop()  修改原数组
  let arr = ['red', 'green']
// arr.pop()
// console.log(arr.pop())  // 返回的是被删除的元素
// console.log(arr)

// 2. 删除数组中的第一个元素 数组.shift() 修改原数组的
arr.shift()
// console.log(arr.shift())  // 返回的是被删除的元素
console.log(arr)
</script>

易错点:pop/shift 返回被删除的元素,不是数组长度;空数组删除得到 undefined。

splice方法:管中间的增加和删除 ​

为什么需要:push/pop/unshift/shift 只管开头和末尾,中间位置要用 splice。
怎么想:splice(start, deleteCount, item1, item2...),start 从 0 计数;省略 deleteCount 表示删到最后;新增时 deleteCount 写 0。
怎么做:

javascript
<script>
  // splice 删除和增加数组元素
  let arr = ['迪丽热巴', '古丽娜扎', '佟丽丫丫', '玛尔扎哈']
// 1. splice 删除  数组.splice(起始位置, 删除几个)
// arr.splice(1, 1) // 记住起始位置是索引号,从0 开始数
// arr.splice(1) // 如果第二个参数(删除几个)省略了,则默认删除到最后
// console.log(arr)

// 2. splice 增加  数组.splice(起始位置, 删除几个, 新增元素1,...新增元素n)
arr.splice(1, 0, '刘德华', 'pink')
// 2.1 注意如果是新增,则起始位置是目标位置的索引号, 删除几个(第二个参数)不能省略我们写为 0, 后面写新增的元素
console.log(arr)

// 3. splice 不是替换pop shift  unshift push.  arr.splice(0, 1)
// 开头结尾找前面 pop shift  unshift push
// splice管中间
</script>

易错点:start 是索引不是“第几个”;新增时第二个参数要写 0;splice 修改原数组,不要和 slice 混淆。转写稿拓展中提到 sort 排序会修改原数组,升序常写 return a - b,降序写 return b - a,这是后续数组操作中同样要注意“方法是否修改原数组”的思路。

手风琴效果:先看需求 ​

手风琴效果示意

为什么需要:页面里有 7 个结构几乎一样的 div>img,手写 7 次既重复又容易改漏。怎么想:把图片地址放进数组,用循环生成标签;手风琴的展开效果本身由 CSS :hover 和 transition 完成,JS 只负责“批量渲染结构”。怎么做:先注释静态 HTML,再按“空字符串 → 循环拼接 → 放入容器”三步走。易错点:空字符串必须写成 '';遍历数组从 0 开始;不要假设图片名一定是 1.jpg,应从数组取地址。

字符串拼接三步法 ​

为什么需要:要生成多个相似标签,不能一条条手写。怎么想:它和累加和类似,str += ... 就是不断把新标签追加到字符串里。怎么做:① let str = '';② 循环里 str += 模板字符串;③ 用 document.write 把 str 放进 .box。转写稿中的调试过程是:先 console.log(arr[i]) 确认拿到图片地址,再拼接;拼接完 console.log(str) 看到 7 个 div,最后才渲染。易错点:模板字符串里取数组要用 \${arr[i]};document.write 前要确认静态结构已注释,避免页面重复出现两套卡片。

手风琴完整代码 ​

js
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .box {
      display: flex;
      overflow: hidden;
      width: 1120px;
      height: 260px;
      margin: 50px auto;
    }
    .box>div {
      width: 120px;
      border: 1px solid #fff;
      transition: all 0.5s;
    }
    .box>div:hover {
      width: 400px;
    }
  </style>
</head>
<body>
  <script>
    let arr = [
      './images/1.jpg',
      './images/2.jpg',
      './images/3.jpg',
      './images/4.jpg',
      './images/5.jpg',
      './images/6.jpg',
      './images/7.jpg',
    ]

    // 1. 声明一个空的字符串变量 str
    let str = ''

    // 2. 利用for循环拼接字符串 +=
    for (let i = 0; i < arr.length; i++) {
      str += `
      <div><img src="${arr[i]}" alt=""></div>
      `
    }
    console.log(str)

    // 3. 把拼接的字符串放入 box盒子里面
    document.write(`
      <div class="box">
        ${str}
      </div>
    `)
  </script>
</body>
</html>

柱形图:先收集 4 个季度数据 ​

柱形图效果示意

为什么需要:柱子的高度要由用户输入决定,所以必须先保存 4 次输入。怎么想:不要写 4 个 prompt,用循环弹 4 次;输入值要按顺序保存,push 最合适。怎么做:声明空数组 arr;for (let i = 1; i <= 4; i++),用模板字符串提示“第 i 季度”;let num = +prompt(...) 转成数字;arr.push(num)。转写稿中先 console.log(arr) 验证数组里是否是 4 个数字。易错点:prompt 返回字符串,不转数字会影响高度计算;循环变量从 1 开始时,条件要写 <= 4;存数据用 push,不要用索引乱放。

渲染柱子:复用“三步法” ​

为什么需要:4 个柱子结构相似,只有高度、季度、数值不同。怎么想:仍用空字符串拼接,循环数组生成 4 个 div。怎么做:height:\${arr[i]}px;title="第\${i + 1}季度-\${arr[i]}万";span 显示 \${arr[i]}万;h4 显示第 \${i + 1} 季度;最后 document.write 包上 .box。易错点:数组索引从 0 开始,所以季度要 i + 1;高度别漏 px;title、span 中的“万”要和需求一致;先 console.log(str) 看 4 个柱子是否正确再渲染。

柱形图完整代码 ​

js
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * { margin: 0; padding: 0; }
    body { background-color: #0c143d; }
    .box {
      display: flex;
      justify-content: space-around;
      align-items: flex-end;
      width: 800px;
      min-height: 300px;
      border-left: 1px solid #4b578f;
      border-bottom: 1px solid #4b578f;
      margin: 0 auto;
      padding-top: 50px;
      text-align: center;
      color: #9799ab;
    }
    .box>div {
      position: relative;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      width: 40px;
      height: 0;
      background: linear-gradient(#3c99ff, #4489d0, #2283e4);
      cursor: pointer;
      border-radius: 8px 8px 0 0;
      transition: all .2s;
    }
    .box>div:hover { animation: bg .5s alternate infinite; }
    @keyframes bg {
      to {
        box-shadow: 0 5px 29px rgb(53 111 226 / 88%);
        background: linear-gradient(#3c99ff, #68aff6, #2283e4);
      }
    }
    .box>div::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 50%;
      width: 2px;
      height: 10px;
      background-color: #4b578f;
      transform: translate(-50%, 100%);
    }
    .box div span { width: 60px; margin: -30px 0 -5px -6px; }
    .box div h4 { width: 70px; margin: 0 0 -35px -10px; }
    .title { margin-top: 50px; text-align: center; color: #9799ab; }
  </style>
</head>
<body>
  <h3 class="title">2099年季度销售数额(单位万)</h3>
  <script>
    // 功能1:用户输入4次,并且把数据存放到数组里面
    let arr = []
    for (let i = 1; i <= 4; i++) {
      let num = +prompt(`请您输入第${i}季度的销售额`)
      arr.push(num)
    }
    console.log(arr)

    // 功能2:根据数组生成柱形图
    let str = ''
    for (let i = 0; i < arr.length; i++) {
      str += `
        <div style="height: ${arr[i]}px;" title="第${i + 1}季度-${arr[i]}万">
          <span>${arr[i]}万</span>
          <h4>第${i + 1}季度</h4>
        </div>
      `
    }
    console.log(str)

    document.write(`
      <div class="box">
        ${str}
      </div>
    `)
  </script>
</body>
</html>

小结:两个案例的共同套路 ​

两个案例都在练“数据驱动渲染”:先准备数组,再用循环拼接字符串,最后放入容器。手风琴的重点是图片地址来自数组;柱形图的重点是输入值要转数字、高度和季度文案要动态替换。调试时不要一上来就写完整页面,先打印数组,再打印拼接后的 str,确认结构无误后再 document.write,这样排错最快。

课件图示 ​

课件第14页:2. 数组(Array) - 重点 数组:(Array) 是一种数据类型,属于引

课件第15页:1. 声明语法 l 注意事项: Ø 数组是按顺序保存(有序),所以每个数据都有自

课件第17页:总结 总结 1. 数组的作用是什么? Ø 在单个变量名下存储多个数据 Ø 数组也

课件第18页:练习 • 数组练习 需求: ①:请声明一个数组,里面包含4个数据: '迪丽热巴'

课件第19页:2.2 数组的基本使用 3. 遍历数组(重点) l 遍历数组:把数组中每个数据都

课件第20页:2.2 数组的基本使用 3. 遍历数组(重点) 数组元素 数组中数据,也称为数组

课件第25页:2.2 操作数组 l 数组本质是数据集合, 操作数据无非就是 增 删 改 查 语

课件第27页:2.2 操作数组 - 新增元素 数组.push(新增数据) 作用:将一个或多个元

代码示例 ​

示例一:数组的声明、访问、遍历与增删改查 ​

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>数组基本使用</title>
</head>
<body>
  <script>
    // 1. 声明数组
    let names = ['小明', '小刚', '小红', '小丽', '小米']
    // let names = ['小明', '小刚', true, '小丽', 1]
    console.log(names)
    // 1.1 数组是按照顺序来存储的,每个数据都有自己的编号
    // 1.2 编号是从0开始的, 0 1 2 3... 也称为 索引 或者 下标
    // 1.3 数组里面可以存放任意的数据类型

    // 2. 数组取值  数组名[下标]
    console.log(names[0])  // '小明'
    console.log(names[1])  // '小刚'
    console.log(names[2])  // '小红'
    console.log(names[3])  // '小丽'
    console.log(names[4])  // '小米'
  </script>

  <script>
    // 6. 数组单值类型可以是任意数据类型
    // a) 数组单元值的类型为字符类型
    let list = ['HTML', 'CSS', 'JavaScript']
    // b) 数组单元值的类型为数值类型
    let scores = [78, 84, 70, 62, 75]
    // c) 混合多种类型
    let mixin = [true, 1, false, 'hello']
    console.log(list, scores, mixin)
  </script>

  <script>
    // 遍历数组: 把数组里面的数据每个都会访问到
    let arr = ['迪丽热巴', '古丽娜扎', '佟丽丫丫', '玛尔扎哈', '哈尼克孜']

    // 1. 数组的长度 数组.length
    console.log(arr.length)

    for (let i = 0; i < arr.length; i++) {
      console.log(arr[i])
    }
    // 2. 数组里面的数据也称为 数组元素
  </script>

  <script>
    // 1. 查询数组元素
    let arr = ['迪丽热巴', '古丽扎娜']
    console.log(arr[0]) //  '迪丽热巴'
    console.log(arr[1]) //  '古丽扎娜'
    console.log(arr[2]) //  undefined

    // 2. 修改数组元素   数组[索引] = 新值
    arr[1] = '佟丽丫丫'
    arr[3] = '古丽扎娜'  // 如果索引号不存在,则是增加数组元素 (不提倡)
    console.log(arr)
    console.log(arr.length)  // 4 修改了数组长度
  </script>

  <script>
    // 数组新增元素
    // 1. 可以向数组的末尾新增1个或者多个数组元素 数组.push(元素1...元素n)
    let arr = ['迪丽热巴']
    // console.log(arr.push('佟丽丫丫'))  // 返回的是新数组的长度 2
    // arr.push('佟丽丫丫', '古丽扎娜')
    // console.log(arr)  // 修改原数组

    // 2. 可以向数组的开头增加1个或者多个数组元素 数组.unshift(元素1,...元素n)
    // console.log(arr.unshift('佟丽丫丫'))  // 返回的是新数组的长度 2
    arr.unshift('佟丽丫丫', '古丽扎娜')
    console.log(arr) // 修改原数组
  </script>

  <script>
    // 删除元素
    // 1. 删除数组中的最后一个元素  数组.pop()  修改原数组
    let arr = ['red', 'green']
    // arr.pop()
    // console.log(arr.pop())  // 返回的是被删除的元素
    // console.log(arr)

    // 2. 删除数组中的第一个元素 数组.shift() 修改原数组的
    arr.shift()
    // console.log(arr.shift())  // 返回的是被删除的元素
    console.log(arr)
  </script>

  <script>
    // splice 删除和增加数组元素
    let arr = ['迪丽热巴', '古丽娜扎', '佟丽丫丫', '玛尔扎哈']
    // 1. splice 删除  数组.splice(起始位置, 删除几个)
    // arr.splice(1, 1) // 记住起始位置是索引号,从0 开始数
    // arr.splice(1) // 如果第二个参数(删除几个)省略了,则默认删除到最后
    // console.log(arr)

    // 2. splice 增加  数组.splice(起始位置, 删除几个, 新增元素1,...新增元素n)
    arr.splice(1, 0, '刘德华', 'pink')
    // 2.1 注意如果是新增,则起始位置是目标位置的索引号, 删除几个(第二个参数)不能省略我们写为 0, 后面写新增的元素
    console.log(arr)

    // 3. splice 不是替换pop shift  unshift push.  arr.splice(0, 1)
    // 开头结尾找前面 pop shift  unshift push
    // splice管中间
  </script>
</body>
</html>

关键行与易错点

  • let names = ['小明', ...]:数组用 [] 定义,单元之间必须用英文逗号分隔;数组单元可以是任意数据类型(字符、数值、布尔、混合)。
  • names[0]:索引(下标)从 0 开始,不是 1,所以 5 个元素的最大索引是 4。
  • console.log(arr[2]) 查不到时返回 undefined,不是报错。
  • arr[3] = '古丽扎娜':当索引号超出范围时会新增元素并改变 length,课上明确说不提倡这么用,新增请用 push / unshift / splice。
  • arr.push() / arr.unshift() 返回的是新数组长度;arr.pop() / arr.shift() 返回的是被删除的那个元素,且四者都修改原数组。
  • arr.length 用于遍历,写 i < arr.length 而不是写死数字,数组变了循环依然正确。
  • arr.splice(1, 1):第二个参数是删除的个数,省略则从起始位置删到最后;做“新增”时第二个参数必须写 0,否则会误删元素。
  • 多个 <script> 里都用 let arr 不会冲突(各自独立作用域),若写在同一个 <script> 里重复 let 声明会报错。

示例二:综合案例——手风琴效果(循环拼接字符串渲染 7 个 div) ​

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .box {
      display: flex;
      overflow: hidden;
      width: 1120px;
      height: 260px;
      margin: 50px auto;
    }

    .box>div {
      width: 120px;
      border: 1px solid #fff;
      transition: all 0.5s;
    }

    .box>div:hover {
      width: 400px;
    }
  </style>
</head>

<body>
  <!-- <div class="box">
    <div><img src="./images/1.jpg" alt=""></div>
    <div><img src="./images/2.jpg" alt=""></div>
    <div><img src="./images/3.jpg" alt=""></div>
    <div><img src="./images/4.jpg" alt=""></div>
    <div><img src="./images/5.jpg" alt=""></div>
    <div><img src="./images/6.jpg" alt=""></div>
    <div><img src="./images/7.jpg" alt=""></div>
  </div> -->

  <script>
    let arr = [
      './images/1.jpg',
      './images/2.jpg',
      './images/3.jpg',
      './images/4.jpg',
      './images/5.jpg',
      './images/6.jpg',
      './images/7.jpg',
    ]

    // 1. 声明一个空的字符串变量 str
    let str = ''

    // 2. 利用for循环拼接字符串 +=
    for (let i = 0; i < arr.length; i++) {
      // console.log(arr[i])
      str += `
      <div><img src="${arr[i]}" alt=""></div>
      `
    }
    console.log(str)

    // 3. 把拼接的字符串放入 box盒子里面
    document.write(`
      <div class="box">
        ${str}
      </div>
    `)

  </script>
</body>

</html>

关键行与易错点

  • let str = '':必须初始化为空字符串,否则 str += ... 会拼出 undefined...。
  • for (let i = 0; i < arr.length; i++):数组遍历从 0 开始、用 < length,别写成 <=,否则会多拼一个 undefined 的图。
  • str += &#96;...&#96;:核心是累加拼接(原理同累加和),每循环一次就往字符串里追加一个 div。
  • src="\${arr[i]}":图片地址必须从数组里取,不要用 i+1 之类去拼文件名——真实项目里图片名不一定按 1~7 排列,取数组元素才可靠。
  • document.write(...) 把 str 塞进 .box 里渲染;document.write 要在页面加载(渲染)阶段执行才能正确插入,放到事件里会把整个文档覆盖掉。
  • 手风琴的展开/收起是纯 CSS 完成的:.box>div 宽 120px,:hover 变 400px,配合 transition: all 0.5s;JS 只负责生成结构。
  • 图片路径 ./images/1.jpg 需自备素材,路径不对时盒子在但看不到图。

示例三:综合案例——根据输入数据渲染柱形图 ​

js
<!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>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #0c143d;
    }

    .box {
      display: flex;
      justify-content: space-around;
      align-items: flex-end;
      width: 800px;
      min-height: 300px;
      border-left: 1px solid #4b578f;
      border-bottom: 1px solid #4b578f;
      margin: 0 auto;
      padding-top: 50px;
      text-align: center;
      color: #9799ab;
    }

    .box>div {
      position: relative;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      width: 40px;
      height: 0;
      background: linear-gradient(#3c99ff, #4489d0, #2283e4);
      cursor: pointer;
      border-radius: 8px 8px 0 0;
      transition: all .2s;
    }

    .box>div:hover {
      animation: bg .5s alternate infinite;
    }

    @keyframes bg {
      to {
        box-shadow: 0 5px 29px rgb(53 111 226 / 88%);
        background: linear-gradient(#3c99ff, #68aff6, #2283e4);
      }
    }

    .box>div::after {
      content: '';
      position: absolute;
      bottom: 0;
      left: 50%;
      width: 2px;
      height: 10px;
      background-color: #4b578f;
      transform: translate(-50%, 100%);
    }

    .box div span {
      width: 60px;
      margin: -30px 0 -5px -6px;
    }

    .box div h4 {
      width: 70px;
      margin: 0 0 -35px -10px;
    }

    .title {
      margin-top: 50px;
      text-align: center;
      color: #9799ab;
    }
  </style>
</head>

<body>
  <h3 class="title">2099年季度销售数额(单位万)</h3>
  <!-- <div class="box">
    <div style="height: 123px;" title="第1季度-123万">
      <span>123万</span>
      <h4>第1季度</h4>
    </div>
    <div style="height: 156px;" title="第2季度-156万">
      <span>156万</span>
      <h4>第2季度</h4>
    </div>
    <div style="height: 120px;" title="第3季度-120万">
      <span>120万</span>
      <h4>第3季度</h4>
    </div>
    <div style="height: 210px;" title="第4季度-210万">
      <span>210万</span>
      <h4>第4季度</h4>
    </div>
  </div> -->
  <script>
    // 功能1: 用户输入4次,并且把数据存放到数组里面

    // 1.1 声明一个空的数组
    let arr = []

    // 1.2 利用循环的形式让用户输入4次,并且把数据追加给数组
    for (let i = 1; i <= 4; i++) {
      let num = +prompt(`请您输入第${i}季度的销售额`)
      arr.push(num)
    }
    console.log(arr)

    // 功能2:根据数组生成柱形图

    // 2.1 声明一个空的字符串 str
    let str = ''

    // 2.2 利用循环拼接字符串,生成多个柱子
    for (let i = 0; i < arr.length; i++) {
      str += `
        <div style="height: ${arr[i]}px;" title="第${i + 1}季度-${arr[i]}万">
          <span>${arr[i]}万</span>
          <h4>第${i + 1}季度</h4>
        </div>
      `
    }
    console.log(str)

    // 2.3 把生成的柱子放到box盒子里面进行渲染
    document.write(`
      <div class="box">
        ${str}
      </div> 
    `)
  </script>
</body>

</html>

关键行与易错点

  • let num = +prompt(...):prompt 返回的是字符串,用一元 + 转成数字,否则后面拼 height 会出错('200' + 'px' 反而没问题,但数组里存字符串不方便比较)。
  • for (let i = 1; i <= 4; i++):这里从 1 开始、用 <= 4,因为要在提示语里显示“第1季度…第4季度”;和遍历数组的 i = 0; i < arr.length 是两种不同场景,别混。
  • arr.push(num):依次把 4 次输入追加到数组末尾,保持季度顺序。
  • 第二个循环 for (let i = 0; i < arr.length; i++) 又从 0 开始,因为要取 arr[i]。
  • style="height: \${arr[i]}px;":柱子高度由数据决定,数据越大柱子越高——这是整个案例的“活数据”关键行。
  • title="第\${i + 1}季度-\${arr[i]}万" 和 <h4>第\${i + 1}季度</h4>:显示季度要用 i + 1,直接写 i 会出现“第0季度”。
  • let str = '' 空字符串初始化 + str += 累加,最后 document.write 包一层 .box 输出;三步顺序不能乱。
  • 取消 prompt 会返回 null,+null 得到 0,柱子高度就是 0(不会报错,但显示异常)。

常见错误 ​

  1. 遍历多出 undefined 或空标签:现象是最后多访问一次数组、多拼一个空项 → 原因是写成 i <= arr.length → 修法统一用 i < arr.length。
  2. 拼接完字符串但页面不显示:现象是控制台有 HTML,页面空白 → 原因是只做了 str += ...,没有放入容器或 document.write → 修法先打印 str 检查,再渲染到目标容器。
  3. 把 push/pop/shift/unshift 的返回值当数组用:现象是 arr = arr.push(x) 后 arr 变成数字 → 原因是这些方法返回长度或被删除元素,不是原数组 → 修法单独调用方法,不要重新赋值给 arr。
  4. splice 参数写错导致误删或替换:现象是新增元素时删掉了原数据,或省略第二参数删到末尾 → 原因是新增时 deleteCount 必须写 0,省略会删除到末尾 → 修法新增用 arr.splice(start, 0, ...items),删除用 arr.splice(start, count)。
  5. sort() 直接排序结果不符合数值大小:现象是出现 100, 99, 78... 这类顺序 → 原因是默认按字符串/字符比较 → 修法数值升序用 arr.sort((a, b) => a - b),降序用 (a, b) => b - a。
  6. 渲染季度时显示“第0季度”:现象是序号从 0 开始 → 原因是直接用了数组索引 i 作为展示序号 → 修法展示层用 i + 1,索引用 i。

练习 ​

  1. 给定数组 ['HTML', 'CSS', 'JS'],用 for 循环输出“索引-元素”,要求不能出现 undefined。
  2. 对数组 ['red', 'green'] 依次执行 push、unshift、pop、shift、splice,记录每步后的数组和返回值。
  3. 根据图片地址数组,循环拼接 7 个 <div><img></div>,并渲染到 .box 容器中。
  4. 对成绩数组 [78, 84, 70, 62, 75] 分别做数值升序、降序,并取出最高分和最低分。
  5. 用选择排序处理 [4, 2, 5, 1, 3],写出外层轮数、minIndex 的记录方式,以及何时交换。

原视频对照 ​

#视频时长
1综合案例-手风琴案例13:02
2综合案例-渲染柱形图弹出4次输入框08:44
3综合案例-渲染柱形图渲染柱子09:08
4拓展知识-数组sort排序07:49
5拓展了解-选择排序13:24

小结 ​

  1. 数组适合在单个变量下管理多个相关数据,索引从 0 开始,length 表示元素个数。
  2. 查询用 arr[i],越界查询得到 undefined;越界赋值会扩长度,但不推荐依赖。
  3. 遍历数组优先用 i < arr.length;展示序号时通常用 i + 1。
  4. push/pop 管尾部,unshift/shift 管头部,splice 管中间;这些方法都会修改原数组。
  5. 批量渲染标签可固定为三步:空字符串 → 循环 += 拼接 → 放入容器渲染。
  6. 数值排序必须给 sort 传比较函数,不能直接依赖默认排序。
  7. 选择排序要抓住三点:外层控制轮数、内层找最小值索引、本轮结束后再交换。
  8. 写数组代码时优先使用标准 API 和清晰命名,避免越界赋值、返回值误用等隐式行为。