Vue阶段练习:tab栏、进度条、购物车

阶段练习旨在学习完Vue 指令、计算属性、侦听器-CSDN博客后,进行自我检测,每个练习分为效果显示、需求分析、静态代码、完整代码、总结 四个部分,效果显示和准备代码已给出,我们需要完成“完整代码”部分。

目录

练习1:tab栏的动态高亮显示

效果显示

静态代码

完整代码

错误代码

总结

练习2:进度条

效果显示

静态代码

完整代码

总结

注意

练习3:购物车

效果显示

静态代码

完整代码

分析

部分错误代码


练习1:tab栏的动态高亮显示

效果显示

静态代码

<!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>022(1)练习:tab栏的active效果</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><a class="active" href="#">京东秒杀</a></li>
      <li><a href="#">每日特价</a></li>
      <li><a href="#">品类秒杀</a></li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]

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

完整代码

<!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>022(1)练习:tab栏的动态高亮显示</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/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex: 2,
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]

      }
    })
  </script>
</body>

</html>

错误代码

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

总结

  1. 列表渲染
  2. 点击事件
  3. v-bind对样式进行控制

练习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>022(2)练习:进度条</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">
        <span>50%</span>
      </div>
    </div>
    <button>设置25%</button>
    <button>设置50%</button>
    <button>设置75%</button>
    <button>设置100%</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

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

完整代码

<!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>022(2)练习:进度条</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 v-for="(item, index) in list" :key="index" @click="percent = item">设置{{item}}%</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        percent: 25,
        list: [25, 50, 75, 100]
      }
    })
  </script>
</body>

</html>

总结

  1. 列表渲染
  2. 点击事件
  3. v-bind对样式进行控制:操作style

注意

:style="{width: percent+ '%' }"

如果没有将百分比值与单位分开并添加单引号,例如:style="{width: percent + %}",那么Vue.js将会尝试将百分比值与JavaScript表达式中的%一起解析为字符串,而这不是一个有效的CSS值,会导致样式设置失败。

练习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" />
  <link rel="stylesheet" href="./css/inputnumber.css" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>028练习:购物车</title>
</head>

<body>
  <div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">
      <span>🏠</span>
      /
      <span>购物车</span>
    </div>
    <!-- 购物车主体 -->
    <div class="main">
      <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 active">
            <div class="td"><input type="checkbox" checked /></div>
            <div class="td"><img src="http://autumnfish.cn/static/火龙果.png" alt="" /></div>
            <div class="td">6</div>
            <div class="td">
              <div class="my-input-number">
                <button class="decrease"> - </button>
                <span class="my-input__inner">2</span>
                <button class="increase"> + </button>
              </div>
            </div>
            <div class="td">12</div>
            <div class="td"><button>删除</button></div>
          </div>

          <div class="tr">
            <div class="td"><input type="checkbox" /></div>
            <div class="td"><img src="http://autumnfish.cn/static/荔枝.png" alt="" /></div>
            <div class="td">7</div>
            <div class="td">
              <div class="my-input-number">
                <button disabled class="decrease"> - </button>
                <span class="my-input__inner">1</span>
                <button class="increase"> + </button>
              </div>
            </div>
            <div class="td">14</div>
            <div class="td"><button>删除</button></div>
          </div>
        </div>
      </div>
      <!-- 底部 -->
      <div class="bottom">
        <!-- 全选 -->
        <label class="check-all">
          <input type="checkbox" />
          全选
        </label>
        <div class="right-box">
          <!-- 所有商品总价 -->
          <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;<span class="price">24</span></span>
          <!-- 结算按钮 -->
          <button class="pay">结算( 6 )</button>
        </div>
      </div>
    </div>
    <!-- 空车 -->
    <div class="empty">🛒空空如也</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 水果列表
        fruitList: [
          {
            id: 1,
            icon: 'http://autumnfish.cn/static/火龙果.png',
            isChecked: true,
            num: 2,
            price: 6,
          },
          {
            id: 2,
            icon: 'http://autumnfish.cn/static/荔枝.png',
            isChecked: false,
            num: 7,
            price: 20,
          },
          {
            id: 3,
            icon: 'http://autumnfish.cn/static/榴莲.png',
            isChecked: false,
            num: 3,
            price: 40,
          },
          {
            id: 4,
            icon: 'http://autumnfish.cn/static/鸭梨.png',
            isChecked: true,
            num: 10,
            price: 3,
          },
          {
            id: 5,
            icon: 'http://autumnfish.cn/static/樱桃.png',
            isChecked: false,
            num: 20,
            price: 34,
          },
        ],
      },
    })
  </script>
</body>

</html>

完整代码

<!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="028inputnumber.css" />
  <link rel="stylesheet" href="028index.css" />
  <title>028练习:购物车</title>
</head>

