Skip to content

1-8分支+循环综合案例 ​

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

学习目标 ​

  • 能使用 while (true) 编写循环菜单,并通过 prompt 反复接收用户操作输入。
  • 能将 prompt 获取的字符串转换为数字类型,确保比较和运算时数据类型一致。
  • 能使用 if / else if 多分支语句实现取款、存款、查看余额和退出四类操作。
  • 能声明并维护 money 变量记录银行卡余额,正确完成金额累加、扣减与重新赋值。
  • 能使用 break 在用户输入退出指令时结束无限循环,避免产生死循环。
  • 能使用赋值运算符简化余额计算,并在程序结束后输出最终银行卡余额。

知识点 ​

综合案例总览 ​

本节做两个综合案例:手风琴效果、根据数据渲染柱形图。它们共同的核心是:准备数据 → 循环遍历 → 拼接字符串 → 放入页面容器渲染。
为什么需要?因为页面中重复结构很多,手写会冗余且难维护;数据一变,结构就应跟着变。怎么想?先问“重复的部分是什么”,再问“数据放在哪里”,最后用循环把数据塞进模板字符串。怎么做?声明空字符串 str,循环里用 += 拼接,最后用 document.write 或容器渲染。易错点:str 要声明在循环外;模板字符串要用反引号;${} 中写变量;拼接字符串时的 + 是拼接,不是数值加法。转写稿里反复强调“prompt 取回的是字符串、类型要统一、循环要有退出条件”,这些调试意识同样适用于本节:先检查数据类型,再检查循环边界,最后检查拼接结果。

手风琴效果:用循环拼接结构 ​

手风琴效果

为什么需要?手风琴有 7 个重复的 <div><img></div>,手写容易漏、改路径麻烦。怎么想?把 7 张图片路径放进数组,用循环生成相同结构。怎么做?① 声明空字符串 let str = '';② 循环中 str += &#96;<div><img src="\${arr[i]}" alt=""></div>&#96;;③ 把 str 放进 .box 容器。易错点:str 必须写在循环外,否则每次都被清空;模板字符串必须用反引号;图片路径要用 \${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>
  <!-- <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>

柱形图:先收集数据,再按数据渲染 ​

柱形图效果

为什么需要?柱子的高度由用户输入的季度数据决定,不能写死。怎么想?先输入 4 次并存进数组,再遍历数组生成 4 个柱子。怎么做?① 声明空数组 arr;② 用 for (let i = 1; i <= 4; i++) 弹出 prompt,用 +prompt(...) 转数字后 push;③ 声明空字符串 str;④ 遍历 arr,拼接 <div style="height: \${arr[i]}px;" title="第\${i + 1}季度-\${arr[i]}万">...;⑤ 用 document.write 把 .box 和 str 写入页面。易错点:prompt 返回字符串,必须用 + 或 Number() 转数字;渲染时索引 i 从 0 开始,所以季度文字用 i + 1;高度要带 px;模板字符串别漏反引号。转写稿中“先准备金额变量,再在循环里做加减”的思路,对应到这里就是“先准备数组和字符串容器,再循环生成结构”。

