Vue从入门到实战Day02

一、指令补充

1. 指令修饰符

通过 “.”指明一些指令后缀,不同后缀封装了不同的处理操作 -> 简化代码

键盘按键修饰符

如:keyup.enter -> 键盘回车监听

常用按键修饰符别名
别名修饰符键值修饰符对应按键
.delete.8/.46回格 / 删除
.tab.9制表
.enter.13回车
.esc.27退出
.space.32空格
.left.37
.up.38
.right.39
.down.40

示例1:Day01中的《小黑记事本》案列,实现在输入框回车即添加任务

示例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>Document</title>
</head>
<body>
  <div id="app">
    <h3>@keyup.enter  →  监听键盘回车事件</h3>
    <input v-model="username" type="text" @keyup.enter="fn()">
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: ''
      },
      methods: {
        fn(e) {
            console.log('键盘回车的时候触发', this.username)
        }
      }
    })
  </script>
</body>
</html>

效果:

鼠标按键修饰符

如:@click.left -> 左键监听

鼠标按键修饰符
修饰符可用版本对应按键
.left2.2.0以上左键
.right2.2.0以上右键
.middle2.2.0以上中键

组合修饰符

如:@click.ctrl  -> 监听Ctrl键

系统按钮修饰符
修饰符可用版本对应按键
.ctrl2.1.0以上Ctrl键
.alt2.1.0以上Alt键
.shift2.1.0以上Shift键
.meta2.1.0以上meta键(Windows系统键盘上的 田 键)

v-model修饰符

可用于v-model的修饰符
修饰符可用版本说明
.lazy所有将用户输入的数据赋值于变量的时机由输入时延迟到数据改变时
.number所有自动转换用户输入为数值类型
.trim所有自动过滤用户输入的首尾空白字符

事件修饰符

常见的事件修饰符
名称可用版本可用事件说明
.stop所有任意当事件触发时,阻止事件冒泡
.prevent所有任意当事件触发时,阻止元素默认行为
.capture所有任意当事件触发时,阻止事件捕获
.self所有任意阻止事件仅作用域节点自身
.once2.14以上任意事件被触发一次后即解除监听
.passive2.3.0以上滚动移动端,限制事件永不调用preventDefault()方法

示例:

<!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>
    .father {
      width: 200px;
      height: 200px;
      background-color: pink;
      margin-top: 20px;
    }
    .son {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div id="app">
    <h3>v-model修饰符 .trim .number</h3>
    姓名:<input v-model.trim="username" type="text"><br>
    年纪:<input v-model.number="age" type="text"><br>

    
    <h3>@事件名.stop     →  阻止冒泡</h3>
    <!-- 冒泡是由内到外的,捕获是外到内的 -->
    <div @click="fatherFn" class="father">
      <div @click.stop="sonFn" class="son">儿子</div>
    </div>

    <h3>@事件名.prevent  →  阻止默认行为</h3>
    <!-- 默认点击链接会进行跳转 -->
    <a @click.prevent href="http://www.baidu.com">阻止默认行为</a>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>


  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        age: '',
      },
      methods: {
        fatherFn () {
          alert('老父亲被点击了')
        },
        sonFn () {
          alert('儿子被点击了')
        }
      }
    })
  </script>
</body>
</html>

效果:

2. v-bind对于样式操作的增强

2-1 操作class

语法::class = "对象/数组"

对象 -> 键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类

适用场景:一个类名,来回切换

<div class="box" :class="{类名1:布尔值, 类名2:布尔值}"></div>

数组 -> 数组中所有的类,都会添加到盒子上,本质就是一个class列表

适用场景:批量添加或删除类

<div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>

示例1:

<!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>
    .box {
      width: 200px;
      height: 200px;
      border: 3px solid #000;
      font-size: 30px;
      margin-top: 10px;
    }
    .pink {
      background-color: pink;
    }
    .big {
      width: 300px;
      height: 300px;
    }
  </style>
</head>
<body>

  <div id="app">
    <!-- 对象 -->
    <div class="box" :class="{pink: false, big: true}">黑马程序员</div>
    <!-- 数组 -->
    <div class="box" :class="['pink', 'big']">黑马程序员</div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>
</html>

效果:

示例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>Document</title>
  <style>
    .color-gray {color: gray}
    .size-18 {font-size: 18px}
    .style-italic {font-style: italic}
  </style>
</head>
<body>

  <div id="app">
    <p class = "color-gray size-18 style-italic"> 《Vue从入门到实战》</p>
    <p :class="classStr"> 《Vue从入门到实战》</p>
    <p :class="classArr"> 《Vue从入门到实战》</p>
    <p :class="classObj1"> 《Vue从入门到实战》</p>
    <p :class="classObj2"> 《Vue从入门到实战》</p>
    
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        classStr: 'color-gray size-18 style-italic',  // 拼接字符串
        classArr: ['color-gray', 'size-18', 'style-italic'],  // 数组
        classObj1: {
            // 对象,绑定类名
            'color-gray': true,
            'size-18': true,
            'style-italic': true
        },
        classObj2: {
            // 对象,未绑定类名
            'color-gray': 0,
            'size-18': '',
            'style-italic': false
        }
      }
    })
  </script>