<body>
  <div class="app-container" id="app">
    <!-- 顶部banner -->
    <div class="banner-box"><img src="#" alt="" /></div>
    <!-- 面包屑 -->
    <div class="breadcrumb">
      <span>🏠</span>
      /
      <span>购物车</span>
    </div>
    <!-- 购物车主体 -->
    <div class="main">
      <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" :class="{active: item.isChecked==true }" v-for="(item, index) in fruitList" :key="item.id">
            <div class="td"><input type="checkbox" @click="check(index)" v-model="item.isChecked" /></div>
            <div class="td"><img src="#" alt="" /></div>
            <div class="td">{{item.price}}</div>
            <div class="td">
              <div class="my-input-number">
                <button class="decrease" @click="item.num--"> - </button>
                <span class="my-input__inner">{{item.num}}</span>
                <button class="increase" @click="item.num++"> + </button>
              </div>
            </div>
            <div class="td">{{subTotalCount(index)}}</div>
            <div class="td"><button @click="del(item.id)">删除</button></div>
          </div>


        </div>
      </div>
      <!-- 底部 -->
      <div class="bottom">
        <!-- 全选 -->
        <label class="check-all">
          <input type="checkbox" @click="toggleAllCheckbox" v-model="allClickFlag" />
          全选
        </label>
        <div class="right-box">
          <!-- 所有商品总价 -->
          <span class="price-box">总价&nbsp;&nbsp;:&nbsp;&nbsp;¥&nbsp;<span class="price">{{totalCount}}</span></span>
          <!-- 结算按钮 -->
          <button class="pay">结算( {{totalKind}} )</button>
        </div>
      </div>
    </div>
    <!-- 空车 -->
    <div class="empty" v-show="num1===0">🛒空空如也</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        num1: 0,
        allClickFlag: false,
        // 水果列表
        fruitList: [
          {
            id: 1,
            icon: '#',
            isChecked: false,
            num: 2,
            price: 6,
          },
          {
            id: 2,
            icon: '#',
            isChecked: false,
            num: 7,
            price: 20,
          },
          {
            id: 3,
            icon: '#',
            isChecked: false,
            num: 3,
            price: 40,
          },
          {
            id: 4,
            icon: '#',
            isChecked: false,
            num: 10,
            price: 3,
          },
          {
            id: 5,
            icon: '#',
            isChecked: false,
            num: 20,
            price: 34,
          },
        ],
      },
      methods: {
        subTotalCount(index) {
          return this.fruitList[index].num * this.fruitList[index].price
        },
        del(id) {
          this.fruitList = this.fruitList.filter(item => item.id != id)
        },
        check(index) {
          this.fruitList[index].isChecked = !this.fruitList[index].isChecked;
          if (this.fruitList[index].isChecked == true) this.num1++;
          else this.num1--;
          if (this.fruitList.every(item => {
            return item.isChecked === !this.allClickFlag;
          })) {
            this.allClickFlag = !this.allClickFlag;
          } else {
            const foundItem = this.fruitList.find(item => {

              return this.allClickFlag === true;
            });

            if (foundItem) {
              this.allClickFlag = !this.allClickFlag;
            }
          }

        },
        allClick() {
          const isChecked = this.allClickFlag;
          this.fruitList.forEach(item => {
            item.isChecked = isChecked;
          });
        },
        toggleAllCheckbox() {
          this.allClickFlag = !this.allClickFlag
        }
      },
      computed: {
        totalCount() {
          let total = this.fruitList.reduce((sum, item) => {
            if (item.isChecked === true) {
              return sum + item.num * item.price;
            } else {
              return sum;
            }
          }, 0);
          return total;
        },
        totalKind() {
          let kind = this.fruitList.reduce((sum, item) => {
            if (item.isChecked === true) {
              return sum + item.num;
            } else {
              return sum;
            }
          }, 0);
          return kind;
        }
      },
      watch: {
        'allClickFlag': {
          immediate: true,
          handler(newVal) {
            if (newVal === true) {
              this.fruitList.forEach(item => {
                item.isChecked = true;
                this.num1++;
              });
            } else {
              this.fruitList.forEach(item => {
                item.isChecked = false;
                this.num1--;
              });
            }
          }
        }
      },
      'num1': {
        immediate: true,
        handler(newVal) {
          if (newVal === this.fruitList.length) this.allClickFlag = true;
          else this.allClickFlag = false;
        }
      }

    })
  </script>
</body>

</html>

分析

部分错误代码

错误原因:toggleAllCheckbox 方法会切换 allClickFlag 的值,从而控制全选按钮的选中状态。但是,当用户手动取消某个待选框的选中状态时,并没有调用 toggleAllCheckbox 方法来更新 allClickFlag 的值。因此,全选按钮的状态不会根据待选框的实际状态自动更新。

改进:

<label class="check-all">

            <input type="checkbox" v-model="isAll"/>

            全选

</label>

computed: {

          // 默认计算属性:只能获取不能设置,要设置需要写完整写法

          // isAll () {

          //   // 必须所有的小选框都选中,全选按钮才选中 → every

          //   return this.fruitList.every(item => item.isChecked)

          // }

         

          // 完整写法 = get + set

          isAll: {

            get () {

              return this.fruitList.every(item => item.isChecked)

            },

            set (value) {

              // 基于拿到的布尔值,要让所有的小选框 同步状态

              this.fruitList.forEach(item => item.isChecked = value)

            }

          },

        },

  • 35
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值