Vue2 day02

1.指令的修饰符

其他的也和这个差不多,这里v-model.number文本框里如果输入的是字母显示的也是字母。

2. v-bind操作class

这里注意一下如果是改颜色什么的,不然颜色就要加引号,比如,不然就改成小驼峰命名

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

4.计算属性

5.computed计算属性vs方法methods

 总的来说,methods方法也能执行computed计算属性,但是性能没有那么高,举个例子:

下面是用了computed计算属性的例子:

而用了methods方法

6.计算属性的完整写法

7.成绩案例


<!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>{{ index + 1 }}</td>
              <td>{{ item.subject }}</td>
              <!-- 需求:不及格的标红, < 60 分, 加上 red 类 -->
              <td :class="{ red: item.score < 60 }">{{ item.score }}</td>
              <td><a @click.prevent="del(item.id)" href="http://www.baidu.com">删除</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">平均分:{{ averageScore }}</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 @click="add" class="submit" >添加</button>
          </div>
        </div>
      </div>
    </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, subject: '语文', score: 62 },
            { id: 7, subject: '数学', score: 89 },
            { id: 12, subject: '英语', score: 70 },
          ],
          subject: '',
          score: ''
        },
        computed: {
          totalScore() {
            return this.list.reduce((sum, item) => sum + item.score, 0)
          },
          averageScore () {
            if (this.list.length === 0) {
              return 0
            }
            return (this.totalScore / this.list.length).toFixed(2)
          }
        },
        methods: {
          del (id) {
            // console.log(id)
            this.list = this.list.filter(item => item.id !== id)
          },
          add () {
            if (!this.subject) {
              alert('请输入科目')
              return
            }
            if (typeof this.score !== 'number') {
              alert('请输入正确的成绩')
              return
            }
            this.list.unshift({
              id: +new Date(),
              subject: this.subject,
              score: this.score
            })

            this.subject = ''
            this.score = ''
          }
        }
      })
    </script>
  </body>
</html>

8.watch-简写-语法


<!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="obj.words"></textarea>
          <span><i>⌨️</i>文档翻译</span>
        </div>
        <div class="output-wrap">
          <div class="transbox">mela</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: {
          // words: ''
          obj: {
            words: ''
          }
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          // 该方法会在数据变化时调用执行
          // newValue新值, oldValue老值(一般不用)
          // words (newValue) {
          //   console.log('变化了', newValue)
          // }

          'obj.words' (newValue) {
            console.log('变化了', newValue)
          }
        }
      })
    </script>
  </body>
</html>

9.watch-简写-业务实现

<!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="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: {
                // 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',
                            params: {
                                words: newValue
                            }
                        })
                        this.result = res.data.data
                        console.log(res.data.data)
                    }, 300)
                }
            }
        })
    </script>
</body>

</html>

10.watch-完整写法

11.水果购物车-基本渲染

先补充一些用法:


<!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="http://autumnfish.cn/static/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 v-for="(item, index) in fruitList" :key="item.id" class="tr" :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.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">总价&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/dist/vue.js"></script>
    <script>
      const defaultArr = [
            {
              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,
            },
          ]
      const app = new Vue({
        el: '#app',
        data: {
          // 水果列表
          fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
        },
        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)
            }
          },
          // 统计选中的总数 reduce
          totalCount () {
            return this.fruitList.reduce((sum, item) => {
              if (item.isChecked) {
                // 选中 → 需要累加
                return sum + item.num
              } else {
                // 没选中 → 不需要累加
                return sum
              }
            }, 0)
          },
          // 总计选中的总价 num * price
          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(item => item.id !== id)
          },
          add (id) {
            // 1. 根据 id 找到数组中的对应项 → find
            const fruit = this.fruitList.find(item => item.id === id)
            // 2. 操作 num 数量
            fruit.num++
          },
          sub (id) {
            // 1. 根据 id 找到数组中的对应项 → find
            const fruit = this.fruitList.find(item => item.id === id)
            // 2. 操作 num 数量
            fruit.num--
          }
        },
        watch: {
          fruitList: {
            deep: true,
            handler (newValue) {
              // 需要将变化后的 newValue 存入本地 (转JSON)
              localStorage.setItem('list', JSON.stringify(newValue))
            }
          }
        }
      })
    </script>
  </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值