vue2干货总结3(computed计算属性、watch监听器)

一.计算属性

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

语法:

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

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

3.计算属性就是将一段求值的代码进行封装,所以最后要return结果

案例:计算礼物

javascript 复制代码
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Microsoft YaHei", sans-serif;
    }

    #app {
      width: 400px;
    }

    .gift-table {
      width: 100%;
      border-collapse: separate;
      border-spacing: 6px;
      border: 2px solid #555;
    }

    .gift-table th,
    .gift-table td {
      width: 50%;
      height: 40px;
      border: 2px solid #555;
      text-align: center;
      font-size: 18px;
      color: #333;
    }

    .gift-table th {
      font-weight: bold;
      font-size: 20px;
    }

    .total {
      margin-top: 20px;
      font-size: 20px;
      color: #333;
    }
</style>
<body>
  <div id="app">
    <table class="gift-table">
      <thead>
        <tr>
          <th>名字</th>
          <th>数量</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in list">
          <td>{{item.name}}</td>
          <td>{{item.num}}个</td>
        </tr>
      </tbody>
    </table>
    <p class="total">礼物总数:{{ 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:2 },
          { id:3, name:'铅笔', num:5 }
        ]
      },
      computed:{
        totalCount(){
          console.log(this.list);
          let total = this.list.reduce((sum,item)=>sum+item.num,0)
          return total
        }
      }
    })
  </script>
</body>

缓存特性(提升性能):

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

算并再次缓存

computed计算属性:

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

语法:

1.写在computed 配置项中

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

methods方法:

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

语法:

1.写在methods配置项中

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

计算属性默认的简写,只能读取访问,不能"修改";如果要"修改"需要写计算属性的完整写法

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

案例:修改改名卡

javascript 复制代码
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Microsoft YaHei", sans-serif;
    }

    #app {
      width: 420px;
      margin: 50px auto;
    }

    .row {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 22px;
      color: #333;
    }

    .row input {
      width: 60px;
      height: 38px;
      border: 1px solid #aaa;
      border-radius: 4px;
      background-color: #f5f5f5;
      font-size: 20px;
      text-align: center;
      outline: none;
    }

    .row input:focus {
      border-color: #666;
      background-color: #fff;
    }

    .row .op {
      margin: 0 4px;
    }

    .rename-btn {
      margin-top: 30px;
      width: 110px;
      height: 44px;
      border: 1px solid #999;
      border-radius: 4px;
      background-color: #eee;
      font-size: 18px;
      cursor: pointer;
    }

    .rename-btn:hover {
      background-color: #e0e0e0;
    }
</style>
<body>
  <div id="app">
    <div class="row">
      <span>姓:</span>
      <input type="text" v-model="firstName">
      <span class="op">+</span>
      <span>名:</span>
      <input type="text" v-model="lastName">
      <span class="op">=</span>
      <span>{{ fullName }}</span>
    </div>
    <button class="rename-btn" @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:'三'
      },
      methods:{
        changeName(){
          this.fullName = '李四'
        }
      },
      computed:{
        fullName:{
          get(){
            return this.firstName + this.lastName
          },
          set(value){
            this.firstName = value.slice(0,1)
            this.lastName = value.slice(1)
          }
        }
      }
    })
  </script>
</body>

案例:成绩单

javascript 复制代码
<style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Microsoft YaHei", sans-serif;
    }

    #app {
      display: flex;
      gap: 60px;
      align-items: flex-start;
      padding: 40px;
    }

    .score-table {
      width: 540px;
      border-collapse: collapse;
      font-size: 15px;
      color: #333;
    }

    .score-table th,
    .score-table td {
      height: 42px;
      border: 1px solid #ddd;
      text-align: center;
    }

    .score-table th {
      background-color: #f7f7f7;
      font-weight: bold;
    }

      .score-table .empty {
      height: 120px;
      color: #999;
    }

    .score-table .red {
      color: #e1251b;
      font-weight: bold;
    }

    .score-table .del {
      color: #6a5acd;
      text-decoration: underline;
      cursor: pointer;
    }

    .score-table tfoot td {
      padding-left: 40px;
      text-align: left;
    }

    .score-table tfoot td span {
      display: inline-block;
      width: 130px;
    }

    .form-item {
      display: flex;
      align-items: center;
      margin-bottom: 16px;
      font-size: 14px;
      color: #333;
    }

    .form-item label {
      width: 44px;
      text-align: right;
      margin-right: 8px;
    }

    .form-item input {
      width: 190px;
      height: 32px;
      padding: 0 8px;
      border: 1px solid #ddd;
      outline: none;
      font-size: 14px;
    }

    .form-item input:focus {
      border-color: #1f6f96;
    }

    .add-btn {
      margin-left: 52px;
      padding: 6px 16px;
      border: none;
      border-radius: 3px;
      background-color: #1f6f96;
      color: #fff;
      font-size: 14px;
      cursor: pointer;
    }

    .add-btn:hover {
      background-color: #2a86b4;
    }
