1.指令补充

  • 指令修饰符

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

    • 按键修饰符

      @keyup.enter:键盘回车监听

    • V-model 修饰符

      v-model.trim:去除首尾空格

      v-model.number:转数字

    • 事件修饰符

      @事件名.stop:组织冒泡

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

  • V-bind 对于样式操作的增强

    为了方便开发者进行样式控制,扩展了 v-bind 的语法,可以针对 class 类名和 style 行内样式进行控制

    • 对象:建就是类名,值是波尔只,如果值为 true 那么会存在这个类名反则无该类名

    image-20231017210113282

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

    image-20231017210137535

    image-20231017210248556

    <body>
      <div id="app">
        <ul>
          <li v-for="(item,index) in list">
            <a :class="{active:index === activeIndex}" href="#" @click="activeIndex = index"></a>
          </li>
        </ul>
      </div>
      <script src="./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>
    
  • V-bind 对于样式控制的增强

    • :style = "样式对象"

    image-20231017210445109

    • 案例

    image-20231017210458784

    <body>
      <div id="app">
        <div class="progress">
          <div class="inner" :style="{ width: percent + '%'}">
            <span>%</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="./vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            percent: 0
          }
        })
      </script>
    </body>
    
  • V-model 应用于其他表单元素

    常见的表单元素都可以用 v-model 绑定关联 -> 快速获取或设置表单元素的值。会根据控件类型自动选取正确的方法来更新元素

    image-20231017210838338

    <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 type="radio" name="gender" v-model="gender" value="1"><input type="radio" name="gender" v-model="gender" value="2"><br><br>
        <!--
          前置理解:
            1. option 需要设置 value 值,提交给后台
            2. select 的 value 值,关联了选中的 option 的 value 值
          结合 Vue 使用 → v-model
        -->
        所在城市:
          <select v-model="city">
            <option value="001">北京</option>
            <option value="002">上海</option>
            <option value="003">成都</option>
            <option value="004">南京</option>
          </select>
          <br><br>
        自我描述:
          <textarea v-model="describe"></textarea>
    
        <button>立即注册</button>
      </div>
      <script src="./vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            username: "",
            isSingle: true,
            gender: "1",
            city: "003",
            describe: "it入门到入土"
          }
        })
      </script>
    </body>
    

2.computed 计算属性

  • 基础语法

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

    • 声明在 computed 配置项中,一个计算属性对应一个函数
    • 使用方法和普通属性一样:

    image-20231017211043460

    <body>
      <div id="app">
        <h3>小黑的礼物清单🛒<span>?</span></h3>
        <table>
          <tr>
            <th>名字</th>
            <th>数量</th>
          </tr>
          <tr v-for="(item, index) in list" :key="item.id">
            <td></td>
            <td></td>
          </tr>
        </table>
    
        <p>礼物总数: 个</p>
      </div>
      <script src="./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 },
            ]
          },
          computed: {
            totalCount () {
              let total = this.list.reduce((sum, item) => sum + item.num, 0)
              return total
            }
          }
        })
      </script>
    </body>
    
  • 计算属性 对比 方法

    • computed 计算事项
      • 封装了一段对于数据的处理,求得一个结果
      • 卸载 coumputed 配置项中
      • 作为属性,直接使用 -> this.计算属性 ||
    • methods 方法
      • 给实例提供一个方法,调用以处理业务逻辑
      • 卸载 methods 配置项中
      • 作为方法,需要调用 -> ...

    computed 存在一个缓存特性(提升性能):计算属性会对计算出来的结果进行一个缓存,再次使用直接读取缓存,依赖项变化了,则会重新计算并再次缓存

  • 完整写法

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

    image-20231017211430927

    image-20231017211501115

    <body>
      <div id="app">
        姓:<input type="text" v-model="firstName"><br>
        名:<input type="text" v-model="lastName"><br>
        <p>姓名:</p>
        <button @click="updateName">修改姓名</button>
      </div>
      <script src="./vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            firstName: "",
            lastName: ""
          },
          computed: {
            pullName: {
              get(){
                return this.firstName + this.lastName
              },
              set(value){
                this.firstName = value.slice(0,1);
                this.lastName = value.slice(1)
              }
            }
          },
          methods: {
            updateName() {
              this.pullName = "马浩楠"
            }
          }
        })
      </script>
    </body>
    
  • 案例

    image-20231017211546254

    <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="this.list.length > 0">
                <tr v-for="(item,index) in list">
                    <td></td>
                    <td></td>
                    <td :class="{ red: item.score < 60 }"></td>
                    <td><a href="#" @click="del(item.id)">删除</a></td>
                </tr>
                </tbody>
                <tbody v-else>
                <tr>
                    <td colspan="5">
                        <span class="none">暂无数据</span>
                    </td>
                </tr>
                </tbody>
    
                <tfoot>
                <tr>
                    <td colspan="5">
                        <span>总分:</span>
                        <span style="margin-left: 50px">平均分:</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="./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(item => item.id !== id)
                },
                add() {
                    this.list.push({id: this.list.length + 1, subject: this.subject, score: this.score})
                }
            },
            computed: {
              totalScore(){
                return this.list.reduce((previous, item) => previous+item.score, 0)
              },
              averageScore(){
                return this.list.length === 0 ? 0 : (this.totalScore / this.list.length).toFixed(2)
              }
            }
        })
    </script>
    </body>
    