柱形图完整代码 ​

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>
    * {
      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>

调试与检查清单 ​

转写稿里出现的同音字要纠正:well 是 while,prot 是 prompt,复制运算符 是“赋值运算符”,简等/甲等 是“减等/加等”,ca是S 是 Ctrl+S。本节调试可照这个顺序:先用 console.log(str) 看拼接结果;再检查 prompt 数据是否转成数字;再检查模板字符串是否用反引号;最后检查循环外变量是否被误放循环内。两个案例都不是无限循环,但“循环要有明确边界、变量要在正确作用域”同样关键。

小结 ​

手风琴案例练“数组 + 循环拼接 + 容器渲染”;柱形图案例练“先收集数据,再按数据生成结构”。记住三步:空字符串/空数组先准备,循环里 += 或 push,最后统一渲染。检查时优先看类型、模板字符串和作用域。

先看问题:为什么要学排序 ​

数组里的数据经常需要“按大小排好”,比如成绩排名、价格从低到高、取最大值最小值。笔记先讲内置方法 sort(),再讲选择排序,是为了让你既会“用工具”,也理解“排序算法大概怎么想”。转写稿里反复强调调试时要先分析流程、再验证结果;排序同样要这样:先看默认结果对不对,再决定是否传比较函数。

数组排序 sort:为什么需要 → 怎么想 → 怎么做 → 易错点 ​

为什么需要:手写排序麻烦,数组.sort() 可以直接排序,并且会修改原数组。
怎么想:先记住默认 sort() 不一定按数字大小排,而是容易按字符串规则比较;要按数值升序/降序,需要传入比较函数。比较函数返回 a - b 表示升序,返回 b - a 表示降序。
怎么做:保留笔记代码如下。

javascript
<script>
  // 数组排序  数组.sort()  修改原数组
  let arr = [88, 78, 100, 34, 99]
  // arr.sort()
  // console.log(arr)  // [100, 34, 78, 88, 99]

  // 1. 升序排序
  // arr.sort(function (a, b) {
  //   return a - b
  // })
  // console.log(arr)  // [34, 78, 88, 99, 100]

  // 2. 降序排序
  arr.sort(function (a, b) {
    return b - a
  })
  console.log(arr)  //  [100, 99, 88, 78, 34]

  // 3. 获取数组最大值和最小值
  document.write(`数组的最大值:${arr[0]}`)
  document.write(`数组的最小值:${arr[arr.length - 1]}`)
</script>

易错点:arr.sort() 不传比较函数时,100 可能排在 34 前面,因为默认不是按数值减法比较;比较函数要 return a - b,不要写成 return a > b;sort() 会改原数组;排序后取最值要注意当前是升序还是降序。

选择排序:为什么需要 → 怎么想 → 怎么做 → 易错点 ​

为什么需要:理解排序算法的基本过程,训练循环嵌套、索引交换和边界控制。算法可视化网站地址:https://visualgo.net/zh/sorting 。
怎么想:从第一个位置开始,假设它是最小值索引 minIndex,然后与后面所有元素比较,发现更小的就把 minIndex 改成那个元素的索引;一轮结束后,如果 minIndex 不在当前起点 i,就交换。每一轮确定一个相对最小值。
怎么做:保留笔记代码如下。

javascript
<script>
  // 选择排序算法
  let arr = [4, 2, 5, 1, 3]
  // 1  [1, 2, 5, 4, 3]
  // 2  [1, 2, 5, 4, 3]
  // 3  [1, 2, 3, 4, 5]
  // 4  [1, 2, 3, 4, 5]

  // 1. 外层循环控制是几轮能够比较出来
  for (let i = 0; i < arr.length - 1; i++) {
    // 最小值的索引号
    let minIndex = i

    // 2. 里层循环来查找最小值,并且记录最小值的索引号
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j
      }
    }

    // 3. 交换变量
    if (minIndex !== i) {
      let temp = arr[minIndex]
      arr[minIndex] = arr[i]
      arr[i] = temp
    }
  }
  console.log(arr)
</script>

易错点:外层只跑 arr.length - 1 轮;minIndex 每轮要重置为 i;内层从 i + 1 开始;交换前判断 minIndex !== i;交换要借助 temp,不要直接覆盖。调试时可以像转写稿里强调的那样,先确认数据类型和条件是否一致,再打印每轮 arr 观察变化;转写稿中的“well、pro、预算符”应纠正为 while、prompt、运算符,这种“先定位类型与条件”的调试意识同样适用于排序。

课件图示 ​

课件第43页:拓展 - 数组排序 l 数组. sort() 方法可以排序 l 语法: l 数组

代码示例 ​