</body>
</html>

效果:

扩展:当变量值为undefined、null、值为0的数字、空字符串、false 时,会被判定为假;除一般值外,[]、{}、-1、-0.1也会被判定为真。

案例:京东秒杀tab导航高亮

核心思路:①基于数据动态渲染;②准备下标记录高亮的是哪一个tab;③基于下标,动态控制class类名

<!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;
    }
    ul {
      display: flex;
      border-bottom: 2px solid #e01222;
      padding: 0 10px;
    }
    li {
      width: 100px;
      height: 50px;
      line-height: 50px;
      list-style: none;
      text-align: center;
    }
    li a {
      display: block;
      text-decoration: none;
      font-weight: bold;
      color: #333333;
    }
    li a.active {
      background-color: #e01222;
      color: #fff;
    }

  </style>
</head>
<body>

  <div id="app">
    <ul>
        <li v-for="(item, index) in list" :key="item.id" @click="activeIndex = index">
            <a :class="{active: index === activeIndex }" href="#">{{ item.name }}</a>
        </li>
    </ul>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex: 0,  // 记录高亮
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]

      }
    })
  </script>
</body>
</html>

效果:

2-2 操作style

语法::style = '样式对象'

<div class="box" :style="{CSS属性名1:CSS属性值, CSS属性名2: CSS属性值}"</div>

适用场景:某个具体属性的动态设置

示例1:

<!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>
    .box {
      width: 200px;
      height: 200px;
      background-color: rgb(187, 150, 156);
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="box" :style="{width: '400px', height: '400px', 'background-color': 'green'}"></div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>
</html>

效果:

示例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>Document</title>
  <style>
    .progress {
      height: 25px;
      width: 400px;
      border-radius: 15px;
      background-color: #272425;
      border: 3px solid #272425;
      box-sizing: border-box;
      margin-bottom: 30px;
    }
    .inner {
      width: 50%;
      height: 20px;
      border-radius: 10px;
      text-align: right;
      position: relative;
      background-color: #409eff;
      background-size: 20px 20px;
      box-sizing: border-box;
      transition: all 1s;
    }
    .inner span {
      position: absolute;
      right: -20px;
      bottom: -25px;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- 外层盒子底色(黑色) -->
    <div class="progress">
      <!-- 内层盒子 —— 进度(蓝色)   -->
      <div class="inner" :style="{ width: percent + '%'}">
        <span>{{ percent }}</span>
      </div>
    </div>
    <button @click="percent = 25">设置25%</button>
    <button @click="percent = 50">设置50%</button>
    <button @click="percent = 75">设置75%</button>
    <button @click="percent = 100">设置100%</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        percent: 50
      }
    })
  </script>
</body>
</html>

效果:

示例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>Document</title>
</head>
<body>
  <div id="app">
    <p style="color: gray; font-size: 18px; font-style: italic;"> 《Vue从入门到实战》</p>
    <p :style="styleStr">《Vue从入门到实战》</p>
    <p :style="styleObj1">《Vue从入门到实战》</p>
    <p :style="styleObj2">《Vue从入门到实战》</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        styleStr: 'color: gray; font-size: 18px; font-style:italic;',  // 拼接字符串
        styleObj1: {
            // 对象,绑定样式
            'color': -1 ? 'gray' : 'black',
            'font-size': '18px',
            'font-style': 'italic'
        },
        styleObj2: {
            // 对象,未绑定样式
            'color': 0 ? 'gray' : '',
            'font-size': '' ? '18px' : '',
            'font-style': null ? 'italic' : ''
        }
      }
    })
  </script>
</body>
</html>

效果:

3. v-model应用于其他表单元素

①输入框 input:text;②文本域 textarea;③复选框 input:checkbox;④单选框 input:radio;⑤下拉菜单 select

常见的表单元素都可以用v-model绑定关联 -> 快速获取 或 设置 表单元素的值

示例1:

<!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>
    textarea {
      display: block;
      width: 240px;
      height: 100px;
      margin: 10px 0;
    }
  </style>