3.watch 侦听器

  • 简单写法:对简单数据类型直接进行监视

    image-20231017211708683

  • 完整写法:添加额外配置项监视复杂数据类型

    • deep: true -> 对复杂数据类型深度监视
    • immediate:true -> 初始化立刻执行一次 handler 方法

    image-20231017212123284

  • 案例

    image-20231017212132096

    <body>
    <div id="app">
        <!-- 条件选择框 -->
        <div class="query">
            <span>翻译成的语言:</span>
            <select v-model="obj.language">
                <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"></div>
            </div>
        </div>
    </div>
    <script src="./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: '单词',
                    language: "english"
                },
                transiate: "",
                timerId: ""
            },
            // 具体讲解:(1) watch语法 (2) 具体业务实现
            watch: {
                //  words(newValue){
                //    console.log(newValue)
                // }
                // 监听对象整体属性
                obj: {
                    deep: true, // 深度监视(监视对象所有属性)
                    immediate: true, // 是否立刻执行一次 handler
                    handler(newValue) {
                        clearTimeout(this.timerId)
                        this.timerId = setTimeout(async () => {
                            const res = await axios({
                                url: "https://applet-base-api-t.itheima.net/api/translate",
                                params: newValue
                            })
                            this.transiate = res.data.data
                        }, 1000)
                    }
                },
                // 单独
                /*'obj.words'(newValue){
                  clearTimeout(this.timerId)
                    this.timerId = setTimeout(async () => {
                      const res = await axios({
                        url: "https://applet-base-api-t.itheima.net/api/translate",
                        params: {
                          words: newValue,
                          lang: this.language
                        }
                      })
                      this.transiate = res.data.data
                    },1000)
                }*/
            }
        })
    </script>
    </body>
    

4.综合案例

image-20231017212214458

<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 :class="{tr:true,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="jian(item.id)"> -</button>
                            <span class="my-input__inner">{{ item.num }}</span>
                            <button class="increase" @click="jia(item.id)"> +</button>
                        </div>
                    </div>
                    <div class="td">{{ item.num * item.price }}</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="checkBox" @click="allChecked"/>
                全选
            </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="./vue.js"></script>
<script>
    const defaultList = [
        {
            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")) || defaultList,
            checkboxAll: false
        },
        methods: {
            del(id) {
                this.fruitList = this.fruitList.filter(item => item.id !== id)
            },
            jia(id) {
                this.fruitList.find(item => item.id === id).num++
            },
            jian(id) {
                this.fruitList.find(item => item.id === id).num--
            },
            allChecked() {
                this.fruitList = this.fruitList.map(item => {
                    item.isChecked = this.checkboxAll
                    return item
                })
            }
        },
        computed: {
            totalPrice() {
                return this.fruitList.filter(item => item.isChecked)
                    .reduce((previous, item) => previous + item.num * item.price, 0)
            },
            checkBox: {
                get() {
                    return this.fruitList.every(item => item.isChecked)
                },
                set(value) {
                    this.fruitList.map(item => item.isChecked = value)
                }
            },
            totalCount() {
                return this.fruitList.reduce((previous, item) => item.isChecked ? previous + item.num : previous, 0)
            }
        },
        watch: {
            fruitList: {
                deep: true,
                handler(newValue) {
                    localStorage.setItem("list", JSON.stringify(newValue))
                }
            }
        }
    })
</script>
</body>

results matching ""

    No results matching ""