示例一:手风琴效果(循环拼接字符串 + 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++) {
      // 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 = '' 是“累加和”思想的字符串版本:先准备空字符串,再在循环里 += 累加,循环结束后一次性渲染。
  • 拼接模板里必须用反引号,图片路径用 \${arr[i]} 插值;若写成单/双引号,\${} 不会解析,页面只会出现一段普通文本。
  • 用 document.write() 输出整个结构,所以 HTML 里不能再手写 <div class="box">(笔记里已注释掉),否则会多渲染一份。
  • 循环条件用 i < arr.length,不要写 <=,否则最后会拼出一个 src="undefined" 的坏图。

示例二:根据数据渲染柱形图(prompt 收集数据 + 拼接渲染) ​

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>
  <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(...) 前的 + 是把字符串转成数字型;少了它,arr 里存的是字符串,后面 height: \${arr[i]}px 虽然还能用,但后续任何加减运算都会变成字符串拼接。
  • 收集数据用 arr.push(num),不要用 arr = num,否则数组被覆盖成单个值,柱子只剩一根。
  • 柱子高度是行内样式 style="height: \${arr[i]}px;",CSS 里 .box>div 的 height: 0 会被行内样式覆盖,这是柱形图能“长出来”的原因。
  • 索引与季度号的对应:循环变量 i 从 0 开始,所以文案里写 第\${i + 1}季度,这是最常见的差一错误。

示例三:简易 ATM 存取款机(while 无限循环 + if 多分支) ​

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>
</head>

<body>
  <script>
    // 提前声明金额变量,注意要写在 while 循环外面
    let money = 100

    // 无限循环:页面一打开就不断弹窗
    while (true) {
      let number = +prompt(`请选择你的操作:
      1 取款
      2 存款
      3 查看余额
      4 退出`)

      if (number === 1) {
        // 取款
        let qu = +prompt('请你输入取款金额')
        money -= qu          // 等价于 money = money - qu
      } else if (number === 2) {
        // 存款
        let cun = +prompt('请你输入存款金额')
        money += cun         // 等价于 money = money + cun
      } else if (number === 3) {
        // 查看余额
        alert(`你的银行卡余额是${money}元`)
      } else if (number === 4) {
        // 退出条件:只有输入 4 才 break
        break
      }
    }

    // 循环结束之后输出提示
    document.write(`你的银行卡余额为${money}元,请节约消费`)
  </script>
</body>

</html>

关键行与易错点

  • let money = 100 必须写在 while 外面;写进循环里,每轮都被重置成 100,存取款就白做了。
  • +prompt(...) 的加号是重点:prompt 取回的是字符串,若直接和数字用 === 比较,'4' === 4 永远为 false,break 永不执行,页面就变成死循环弹窗。
  • money -= qu / money += cun 是复合运算符的简写,等价于 money = money - qu 和 money = money + cun;用 += 做加法时两侧必须都是数字,否则会变成字符串拼接(如 100 变成 100100)。
  • 最后一个分支用 else if (number === 4) 而不是 else:否则用户输入 5、6、任意字符都会退出,逻辑不严谨。
  • 无限循环一定要有 break 退出条件,这是 while (true) 能安全使用的前提。

常见错误 ​

  1. ATM 中输入 4 无法退出:现象是弹窗一直循环;原因是 prompt 返回字符串,与数字比较不相等;修法是先 +prompt(...) 或 Number(...),再比较。
  2. 存款后余额变成拼接结果:现象是 100 + 100 得到 100100;原因是取款/存款金额未转数字;修法是输入金额后立即转数字,再进行 += 或 -=。
  3. 余额每次都被重置:现象是存取后余额不累积;原因是 money 声明在 while 内部;修法是把 money 声明在循环外。
  4. 无限循环停不下来:现象是页面一直弹窗;原因是缺少可达的 break 或退出分支写错;修法是在明确条件分支内写 break,并先用 console.log 验证输入值。
  5. 手风琴/柱形图页面空白:现象是只看到空容器或原始结构;原因是拼接了 str 但未放入容器;修法是确认 document.write(...) 或 innerHTML 使用了最终 str。
  6. 数字排序结果不对:现象是 100 排在 34 前面;原因是 sort() 未传比较函数,按字符串比较;修法是升序 a - b、降序 b - a。

练习 ​

  1. 改造 ATM:当用户输入不是 1~4 时提示“请输入正确操作”,且余额不足时禁止取款。
  2. 用数组保存 7 张图片路径,循环拼接成手风琴结构并渲染到 .box 中。
  3. 输入 4 个季度销售额,非数字时提示重输,并按最大值等比缩放柱形图高度。
  4. 对 [88, 78, 100, 34, 99] 分别完成升序、降序,并输出最大值和最小值。
  5. 用选择排序处理 [4, 2, 5, 1, 3],每轮结束后打印当前数组,观察交换过程。

原视频对照 ​

#视频时长
1综合案例-ATM存取款机上06:20
2综合案例-ATM存取款机下11:25

小结 ​

  1. 交互输入先统一数据类型,再比较和运算。
  2. 累计状态变量应放在循环外,循环内只更新状态。
  3. 无限循环必须有明确、可达的退出条件。
  4. 批量渲染先拼字符串,最后必须挂载到容器。
  5. 数字排序不要依赖默认 sort(),要显式写比较函数。
  6. 选择排序重点检查 minIndex 初始值、内层起点和交换条件。
  7. 调试时优先打印输入类型、累计变量、数组和拼接结果。