</head>
<body>

  <div id="app">
    <h3>小黑学习网</h3>
    <!-- 单行文本框 -->
    姓名:
      <input type="text" v-model="username"> 
      <br><br>

    <!-- 单个复选框 -->
    是否单身:
      <input type="checkbox" v-model="isSingle"> 
      <br><br>

    <!-- 
      前置理解:
        1. name:  给单选框加上 name 属性 可以分组 → 同一组互相会互斥
        2. value: 给单选框加上 value 属性,用于提交给后台的数据
      结合 Vue 使用 → v-model
    -->
    性别: 
      <input v-model="gender" type="radio" name="gender" value="1">男
      <input v-model="gender" type="radio" name="gender" value="2">女
      <br><br>

    <!-- 
      前置理解:
        1. option 需要设置 value 值,提交给后台
        2. select 的 value 值,关联了选中的 option 的 value 值
      结合 Vue 使用 → v-model
    -->
    所在城市:
      <select v-model="cityId">
        <option value="101">北京</option>
        <option value="102">上海</option>
        <option value="103">成都</option>
        <option value="104">南京</option>
      </select>
      <br><br>

    自我描述:
      <textarea v-model="desc"></textarea> 

    <button>立即注册</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        isSingle: false,
        gender: '1',
        cityId: '101',
        desc: ''
      }
    })
  </script>
</body>
</html>

效果:

示例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>Document</title>
</head>
<body>

  <div id="app">
    <h3>单行文本框</h3>
    <input type="text" v-model="singleText" style="width: 240px;">
    <p> {{ singleText }}</p>
    
    <h3>多行文本框</h3>
    <textarea v-model="multiText" style="width: 240px;"></textarea>
    <pre> {{ multiText }}</pre>

    <h3>单选框</h3>
    <!-- 由于点击被选中的单选项无法取消其被选中状态,所以实战中一般没有使用单个单选项的场景
    这里,设置v-model共用一个变量(radioValue)可实现RadioGroup的效果
    -->
    <input id="ra" type="radio" value="杨玉环" v-model="radioValue">
    <label for="ra">A.杨玉环</label>
    <input id="rb" type="radio" value="赵飞燕" v-model="radioValue">
    <label for="rb">B.赵飞燕</label>
    <p>{{ radioValue }}</p>

    <h3>单个复选框</h3>
    <!-- 单个复选框被用于true和false的切换 -->
    <input id="c" type="checkbox" v-model="toggleValue">
    <label for="c">天生丽质</label>
    <p>{{ toggleValue }}</p>

    <h3>多个复选框</h3>
    <!--多个复选框,v-model接收数组类型变量-->
    <input id="ca" type="checkbox" value="漂亮" v-model="checkedValues">
    <label for="ca">A.回眸一笑百媚生</label>
    <input id="cb" type="checkbox" value="瘦弱" v-model="checkedValues">
    <label for="cb">B.体轻能为掌上舞</label>
    <input id="cc" type="checkbox" value="得宠" v-model="checkedValues">
    <label for="cc">C.三千宠爱在一身</label>
    <p>{{ checkedValues.join(', ') }}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        singleText: '',
        multiText: '',
        radioValue: '',
        toggleValue: false,
        checkedValues: []
      }
    })
  </script>
</body>
</html>

效果:

二、computed计算属性

1. 基础语法

概念:基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算

语法:

①声明在computed配置项中,一个计算属性对应一个函数;

②使用起来和普通属性一样使用 {{ 计算属性名 }}

计算属性默认的简写,只能读取访问,不能“修改”

computed: {
    计算属性名 () {
        基于现有数据,编写求值逻辑
        return 结果
    }
}

示例:

<!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>
    table {
      border: 1px solid #000;
      text-align: center;
      width: 240px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
  </style>
</head>
<body>

  <div id="app">
    <h3>小黑的礼物清单</h3>
    <table>
      <tr>
        <th>名字</th>
        <th>数量</th>
      </tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}</td>
        <td>{{ item.num }}个</td>
      </tr>
    </table>

    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数:{{ totalCount }} 个</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 3 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed: {
        totalCount() {
            // 基于现有的数据,编写求值逻辑
            // 计算属性函数内部,可以直接通过this访问到app实例
            // 需求:对this.list数组里面的num进行求和 -> reduce
            // sum是累加器,初始值为0,item是数组中的当前元素.将累加器和当前元素的num属性相加
            return this.list.reduce((sum, item) => sum + item.num, 0)
        }
      }
    })
  </script>
</body>
</html>

效果:

2. 计算属性 vs 方法

computed计算属性

作用:封装了一段对于数据的处理,求得一个结果。

语法:

①写在computed配置项中;

②作为属性,直接使用 -> this.计算属性 {{ 计算属性 }}

缓存特性(提升性能):计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算 -> 并再次缓存

methods方法

作用:给实例提供一个方法,调用以处理业务逻辑。

语法:

①写在methods配置项中;

②作为方法,需要调用 -> this.方法名()  {{ 方法名() }} @事件名="方法名"

示例