</style>
<body>
  <div id="app">
    <table class="score-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>{{ index + 1 }}</td>
          <td>{{ item.subject }}</td>
          <td :class="{ red: item.score < 60 }">{{ item.score }}</td>
          <td><a href="#" class="del" @click="del(item.id)">删除</a></td>
        </tr>
      </tbody>
      <tbody v-else>
        <tr>
          <td colspan="4" class="empty">暂无成绩记录</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="4">
            <span>总分:{{ totalScore }}</span>
            <span>平均分:{{ avgScore }}</span>
          </td>
        </tr>
      </tfoot>
    </table>
    <div class="form">
      <div class="form-item">
        <label>科目:</label>
        <input type="text" placeholder="请输入科目" v-model.trim="subject">
      </div>
      <div class="form-item">
        <label>分数:</label>
        <input type="text" placeholder="请输入分数" v-model.number="score">
      </div>
      <button class="add-btn" @click="add">添加</button>
    </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: 80 },
          { id: 2, subject: '数学', score: 90 },
          { id: 3, subject: '英语', score: 55 }
        ],
        subject: '',
        score: ''
      },
      methods:{
        del(id){
          this.list = this.list.filter(item => item.id !== id);
        },
        add(){
          if(!this.subject || !this.score)return
          this.list.push({
            id: this.list.length + 1,
            subject: this.subject,
            score: this.score
          });
          this.subject = '';
          this.score = '';
        }
      },
      computed:{
        totalScore(){
          return this.list.reduce((sum, item) => sum + item.score, 0);
        },
        avgScore(){
          return this.list.length > 0 ? (this.totalScore / this.list.length).toFixed(2) : 0;
        }
      }
    })
  </script>
</body>

二.watch监听器

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

语法:

1.简单写法 简单类型数据,直接监视

2.完整写法 添加额外配置项

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

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

javascript 复制代码
<body>
  <div id="app">
    <textarea name="" id="" cols="30" rows="10" v-model="msg"></textarea>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app', 
      data: {
        msg: ''
      },
      watch:{
        msg(newValue,oldValue){
          console.log('msg变化了',newValue,oldValue);
        }
      }
    })
  </script>
</body>
javascript 复制代码
<body>
  <div id="app">
    <textarea name="" id="" cols="30" rows="10" v-model="msg"></textarea>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app', 
      data: {
        msg: ''
      },
      watch:{
        msg(newValue){
          console.log('msg变化了',newValue);
        }
      }
    })
  </script>
</body>
javascript 复制代码
<body>
  <div id="app">
    <textarea name="" id="" cols="30" rows="10" v-model="obj.msg"></textarea>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app', 
      data: {
        obj:{
          msg: ''
        }
      },
      watch:{
        // 监视对象子属性变化
        'obj.msg'(newValue){
          console.log('msg变化了',newValue);
        }
      }
    })
  </script>
</body>

案例:水果购物车(重点)

javascript 复制代码
<style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: "Microsoft YaHei", sans-serif;
      background-color: #f5f5f5;
      padding: 30px 0;
    }
    #app {
      width: 720px;
      margin: 0 auto;
      background-color: #fff;
    }
    .cart-header,
    .cart-row {
      display: flex;
      align-items: center;
      padding: 16px 12px;
      border-bottom: 1px solid #eee;
    }
    .cart-header {
      background-color: #fafafa;
      font-size: 14px;
      color: #666;
      font-weight: bold;
    }
    .col-check { width: 40px; text-align: center; }
    .col-img   { width: 80px; text-align: center; }
    .col-price { width: 100px; text-align: center; }
    .col-count { width: 140px; text-align: center; }
    .col-total { width: 100px; text-align: center; }
    .col-ops   { width: 80px; text-align: center; }
    .col-img img {
      width: 60px;
      height: 60px;
      border-radius: 4px;
      object-fit: cover;
    }
    .count-box {
      display: inline-flex;
      align-items: center;
      border: 1px solid #ddd;
      border-radius: 3px;
    }
    .count-box .btn {
      width: 28px;
      height: 28px;
      border: none;
      background-color: #f5f5f5;
      color: #555;
      font-size: 16px;
      cursor: pointer;
    }
    .count-box .btn:hover {
      background-color: #e8e8e8;
    }
    .count-box .num {
      width: 36px;
      height: 28px;
      line-height: 28px;
      text-align: center;
      font-size: 14px;
      color: #333;
    }
    .del-btn {
      border: none;
      background-color: #e1251b;
      color: #fff;
      font-size: 13px;
      padding: 5px 12px;
      border-radius: 3px;
      cursor: pointer;
    }
    .del-btn:hover {
      background-color: #c0392b;
    }
    .cart-footer {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      padding: 16px 12px;
      gap: 16px;
    }
    .cart-footer .select-all {
      margin-right: auto;
      font-size: 14px;
      color: #333;
      display: flex;
      align-items: center;
      gap: 6px;
    }
    .cart-footer .total-price {
      font-size: 16px;
      color: #333;
    }
    .cart-footer .total-price b {
      color: #e1251b;
      font-size: 22px;
      margin-left: 4px;
    }
    .cart-footer .checkout-btn {
      width: 120px;
      padding: 10px 28px;
      border: none;
      border-radius: 4px;
      background-color: #4a9eff;
      color: #fff;
      font-size: 15px;
      cursor: pointer;
    }
    .cart-footer .checkout-btn:hover {
      background-color: #3a8eed;
    }
    .empty {
      width: 100%;
      height: 100px;
      line-height: 120px;
      text-align: center;
      color: #999;
      font-size: 18px;
    }
    .active{
      background-color: #f5f7fb;
    }
