Vue day02

一、指令补充

1.  指令修饰符(简化代码)

通过 "."  指明一些指令后缀,不同后缀封装了不同的处理操作

a.   按键修饰符

      @keyup.enter         键盘监听回车         @keyup.enter="addList"

b.   v-model 修饰符

      v-model.trim           去除首尾空格      

      v-model.number     转数字                     不会强制转换(不会把字符转成undefined)

c.  事件修饰符

     @事件名.stop           阻止冒泡 

     @事件名.prevent      阻止默认行为

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

针对 class 类名,style 行内样式 进行控制

操作 class

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

对象   

// 值为 true,有这个类,为 false,无这个类       适用于一个类名来回切换
<div class="box" :class="{类名1: true, 类名2: false}"></div>

 数组 

// 所有的类都会被添加上                         适用于批量添加或删除类
<div class="box" :class="[类名1, 类名2]"></div>

京东秒杀 tab 导航高亮

  <!-- 切换高亮,就是改下标 -->
  <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: 0,  // 记录高亮
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]
      }
    })
  </script>

 

操作 style

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

语法::style = "对象"

<div class="box" :style="{width: '200px', heigth: '200px'}"></div>

 进度条

  <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/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        percent: 30
      }
    })
  </script>

 


 

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

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

它会根据控件类型自动选取正确的方法来更新元素

输入框       input:text              value

文本域       textarea                value

复选框       input:checkbox     checked

单选框       input:radio            checked      给两个单选框加上同一个name属性,会互斥

下拉菜单    select                    value

 

二、computed 计算属性

作用:依赖的数据变化,自动重新计算

1.  基础语法(只能读取访问,不能修改)
      computed: {
        属性名() {
          // 计算逻辑
          return 结果
        }
      }

使用:{{属性名}}   和普通属性一样使用

    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数:{{total}} 个</p>
  </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: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      // 将一段可以求值的代码进行封装
      computed: {
        total() {
          return this.list.reduce((sum, item) => sum += item.num, 0)
        }
      }
    })
  </script>

2.  计算属性 vs 方法
computed 计算属性

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

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

计算属性缓存特性(提升性能):

        计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算,并再次缓存

methods 方法

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

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

 

3.  完整写法(能修改)
      computed: {
        属性名: {
          get() {
            // 计算逻辑
            return 结果
          }
          set(修改的值) {
            // 修改逻辑
          }
        }
      }

 改名

  <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/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        firstName: '孙',
        lastName: '悟空'
      },
      computed: {
        fullName: {
          get() {
            return this.firstName + this.lastName
          },
          set(value) {
            // console.log(value)    // 曹雪芹
            this.firstName = value.slice(0, 1)
            this.lastName = value.slice(1)
          }
        }
      },
      methods: {
        changeName() {
          this.fullName = '曹雪芹'
        }
      }
    })
  </script>

 

 

4.  成绩案例


 

三、wantch 侦听器

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

1.  基础语法
      data: {
        words: '苹果',
        // obj: {
        //   words: '苹果'
        // }
      }
      watch: {
        words(newValue, oldValue) {
          // 业务逻辑
        },
        // 'obj.words'(newValue, oldValue) {
        //   // 业务逻辑
        // }
      }

翻译框 

    <!-- 翻译框 -->
    <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/dist/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.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: '',
        },
        result: ''   // 翻译结果
      },
      watch: {
        'obj.words'(newValue) {
          // 防抖
          clearTimeout(this.timer)
          this.timer = setTimeout(async () => {
            const res = await axios({
              url: 'https://applet-base-api-t.itheima.net/api/translate',
              params: {
                words: newValue
              }
            })
            // console.log(res.data.data)
            this.result = res.data.data
          }, 300)
        }
      }
    })
  </script>

 

 

2.  完整写法

添加额外配置项

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

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

    <!-- 翻译框 -->
    <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/dist/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        obj: {
          words: '',
          lang: 'italy'
        },
        result: ''
      },
      watch: {
        obj: {
          deep: true,
          handler(newValue) {
            clearTimeout(this.timer)
            this.timer = setTimeout(async () => {
              const res = await axios({
                url: 'https://applet-base-api-t.itheima.net/api/translate',
                params: newValue
              })
              this.result = res.data.data
            }, 300)
          }
        }
      }
    })

 

四、综合案例:水果购物车

  • 渲染
  • 删除
  • 修改个数
  • 全选反选
  • 统计选中的总价和总数量
  • 持久化到本地
<!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='../images/01.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" :class="{active: item.isChecked}" v-for="(item,index) in fruitList" :key="item.id">
            <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 class="decrease" :disabled="item.num <= 1" @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.num * item.price}}</div>
            <div class="td"><button @click="del(item.id)">删除</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">总价<span class="price">¥{{toPrice}}</span></span>
          <!-- 结算按钮 -->
          <button class="pay">结算({{toCount}} )</button>
        </div>
      </div>
    </div>
    <!-- 空车 -->
    <div class="empty">🛒空空如也</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const defaultArr = [
      {
        id: 1,
        icon: '../images/01.jpg',
        isChecked: true,
        num: 2,
        price: 6,
      },
      {
        id: 2,
        icon: '../images/02.jpg',
        isChecked: false,
        num: 7,
        price: 20,
      },
      {
        id: 3,
        icon: '../images/03.jpg',
        isChecked: false,
        num: 3,
        price: 40,
      },
      {
        id: 4,
        icon: '../images/04.jpg',
        isChecked: true,
        num: 10,
        price: 3,
      },
      {
        id: 5,
        icon: '../images/05.jpg',
        isChecked: false,
        num: 20,
        price: 34,
      }
    ]
    const app = new Vue({
      el: '#app',
      data: {
        // 水果列表
        fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr
      },
      computed: {
        isAll: {
          get() {
            // 所有小按钮都选中,全选按钮才选中
            return this.fruitList.every(item => item.isChecked)
          },
          set(value) {
            // console.log(value)  全选按钮的状态
            this.fruitList.forEach(item => item.isChecked = value)
          }
        },
        // 选中的总数
        toCount() {
          return this.fruitList.reduce((sum, item) => {
            if (item.isChecked) {
              // 选中了,需要累加
              return sum + item.num
            } else {
              // 不需要累加
              return sum
            }
          }, 0)
        },
        // 选中的总价
        toPrice() {
          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(item => item.id !== id)
        },
        sub(id) {
          console.log(id)
          // 根据 id 找到数组中的对应项 find
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.num--
        },
        add(id) {
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.num++
        }
      },
      watch: {
        fruitList: {
          deep: true,
          handler(newValue) {
            localStorage.setItem('list', JSON.stringify(newValue))
          }
        }
      }
    })
  </script>
</body>

</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值