<!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>
    table {
      border: 1px solid #000;
      text-align: center;
      width: 300px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
    span {
      position: absolute;
      left: 145px;
      top: -4px;
      width: 16px;
      height: 16px;
      color: white;
      font-size: 12px;
      text-align: center;
      border-radius: 50%;
      background-color: #e63f32;
    }
  </style>
</head>
<body>

  <div id="app">
    <h3>小黑的礼物清单🛒<span>{{ totalCount }}</span></h3>
    <h3>小黑的礼物清单🛒<span>{{ totalCount }}</span></h3>
    <h3>小黑的礼物清单🛒<span>{{ totalCount }}</span></h3>
    <table>
      <tr>
        <th>名字</th>
        <th>数量</th>
      </tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}</td>
        <td>{{ item.num }}个</td>
      </tr>
    </table>

    <p>礼物总数:{{ totalCount }} 个</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 3 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      methods: {
        totalCountFn () {
            console.log('methods方法执行了')
          let total = this.list.reduce((sum, item) => sum + item.num, 0)
          return total
        }
      },
      computed: {
        // 计算属性:有缓存,一旦计算出来结果,就会立即缓存
        // 下一次读取 -> 直接读取缓存即可
        // 如果数据发生变化,会自动重新计算,并缓存结果
        totalCount () {
            console.log('计算属性执行了')
          let total = this.list.reduce((sum, item) => sum + item.num, 0)
          return total
        }
      }
    })
  </script>
</body>
</html>

computed计算属性:调用4次,只计算1次

methods方法:调用4次,计算4次

3. 完整写法

计算属性默认的简写,只能读取访问,不能“修改”

如果要“修改”,需要写计算属性的完整写法

语法:

computed: {
    计算属性名: {
        get()  {
            一段代码逻辑(计算逻辑)
            return 结果
        },
        set(修改的值) {
            一段代码逻辑(修改逻辑)
        }
    }
}

示例:

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

  <div id="app">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName"><br>
    <p>姓名:{{ fullName }}</p>
    <button @click="changeName">修改姓名</button>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        firstName: '',
        lastName: ''
      },
      computed: {
        // 简写 -> 获取,没有配置 设置 的逻辑
        // fullName() {
        //     return this.firstName + this.lastName
        // }

        // 完整写法 -> 获取 + 设置
        fullName: {
            // 当fullName计算属性,被获取求值时,执行get(有缓存读缓存)
            // 会将返回值作为求值的结果
            get() {
                return this.firstName + this.lastName
            },
            // 当fullName计算属性,被修改赋值时,执行set方法
            // 修改的值,传递给set方法的形参
            set(value) {
                console.log(value)
                this.firstName = value.slice(0, 1)
                this.lastName = value.slice(1)
            }
        }
      },
      methods: {
        changeName() {
            this.fullName = '吕小布'
        }
      }
    })
  </script>
</body>
</html>

效果:

4. 成绩案列

需求说明:①渲染功能;②删除功能;③添加功能;④统计总分,求平均分

<!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" />
    <link rel="stylesheet" href="./styles/index.css" />
    <title>Document</title>
  </head>
  <body>
    <div id="app" class="score-case">
      <div class="table">
        <table>
          <thead>
            <tr>
              <th>编号</th>
              <th>科目</th>
              <th>成绩</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody v-if="list.length > 0">
            <tr v-for="(item, index) in list" :key="item.id">
              <td>{{ item.id }}</td>
              <td>{{ item.subject }}</td>
              <!-- 小于60分的标红 -->
              <td :class="{ red: item.score < 60 }">{{ item.score }}</td>
              <td><a @click.prevent="del(item.id)" href="#">删除</a></td>
            </tr>
          </tbody>

          <tbody v-else>
            <tr>
              <td colspan="5">
                <span class="none">暂无数据</span>
              </td>
            </tr>
          </tbody>

          <tfoot>
            <tr>
              <td colspan="5">
                <span>总分:{{ totalScore }}</span>
                <span style="margin-left: 50px">平均分:{{ aveScore }}</span>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
      <div class="form">
        <div class="form-item">
          <div class="label">科目:</div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入科目"
              v-model.trim="subject"
            />
          </div>
        </div>
        <div class="form-item">
          <div class="label">分数:</div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入分数"
              v-model.number="score"
            />
          </div>
        </div>
        <div class="form-item">
          <div class="label"></div>
          <div class="input">
            <button class="submit" @click="add">添加</button>
          </div>
        </div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>


    <script>
      const app = new Vue({
        el: '#app',
        data: {
          list: [
            { id: 1, subject: '语文', score: 20 },
            { id: 7, subject: '数学', score: 99 },
            { id: 12, subject: '英语', score: 70 },
          ],
          subject: '',
          score: ''
        },
        methods: {
            del(id) {
                this.list = this.list.filter(res => res.id !== id)
            },
            add() {
                if(!this.subject) {
                    alert('请输入科目!')
                    return
                }
                if(this.score > 100 || this.score < 0 || typeof this.score !== 'number') {
                    alert('请输入正确的成绩!')
                    return
                }
                this.list.unshift({
                    id: +new Date(),
                    subject: this.subject,
                    score: this.score
                })
                this.subject = ''
                this.score = ''
            }
        },
        computed: {
           totalScore() {
                return this.list.reduce((sum, item) => sum + item.score, 0)
            },
            aveScore() {
                if(this.list.length === 0) {
                    return 0
                }
                return (this.totalScore / this.list.length).toFixed(2)
            }
        }
      })
    </script>
  </body>