</style>
<body>
  <div id="app">
    <!-- 表头 -->
    <div class="cart-header">
      <div class="col-check">选中</div>
      <div class="col-img">图片</div>
      <div class="col-price">单价</div>
      <div class="col-count">个数</div>
      <div class="col-total">小计</div>
      <div class="col-ops">操作</div>
    </div>
    <!-- 商品行 -->
    <div v-if="fruitList.length > 0">
      <div class="cart-row" :class="{ active:item.isChecked }" v-for="item in fruitList" :key="item.id">
        <div class="col-check">
          <input type="checkbox" v-model="item.isChecked">
        </div>
        <div class="col-img">
          <img :src="item.icon" alt="">
        </div>
        <div class="col-price">{{item.price}}</div>
        <div class="col-count">
          <div class="count-box">
            <button class="btn" @click="sub(item.id)" :disabled="item.count <= 1">-</button>
            <span class="num">{{item.count}}</span>
            <button class="btn" @click="add(item.id)">+</button>
          </div>
        </div>
        <div class="col-total">{{item.price * item.count}}</div>
        <div class="col-ops"><button class="del-btn" @click="del(item.id)">删除</button></div>
      </div>
    </div>
    <div class="empty" v-else>暂无商品</div>
    <!-- 底部结算栏 -->
    <div class="cart-footer">
      <label class="select-all">
        <input type="checkbox" v-model="isAllChecked"> 全选
      </label>
      <span class="total-price">总价:<b>¥{{ totalPrice }}</b></span>
      <button class="checkout-btn">结算({{ totalCount }})</button>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
  <script>
    const fruitArr = [
      { id:1,icon:'./images/apple.png',isChecked:true,price:6,count:2},
      { id:2,icon:'./images/banana.png',isChecked:false,price:7,count:1},
      { id:3,icon:'./images/watermelon.png',isChecked:false,price:3,count:3}
    ]
    const app = new Vue({
      el: '#app', 
      data: {
        fruitList: JSON.parse(localStorage.getItem('fruitList')) || fruitArr
      },
      computed:{
        isAllChecked:{
          get(){
            return this.fruitList.every(item => item.isChecked)
          },
          set(value){
            this.fruitList.forEach(item => item.isChecked = value)
          }
        },
        totalPrice(){
          return this.fruitList.reduce((sum,item) => {
            if(item.isChecked){
              return sum + item.price * item.count
            }else{
              return sum
            }
          },0)
        },
        totalCount(){
          return this.fruitList.reduce((sum,item) => {
            if(item.isChecked){
              return sum + item.count
            }else{
              return sum
            }
          },0)
        }
      },
      methods:{
        del(id){
          this.fruitList = this.fruitList.filter(item => item.id !== id)
        },
        sub(id){
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.count--
        },
        add(id){
          const fruit = this.fruitList.find(item => item.id === id)
          fruit.count++
        }
      },
      watch:{
        fruitList:{
          deep:true,
          handler(newValue){
            localStorage.setItem('fruitList',JSON.stringify(newValue))
          }
        }
      }
    })
  </script>
</body>
相关推荐
Java小卷1 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
Fatbobman(东坡肘子)1 小时前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift
揽星河..2 小时前
【C语言】底层程序设计
c语言·开发语言
JavaPub-rodert2 小时前
从零搭建通用管理后台:ShiyuAdmin 的 Go、React 与 RBAC 实践
开发语言·react.js·golang
kyriewen3 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
海的透彻3 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
IT_陈寒3 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
code2cat3 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
北京中科新远科技3 小时前
高速交换机端口预算怎么做?下行、上联、拆分和冗余计算框架
开发语言·php