</html>

效果:

三、watch侦听器(监视器)

作用:监视数据变化,执行一些业务逻辑 或 异步操作。

语法:

①简单写法:简单类型数据,直接监视

data: {
    words: '苹果',
    obj: {
        words: '苹果'
    }
},
watch: {
    // 该方法会在数据变化时,触发执行
    数据属性名(newValue, odlValue) {
        一些业务逻辑或异步操作
    },
    '对象.属性名'(newValue, oldValue) {
        一些业务逻辑或异步操作
    }
}

示例:

<!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;
        box-sizing: border-box;
        font-size: 18px;
      }
      #app {
        padding: 10px 20px;
      }
      .query {
        margin: 10px 0;
      }
      .box {
        display: flex;
      }
      textarea {
        width: 300px;
        height: 160px;
        font-size: 18px;
        border: 1px solid #dedede;
        outline: none;
        resize: none;
        padding: 10px;
      }
      textarea:hover {
        border: 1px solid #1589f5;
      }
      .transbox {
        width: 300px;
        height: 160px;
        background-color: #f0f0f0;
        padding: 10px;
        border: none;
      }
      .tip-box {
        width: 300px;
        height: 25px;
        line-height: 25px;
        display: flex;
      }
      .tip-box span {
        flex: 1;
        text-align: center;
      }
      .query span {
        font-size: 18px;
      }

      .input-wrap {
        position: relative;
      }
      .input-wrap span {
        position: absolute;
        right: 15px;
        bottom: 15px;
        font-size: 12px;
      }
      .input-wrap i {
        font-size: 20px;
        font-style: normal;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 条件选择框 -->
      <div class="query">
        <span>翻译成的语言:</span>
        <select>
          <option value="italy">意大利</option>
          <option value="english">英语</option>
          <option value="german">德语</option>
        </select>
      </div>

      <!-- 翻译框 -->
      <div class="box">
        <div class="input-wrap">
          <!-- <textarea v-model="words"></textarea> -->
          <textarea v-model="obj.words"></textarea>
          <span><i>⌨️</i>文档翻译</span>
        </div>
        <div class="output-wrap">
          <div class="transbox">{{ result }}</div>
        </div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

    <script src="./axios.js"></script>
    <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
          words: '',
          obj: {
            words: ''
          },
          result: '',  // 翻译结果
        //   timer: null // 延时器id
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
            // 改方法会在数据变化时执行
            // newValue:变化后的新值, oldValue:变化前的旧值(一般不用)
            // words(newValue) {
            //     console.log('变化了', newValue)
            // }

            'obj.words' (newValue) {
                // console.log('变化了', newValue)

                // 防抖:延迟执行
                // 如果一段时间内触发了,清空计时器
                clearTimeout(this.timer)
                this.timer = setTimeout(async () => {
                    const res = await axios({
                        url: 'https://applet-base-api-t.itheima.net/api/translate',
                        method: 'GET',
                        params: {
                            words: newValue
                        }
                    })
                    // console.log(res)
                    this.result = res.data.data
                }, 200)
            }
        }
      })
    </script>
  </body>
</html>

效果:

②完整写法:添加额外配置项

(1)deep: true 对复杂类型深度监视

(2)immediate: true 初始化立刻执行一次handler方法

(3)handler: 要执行的方法

data: {
    obj: {
        words: '苹果',
        lang: 'italy'
    },
},

watch: {
    // watch完整写法
    数据属性名: {
        deep: true,  // 深度监视
        immediate: true,// 是否立刻执行一次handler方法
        handler(newValue) {
            console.log(newValue)
        }
    }
}

示例:

要求:输入内容,修改语言,都实时翻译

<!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;
            box-sizing: border-box;
            font-size: 18px;
        }

        #app {
            padding: 10px 20px;
        }

        .query {
            margin: 10px 0;
        }

        .box {
            display: flex;
        }

        textarea {
            width: 300px;
            height: 160px;
            font-size: 18px;
            border: 1px solid #dedede;
            outline: none;
            resize: none;
            padding: 10px;
        }

        textarea:hover {
            border: 1px solid #1589f5;
        }

        .transbox {
            width: 300px;
            height: 160px;
            background-color: #f0f0f0;
            padding: 10px;
            border: none;
        }

        .tip-box {
            width: 300px;
            height: 25px;
            line-height: 25px;
            display: flex;
        }

        .tip-box span {
            flex: 1;
            text-align: center;
        }

        .query span {
            font-size: 18px;
        }

        .input-wrap {
            position: relative;
        }

        .input-wrap span {
            position: absolute;
            right: 15px;
            bottom: 15px;
            font-size: 12px;
        }

        .input-wrap i {
            font-size: 20px;
            font-style: normal;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- 条件选择框 -->
        <div class="query">
            <span>翻译成的语言:</span>
            <select v-model="obj.lang">
                <option value="italy">意大利</option>
                <option value="english">英语</option>
                <option value="german">德语</option>
            </select>
        </div>

        <!-- 翻译框 -->
        <div class="box">
            <div class="input-wrap">
                <textarea v-model="obj.words"></textarea>
                <span><i>⌨️</i>文档翻译</span>
            </div>
            <div class="output-wrap">
                <div class="transbox">{{ result }}</div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

    <script src="./axios.js"></script>
    <script>
        // 接口地址:https://applet-base-api-t.itheima.net/api/translate
        // 请求方式:get
        // 请求参数:
        // (1)words:需要被翻译的文本(必传)
        // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
        // -----------------------------------------------

        const app = new Vue({
            el: '#app',
            data: {
                obj: {
                    words: '小黑',
                    lang: 'italy'
                },
                result: '',  // 翻译结果
            },
            // 具体讲解:(1) watch语法 (2) 具体业务实现
            watch: {
                obj: {
                    deep: true,  // 深度观察,对象任何层级数据发生变化,watch方法都会被触发
                    immediate: true,  // 立即调用:在侦听开始时立即调用一次watch方法
                    handler(newValue) {
                        // console.log('对象被修改了', newValue)
                        clearTimeout(this.timer)
                        this.timer = setTimeout(async () => {
                            const res = await axios({
                                url: 'https://applet-base-api-t.itheima.net/api/translate',
                                method: 'GET',
                                params: newValue
                            })
                            this.result = res.data.data
                        }, 200)
                    } 
                }
            }
        })
    </script>
</body>

</html>

效果:

四、综合案列 — 水果购物车

需求明确:

①渲染功能:v-if/v-else v-for :class;

②删除功能:点击传参 filter过滤覆盖原数组;

③修改数量:点击传参 find找对象;

④全选反选:计算属性computed 完整写法get/set;

⑤统计选中的总价 和 总数量:计算属性computed reduce条件求和;

⑥持久化到本地:watch监视,localStorage,JSON.stringfy,JSON.parse

<!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" />
    <link rel="stylesheet" href="./css/inputnumber.css" />
    <link rel="stylesheet" href="./css/index.css" />
    <title>购物车</title>
  </head>
  <body>
    <div class="app-container" id="app">
      <!-- 顶部banner -->
      <div class="banner-box"><img src="./img/fruit.jpg" alt="" /></div>
      <!-- 面包屑 -->
      <div class="breadcrumb">
        <span>🏠</span>
        /
        <span>购物车</span>
      </div>
      <!-- 购物车主体 -->
      <div class="main" v-if="fruitList.length > 0">
        <div class="table">
          <!-- 头部 -->
          <div class="thead">
            <div class="tr">
              <div class="th">选中</div>
              <div class="th th-pic">图片</div>
              <div class="th">单价</div>
              <div class="th num-th">个数</div>
              <div class="th">小计</div>
              <div class="th">操作</div>
            </div>
          </div>
          <!-- 身体 -->
          <div class="tbody">
            <div class="tr" v-for="(item, index) in fruitList" :key="item.id" :class="{active: item.isChecked}">
              <div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
              <div class="td"><img :src="item.icon" alt="" /></div>
              <div class="td">{{ item.price }}</div>
              <div class="td">
                <div class="my-input-number">
                  <button :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> - </button>
                  <span class="my-input__inner">{{ item.num }}</span>
                  <button class="increase" @click="add(item.id)"> + </button>
                </div>
              </div>
              <div class="td">{{ item.price * item.num}}</div>
              <div class="td" @click="del(item.id)"><button>删除</button></div>
            </div>
          </div>
        </div>
        <!-- 底部 -->
        <div class="bottom">
          <!-- 全选 -->
          <label class="check-all">
            <input type="checkbox" v-model="isAll"/>
            全选
          </label>
          <div class="right-box">
            <!-- 所有商品总价 -->
            <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;<span class="price" >{{ totalPrice }}</span></span>
            <!-- 结算按钮 -->
            <button class="pay" >结算( {{ totalCount}} )</button>
          </div>
        </div>
      </div>
      <!-- 空车 -->
      <div class="empty" v-else>🛒空空如也</div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

    <script>
      // 默认值
      const defaultArr = [
            {
              id: 1,
              icon: './img/火龙果.png',
              isChecked: true,
              num: 2,
              price: 6,
            },
            {
              id: 2,
              icon: './img/荔枝.png',
              isChecked: false,
              num: 7,
              price: 20,
            },
            {
              id: 3,
              icon: './img/榴莲.png',
              isChecked: false,
              num: 3,
              price: 40,
            },
            {
              id: 4,
              icon: './img/鸭梨.png',
              isChecked: true,
              num: 10,
              price: 3,
            },
            {
              id: 5,
              icon: './img/樱桃.png',
              isChecked: false,
              num: 20,
              price: 34,
            },
          ]
      const app = new Vue({
        el: '#app',
        data: {
          // 水果列表
          // 从本地读取
          fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr
        },
        computed: {
          // isAll() {
          //   // 必须所有的小选框都选中,全选按钮才选中 -> every
          //   return this.fruitList.every(item => item.isChecked === true)
          // }

          isAll: {
            set(value) {
              // console.log(value)
              // 基于拿到的布尔值,要让所有的小选框都同步状态
              this.fruitList.forEach(item => item.isChecked = value)
            },
            get() {
              return this.fruitList.every(item => item.isChecked === true)
            }
          },
          // 统计选中的总数
          totalCount() {
            return this.fruitList.reduce((sum, item) => {
              if(item.isChecked) {
                // 选中 -> 需要累加
                return sum + item.num
              } else {
                // 没选中 -> 不需要累加
                return sum
              }
            }, 0)
          },
          // 统计选中的总价
          totalPrice() {
            return this.fruitList.reduce((sum, item) => {
              if(item.isChecked) {
                // 选中 -> 需要累加
                return sum + item.num * item.price
              } else {
                // 没选中 -> 不需要累加
                return sum
              }
            }, 0)
          }
        },
        methods: {
          del(id) {
            this.fruitList = this.fruitList.filter(res => res.id !== id)
          },
          add(id) {
            const fruit = this.fruitList.find(item => item.id === id)
            fruit.num++
          },
          sub(id) {
            const fruit = this.fruitList.find(item => item.id === id)
            fruit.num--
          }
        },
        watch: {
          fruitList: {
            deep: true,
            handler(newValue) {
              // console.log(newValue)
              // 需要将变化后的newValue存入本地(转JSON)
              localStorage.setItem('list', JSON.stringify(newValue))
            }
          }
        }
      })
    </script>
  </body>
</html>

五、补充知识

与数据有关的数组方法
名称说明
push将一个或多个元素添加至数组末尾,并返回新数组的长度
pop从数组中删除并返回最后一个元素
shift从数组中删除并返回第一个元素
unshift将一个或多个元素添加至数组开头,并返回新数组的长度
splice从数组中删除元素或向数组添加元素
sort对数组元素排序,默认按照Unicode编码排序,返回排序后的数组
reverse将数组中的元素位置颠倒,返回颠倒后的数组
reduce计算数组中每个元素中某项的和
filter对数组元素进行过滤,仅保留符合条件的项(不会改变原数组的值)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/605875.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

01-单片机商业项目编程,从零搭建低功耗系统设计

一、引言 这是关于《单片机商业编程之从零搭建低功耗系统》的第一篇章&#xff0c;个人善忘&#xff0c;平常项目设计当中的一些思路&#xff0c;以前年轻的时候习惯性的录制成视频&#xff0c;也算是当作是自己的笔记&#xff0c;无奈现在喉咙实在扛不住&#xff0c;因此先尝试…

Linux下的I2C通信

I2C通信: 一.硬件初识: IIC(inter-intergrated-Circu):内部集成总线 四线通讯:SCL,SDA,GND,VCC,串行,半双工 I2C 总线是同步,串行,半双工通信总线。 I2C 总线由时钟线 SDA 和 SCL 两根信号线构成。并且都有上拉电阻。确保总线空闲状态为高电平。 I2C 总线支持多…

四川古力未来科技抖音小店:安全便捷购物新体验

在这个数字化快速发展的时代&#xff0c;网络购物已经成为人们生活中不可或缺的一部分。四川古力未来科技抖音小店以其高度的安全性&#xff0c;为广大消费者提供了一个值得信赖的购物平台。在这里&#xff0c;我们可以享受到安全便捷的购物体验&#xff0c;畅游科技的海洋。 一…

java回调机制

目录 一、简介二、示例2.1 同步回调2.2 异步回调2.3 二者区别 三、应用场景 一、简介 在Java中&#xff0c;回调是一种常见的编程模式&#xff0c;它允许一个对象将某个方法作为参数传递给另一个对象&#xff0c;以便在适当的时候调用该方法。 以类A调用类B方法为例: 在类A中…

CTF-reverse,逆向分析,对“左移4或右移4,即(x<<4) | (x >>4)的加密探讨

博主在刷题过程中遇上这样一个有意思的加密&#xff08;如下图&#xff09;&#xff0c;苦苦思索其逆向运算&#xff0c;被硬控了很久&#xff0c;也没搜到什么资料来解释这个问题&#xff08;也许是太简单&#xff1f;&#xff1f;蒟蒻博主怀疑人生……&#xff09; 经过博主不…

2024最新版JavaScript逆向爬虫教程-------基础篇之无限debugger的原理与绕过

目录 一、无限debugger的原理与绕过1.1 案例介绍1.2 实现原理1.3 绕过debugger方法1.3.1 禁用所有断点1.3.2 禁用局部断点1.3.3 替换文件1.3.4 函数置空与hook 二、补充2.1 改写JavaScript文件2.2 浏览器开发者工具中出现的VM开头的JS文件是什么&#xff1f; 一、无限debugger的…

正点原子Linux学习笔记(七)在 LCD 上显示 png 图片

在 LCD 上显示 png 图片 21.1 PNG 简介21.2 libpng 简介21.3 zlib 移植下载源码包编译源码安装目录下的文件夹介绍移植到开发板 21.4 libpng 移植下载源码包编译源码安装目录下的文件夹介绍移植到开发板 21.5 libpng 使用说明libpng 的数据结构创建和初始化 png_struct 对象创建…

win11个性化锁屏界面怎么关闭?

win11个性化锁屏界面关闭方法对于win11用户来说&#xff0c;关闭个性化锁屏界面是一个常见问题。本文将由php小编苹果详细介绍如何执行此操作&#xff0c;分步指导并提供操作截图。继续阅读以了解具体步骤。 win11个性化锁屏界面关闭方法 第一步&#xff0c;点击底部Windows图…

企信通_企信通短信群发平台

现代社会&#xff0c;随着互联网技术的快速发展&#xff0c;传统的营销方式已经无法满足企业对于市场开拓和客户沟通的需求。群发作为一种高效、低成本的营销手段&#xff0c;逐渐成为了众多企业的首选。而在众多群发平台中&#xff0c;嘀迈信息企信通公司凭借其稳定可靠的服务…

GM EPUB Reader Pro for Mac:专业电子书阅读工具

GM EPUB Reader Pro是一款适用于Mac的专业EPUB阅读软件。它为用户提供了优质的阅读体验和丰富的功能。 GM EPUB Reader Pro支持EPUB格式&#xff0c;这是一种广泛使用的电子书格式&#xff0c;常用于小说、教育书籍、期刊等。您可以通过该软件打开和阅读EPUB文件&#xff0c;享…

提取网页元数据的Python库之lassie使用详解

概要 Lassie是一个用于提取网页元数据的Python库,它能够智能地抓取网页的标题、描述、关键图像等内容。Lassie的设计目的是为了简化从各种类型的网页中提取关键信息的过程,适用于需要预览链接内容的应用场景。 安装 安装Lassie非常简单,可以通过Python的包管理器pip进行安…

WPS二次开发系列:一文快速了解WPS SDK功能场景

作者持续关注 WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;QQ:250325397&#xff09; 目录 SDK功能介绍 功能详解&#xff1a; 打开文档…

Windows系统完全卸载删除 Node.js (包含控制面板找不到node.js选项情况)

1.打开cmd命令行窗口&#xff0c;输入npm cache clean --force 回车执行 2.打开控制面板&#xff0c;在控制面板中把Node.js卸载 移除之后检查环境变量是否也移除&#xff1a;点击Path&#xff0c;点击编辑。 把环境变量中和node有关的全部移除&#xff0c;然后点击确定。 3.重…

WEB基础--JDBC基础

JDBC简介 JDBC概述 数据库持久化介绍 jdbc是java做数据库持久化的规范&#xff0c;持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备(断电之后&#xff0c;数据还在&#xff0c;比如硬盘&#xff0c;U盘)中以供之后使用。大多数情况下&#xff0c;特别是企业级…

Gartner发布准备应对勒索软件攻击指南:勒索软件攻击的三个阶段及其防御生命周期

攻击者改变了策略&#xff0c;在某些情况下转向勒索软件。安全和风险管理领导者必须通过提高检测和预防能力来为勒索软件攻击做好准备&#xff0c;同时还要改进其事后应对策略。 主要发现 勒索软件&#xff08;无加密的数据盗窃攻击&#xff09;是攻击者越来越多地使用的策略。…

SpringBoot启动流程分析之创建SpringApplication对象(一)

SpringBoot启动流程分析之创建SpringApplication对象(一) 目录&#xff1a; 文章目录 SpringBoot启动流程分析之创建SpringApplication对象(一)1、SpringApplication的构造方法1.1、推断应用程序类型1.2、设置Initializers1.3、设置Listener1.4、推断main方法所在类 流程分析…

Seata之XA 模式的使用

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 Seata 是一款开源的…

计算机专业,求你别再玩了,我都替你们着急

明确学习目标和方向&#xff1a;确定自己希望在计算机领域的哪个方向深入发展&#xff0c;如前端开发、后端开发、数据库管理、人工智能等。根据目标方向&#xff0c;制定详细的学习计划&#xff0c;确保所学知识与未来职业方向相匹配。 【PDF学习资料文末获取】 扎实基础知识…

变配电工程 变配电室智能监控系统 门禁 视频 环境 机器人

一、方案背景 要真正了解无人值守配电房的运行模式&#xff0c;我们必须对“无人值守”这一概念有准确的理解。它并不意味着完全没有工作人员管理&#xff0c;而是通过技术设备和人机协作来确保配电房的正常运行。 利用变配电室智能监控系统&#xff0c;可以实时获得配电室各…

【优选算法】—Leetcode—11—— 盛最多水的容器

1.题目 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#…