Vue2全家桶 - Vue2 - 【1】基础API【插值表达式、指令、更新监测和key的作用、动态class和style、计算属性、侦听器、事件处理】

一、插值表达式

  • 数据绑定最常见的形式就是使用"Mustache"语法 (双大括号) 的文本插值;

  • 作用

    • 把Vue变量直接显示在标签内;
  • 表达式

    • 可以被求值,凡是有结果的操作;
      • 字面量;
      • 对象.属性名;
      • 算术运算;
      • 三元表达式;
      • 方法的调用;
  • 语法

    html 复制代码
    <标签> {{ 表达式 }} </标签>
  • 注意

    • 单标签不能使用;
    • Vue数据变量要在 <script>中的 data函数返回对象 中声明;
    • 双大括号之间只能写表达式(上面说的五种);
    • "Mustache"语法会将数据解释为普通文本:
      • 如果要解析HTML,需要配合指令;
    • "Mustache"语法不能作用在 HTML attribute上,遇到这种情况应该使用指令;
  • 代码展示:

    html 复制代码
    <template>
    <!-- 插值表达式:将表达式的值直接显示在标签内 -->
    <!-- 表达式:可以被求值,凡是有结果的操作 -->
    <!-- 
        表达式:
            字面量
            对象.属性名
            算数运算 或 三元表达式
            函数调用
    -->
    <!-- 插值表达式:{{ 表达式 }} -->
    <!-- 
        使用步骤:
            1.声明数据 -> 在data方法返回的对象中声明
            2.书写插值表达式
    -->
        <div>
            <!-- 数据属性名 -->
            <h1>{{ msg }}</h1>
            <!-- 对象.属性名 -->
            <p>我叫{{ obj.name }},今年{{ obj.age }}岁了</p>
            <!-- 算术运算 -->
            <p>明年我就{{ obj.age + 1 }}岁了</p>
            <!-- 三元表达式 -->
            <p>我目前是{{ obj.age >= 18 ? "成年" : "未成年" }}</p>
            <!-- 方法调用 -->
            <p>msg由{{ msg.split(",").length }}个单词组成</p>
        </div>
    </template>
    
    <script>
        export default {
            // 声明数据的地方
            data() {
                return {
                    // msg -> 数据属性
                    msg: "Hello, Vue2!",
                    obj: {
                        name: "小vue",
                        age: 7
                     }
                };
            },
        };
    </script>

二、Vue指令

  • 什么是指令?
    • 指令是带有 v- 前缀的特殊属性。指令的属性的值预期是 单个 JavaScript 表达式v-for是例外情况);
  • 指令的职责是什么?
    • 当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM;

2.1 v-bind

  • 作用

    • 标签属性 动态 赋值
      • 将Vue变量的值赋值给标签;
  • 语法

    • 基本语法:

      html 复制代码
      <标签 v-bind:标签自带的属性名="表达式"></标签>
    • 简写简写:

      html 复制代码
      <标签 :标签自带的属性名="表达式"></标签>
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- 属性绑定指令 -->
            <!-- 语法:v-bind:属性名="表达式" -->
            <!-- <a v-bind:href="url">去B站</a> -->
            <a :href="url">点击去B站</a>
            <a :href="gitee">
                <img :src="img.urlImg" :title="img.title" />
            </a>
        </div>
    </template>
    
    <script>
        // 默认导出
        export default {
            data() {
                return {
                    url: "https://www.bilibili.com/",
                    gitee: "https://gitee.com/",
                    img: {
                        urlImg: "https://gitee.com/static/images/logo-black.svg?t=158106664",
                        title: "点击去Gitee",
                    }
                };
            },
        };
    </script>

2.2 v-on

  • 语法

    • 基本语法:

      js 复制代码
      v-on:事件名 = '要执行的少量代码' // 适合事件处理函数中只改变一个变量的值
      v-on:事件名 = 'methods中的方法名'
      v-on:事件名 = 'methods中的方法名(实参)'
    • 简写简写:

      js 复制代码
      @事件名 = '要执行的少量代码' // 适合事件处理函数中只改变一个变量的值
      @事件名 = 'methods中的方法名'
      @事件名 = 'methods中的方法名(实参)'
  • 注意

    • data函数 会把 return 的 对象 挂载 到 当前 组件实例 上;
    • 事件处理函数中的 this 指向 组件实例
      • this 包含了 data 中所有的 数据属性 和 methods中的方法;
      • 因此我们可以通过 this 访问 data 中的任何一个数据属性和methods中的任何方法;
      • 如果是写在 标签 上,this 可以 省略
  • 关于 this 的注意事项

    • 在开发中我们,我们有时候需要在 mounted钩子函数中监听页面尺寸变等等,此时resize的事件注册方式有两种,一种是使用addEventListener去注册,还有一种就是直接使用window.onresize = xxx这种方式去注册,在这里事件处理函数的声明需要格外的注意:
      • 如果事件处理函数不是箭头函数的话,在事件处理函数内部不能使用this关键字(此时的this指的是事件处理函数内部的this),我们可以在声明一个变量_this,将this的值赋值给_this,然后通过_this访问数据属性或者方法;
      • 如果事件处理函数使用的是箭头函数,那么就可以正常使用this不受影响;
  • 关于此处的【事件对象、事件修饰符、按键修饰符、系统修饰符等 可见 本篇第八节】;

  • 实例展示:

    html 复制代码
    <template>
        <div>
            <!-- 事件绑定指令:v-on -->
            <!-- v-on-click="少量代码" -->
            <!-- v-on-click="methods中方法名" -->
            <!-- v-on-click="methods中方法名(实参)" -->
            <h4>您购买的商品数量:{{ count }}</h4>
            <button v-on:click="count++">+1</button>
            <button v-on:click="add">+5</button>
            <button v-on:click="addFn(10)">+10</button>
            <!-- 简写:v-on: => @ -->
            <button @click="count--">-1</button>
            <button @click="minus">-5</button>
            <button @click="minusFn(10)">-10</button>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    count: 0,
                };
            },
            methods: {
                add() {
                    // 方法中的this指向组件实例(对象)
                    // 这个对象包含了data中所有数据属性和methods方法
                    // 因此我们可以通过this访问data中的任何一个数据属性和methods中的方法
                    this.count += 5;
                },
                addFn(num) {
                    this.count += num;
                },
                minus() {
                    this.count -= 5;
                },
                minusFn(num) {
                    this.count -= num;
                },
            },
        };
    </script>

2.3 v-model

2.3.1 基本语法

  • 作用

    • value 属性 和 Vue数据属性 进行 双向绑定
  • 语法

    js 复制代码
    v-mdoel="Vue数据属性"
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- Vue采用MVVM的设计模式,数据和视图双向绑定 -->
            <!-- v-model:将表单的value属性和Vue数据变量进行双向绑定 -->
            <!-- text,password -->
            <label for="text">用户名:</label>
            <input v-model="text" type="text" id="text" /> <br />
            <label for="pwd">密码:</label>
            <input v-model="pwd" type="password" id="pwd" /> <br />
    
            <!-- 下拉菜单 -->
            <!-- 下拉菜单v-model添加在select标签上,绑定的是option标签的value属性 -->
            <select v-model="city" name="" id="">
                <option value="武汉">武汉</option>
                <option value="杭州">杭州</option>
                <option value="深圳">深圳</option>
                <option value="浙江">浙江</option>
            </select>
            <br />
    
            <!-- 文本域 -->
            <textarea v-model="txt" name="" id="" cols="30" rows="10"></textarea>
    
            <!-- 单选框 -->
            <!-- 
                单选框没有value属性,使用v-model得到的是null
                想要使用v-model就必须手动添加value属性
            -->
            <p>
                <span>性别:</span>
                <label for="man">男</label>
                <input v-model="sex" value="男" type="radio" name="sex" id="man" />
                <label for="woman">女</label>
                <input v-model="sex" value="女" type="radio" name="sex" id="woman" />
            </p>
    
            <!-- 一个复选框 -->
            <!-- 
                要想查看这个复选框是否选中,需要两步
                1.准备一个布尔型的数据变量
                2.通过v-model绑定这个布尔值作用在复选框上即可
                注意:此时这个布尔值和复选框的checked属性关联
            -->
            <p>
                <input v-model="deal" type="checkbox" name="" id="deal" />
                <label for="deal">同意商家协议</label>
            </p>
    
            <!-- 多个复选框 -->
            <!--
                多个复选框:想收集多个值的时候,需要两步:
                1.准备一个数组类型的数据属性
                2.通过v-model绑定这个数组作用在复选框上即可
                注意:此时这个数组和复选框的value属性关联
                      多个复选框需要手动添加value属性
            -->
    
            <p>
                爱好:
                <label for="wuhan">武汉</label>
                <input v-model="city" value="武汉" type="checkbox" name="" id="wuhan" />
                <label for="hangzhou">杭州</label>
                <input
                    v-model="city"
                    value="杭州"
                    type="checkbox"
                    name=""
                    id="hangzhou"
                />
                <label for="shanghai">上海</label>
                <input
                    v-model="city"
                    value="上海"
                    type="checkbox"
                    name=""
                    id="shanghai"
                />
                <label for="zhejiang">浙江</label>
                <input
                    v-model="city"
                    value="浙江"
                    type="checkbox"
                    name=""
                    id="zhejiang"
                />
        </p>
    </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    text: "",
                    pwd: "",
                    city: "武汉",
                    txt: "",
                    sex: "",
                    deal: "",
                    city: [],
                };
            },
        };
    </script>

2.3.2 修饰符

修饰符 作用
.number 尝试调用 parseFloat() 去将字符串转为数字,能转就转,不能转
.trim 去除 首尾 空白符
.lazy 内容改变的同时又失去焦点,在 change 触发时 而非 input
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <div>
                <!-- .number - parseFloat将字符串转成数字型 -->
                <span>年龄:</span>
                <input type="text" v-model.number="age" name="" id="" />
                <!-- <input type="text" v-model.number="age" name="" id="" /> -->
            </div>
            <div>
                <!-- .trim - 去除字符串首尾两侧的空白字符 -->
                <span>人生格言:</span>
                <input type="text" v-model.trim="motto" name="" id="" />
                <!-- <input type="text" v-model.trim="motto" name="" id="" /> -->
            </div>
            <div>
                <span>自我介绍:</span>
                <textarea
                    v-model.lazy="intro"
                    name=""
                    id=""
                    cols="30"
                    rows="10"
                ></textarea>
            </div>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    age: "",
                    motto: "",
                    intro: "",
                };
            },
        };
    </script>

2.3.3 v-model语法糖

  • 这里就举个简单的例子来说明:
    • input输入框为例;
    • 标签上绑定input事件,在input事件的事件处理函数内,将value属性的值赋值给vue数据属性;
    • 在标签上使用v-bind指令给inputvalue属性绑定Vue数据属性;
  • 注意
    • v-model的内部为不同的输入元素使用不同的属性并抛出不同的事件
    • text和textarea元素使用 value属性和input事件
    • checkbox和radio使用checked和change事件

2.4 v-text 和 v-html

  • 作用

    • 显示标签的内容;
  • 语法

    js 复制代码
    v-text = "Vue数据属性"  // 和 innerText 一样 (不识别标签)
    v-html = "Vue数据属性"  // 和 innerHTML 一样 (识别标签)
  • 注意

    • v-html 识别标签;
    • v-text 不识别标签;
    • 覆盖 插值表达式标签的文本
    • v-text插值表达式 效果一样;

2.5 v-show 和 v-if

2.5.1 基础用法

  • 作用

    • 控制标签的 显示隐藏
  • 语法

    js 复制代码
    // 表达式 的 值 为真,标签显示
    // 反之则隐藏
    v-show = "表达式"
    v-if = "表达式"
  • 注意

    • 表达式的值为 true 标签显示,反之则隐藏;
    • v-if优先级 高于 v-show
    • v-if
      • 会产生更大的 渲染 消耗
      • v-if创建删除 DOM元素
    • v-show
      • 会产生更大的 切换 消耗
      • v-show 是 通过 改变 CSS属性(display: block / none;) 来控制标签的 显示隐藏

2.5.2 ❌ v-if的高级用法

  • 首先,在开发中不推荐使用;
  • v-ifJS中的 if 语句很相似;
  • 双分支:
    • v-ifv-else
  • 多分支:
    • v-ifv-else-if
    • 可以写多个 v-else-if,判断的条件不一样;
  • 注意
    • 不管是 双分支 还是 多分支 ,使用的时候,标签与标签的关系 必须是 兄弟关系
  • 为什么在开发的时候不推荐使用?
    • 在阅读代码的时候,如果看到 v-else-ifv-else,都必须先找到 v-if,才能明白后面的意思;
    • 假如 v-if所在标签的代码很多,翻看的时候就是真的很难受哈;
    • 所以大家还是尽量少用吧,是真的很烦;

2.5.3 示例展示

html 复制代码
<template>
    <div>
        <!-- 元素的显示和隐藏 -->
        <!-- 
            v-show : 原理:display: none;
            v-if:原理:直接从DOM树上移除
            相同点:都可以控制元素的显示和隐藏(视觉效果一样)
            不同点:控制元素显示和隐藏的原理不同
                    v-show:控制css的display属性控制
                    v-if:通过创建和插入或者移除DOM元素的方式控制
            使用场景:频繁切换元素的显示隐藏就使用v-show,否则就使用v-if
        -->
        <!-- 双分支 -->
        <p v-if="!token">你好,请登录!</p>
        <p v-else>xxx,欢迎回来!</p>
        
        <!-- 多分支 -->
        <p v-if="score >= 90">A</p>
        <p v-else-if="score >= 80">B</p>
        <p v-else-if="score >= 70">C</p>
        <p v-else-if="score >= 60">E</p>
        <p v-else-if="score < 60">D</p>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                token: "token...",
                score: "85",
            };
        },
    };
</script>

2.6 v-for

  • 这里只介绍基本语法,关于该指令的 更新监测 和 key 请看下一章节;
  • 作用
    • 列表渲染;
    • 循环渲染标签结构;
    • 按照 数组 / 对象 / 数字 循环生成;
      • 在开发中,对象 和 数字 很少使用到(基本遇不到);

2.6.1 ✅❗ 数组

  • 语法

    js 复制代码
    // 索引 / 下标 不是必须的
    v-for="((item, idnex) in 数组)" :key="index"

2.6.2 对象

  • 语法

    js 复制代码
    v-for="((item, idnex) in 对象)" :key="index"

2.6.3 数字

  • 语法

    js 复制代码
    v-for="((item, idnex) in 数字)" :key="index"

2.6.4 注意事项

  • 让谁循环生成,v-for就写在谁身上;
  • in 俩测 必须要有 空格
  • v-for 的变量名 只能用在 v-for 的范围内;
  • 在写 v-for 的时候,需要添加 key 属性;
    • 唯一 不重复 的 数字(❌) 或 字符串(✅)

2.6.5 示例展示

html 复制代码
<template>
    <div>
        <!-- v-for:循环列表 -->
        <!-- 谁想循环就加给谁 -->
        <!-- v-for的变量名只能在v-for的范围内访问 -->
        
        <!-- 语法1:循环数组 -->
        <!-- v-for="(值变量, 索引变量) in 目标结构" -->
        <ul>
            <li v-for="(item, index) in arr" :key="index">
                {{ item }} --- {{ index }}
            </li>
        </ul>
        
        <!-- 语法2:循环数组(不需要索引) -->
        <ul>
            <li v-for="item in stuArr" :key="item">
                {{ item.id }}-{{ item.name }}-{{ item.sex }}-{{ item.hobby }}
            </li>
        </ul>
        
        <!-- 语法3:循环对象 -->
        <ul>
            <li v-for="(value, key) in tObj" :key="value">{{ value }} - {{ key }}</li>
        </ul>
        
        <!-- 语法4:循环固定数字 -->
        <ul>
            <li v-for="n in count" :key="n">
                {{ n }}
            </li>
        </ul>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                arr: ["小明", "小欢欢", "大黄"],
                stuArr: [
                    {
                        id: 1001,
                        name: "孙悟空",
                        sex: "男",
                        hobby: "吃桃子",
                    },
                    {
                        id: 1002,
                        name: "猪八戒",
                        sex: "男",
                        hobby: "背媳妇",
                    },
                ],
                tObj: {
                    name: "小黑",
                    age: 18,
                    class: "1期",
                },
                count: 10,
            };
        },
    };
</script>

三、更新监测和key的作用

3.1 更新监测

  • 目标结构变化,触发v-for的更新;

  • 哪些操作会导致目标结构发生变化并使v-for更新?

    • 数组的变更方法(改变原始数组的方法):
      • push、unshift、pop、shift、splice、reverse
    • 数组非变更方法(不改变原始数组的方法):
      • 注意
        • 数组非变更方法,返回一个新数组,并不会导致v-for的更新;
      • 解决办法
        • 将返回的新数组重新赋值给目标结构即可;
    • 更新某个值;
      • 注意
        • 更新某个值的时候,v-for监测不到,不会更新;
      • 解决办法
        • 使用 this.$set()

        • 语法

          js 复制代码
          // 目标结构:需要更新的数组或对象
          // 数组的索引:需要更新的是数组的第几个值
          // 对象的属性:需要更新的是对象的哪个属性
          this.$set(目标结构, 数组的索引 / 对象的属性, 更新值)
  • v-for更新时,会循环出新的虚拟DOM,和旧的虚拟DOM结构比较,尝试复用标签就地更新(diff算法);

  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- 更新监测 -->
            <ul>
                <li v-for="item in arr" :key="item">{{ item }}</li>
            </ul>
            <button @click="reverseFn">数组变更方法</button>
            <button @click="changeFn">数组非变更方法</button>
            <button @click="noChangeFn">改变某个值</button>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    arr: [1, 2, 3, 4, 5],
                };
            },
            methods: {
                reverseFn() {
                    // 1.调用数组变更方法(改变原始数组的方法)
                    // 会导致 v-for 的更新,页面更新
                    // push, unshift, pop, shift, splice, sort, reverse
                    // this指向组件实例
                    this.arr.reverse();
                },
                changeFn() {
                    // 2.调用数组非变更方法,返回一个新数组,不会导致 v-for 的更新
                    // 解决方法: 只用得到的新数组直接覆盖原始数组,既对原始数组进行赋值操作
                    this.arr = this.arr.slice(0, 3);
                },
                noChangeFn() {
                    // 3.改变数组某个值的时候,v-for监测不到,不会导致v-for更新
                    // 解决方法: 使用 this.$set()
                    // 语法: this.$set(更新的目标结构, 改变元素的索引, 更新值)
                    this.$set(this.arr, 0, 1000);
                },
            },
        };
    </script>

4.3 key的作用

  • key:
    • 唯一 不重复 的 数字 或 字符串
  • key的使用:
    • 有id用id,无id用索引。
  • key的优点:
    • 可以配合虚拟DOM提高更新性能。

四、动态class

  • 使用 v-bind 给标签 动态设置 class 的值;

  • 语法

    js 复制代码
    // 表达式为真,类名生效;反之,则不生效。
    // 1. 三元绑定法
    <标签 :class = "条件 ? '类名1' : '类名2'"></标签>
    
    // 2. 对象绑定法
    // 可以绑定多个类名
    <标签 :class = { 类名: 表达式 }></标签>
    
    // 3.将现有 class(固定类名) 进行合并 - 数组
    <标签 :class = ["固定类名", 条件 ? '类名1' : '类名2', { 类名: 表达式 }]></标签>
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- 动态设置 - class -->
            <!-- 1.三元绑定法 -->
            <p class="xiHa" :class="isActive ? 'active' : ''">嘻哈少年1</p>
    
            <!-- 2.对象绑定法 -->
            <p class="xiHa" :class="{ active: 'active' }">嘻哈少年2</p>
    
            <!-- 3.将现有 class(固定类名) 进行合并 - 数组 -->
            <p :class="['xiHa', flag1 ? 'color1' : '', { color2: flag2 }]">嘻哈少年3</p>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    isActive: true,
                    flag1: true,
                    flag2: true
                };
            },
        };
    </script>
    
    <style>
        .xiHa {
            font-size: 30px;
        }
        .active {
            color: #9e03d6;
            font-size: 40px;
            font-family: '隶书';
        }
    
        .color1 {
            color: red;
        }
    
        .color2 {
            font-size: 50px;
        }
    </style>

五、动态style

  • 标签 动态设置 style 的值;

  • 语法

    js 复制代码
    :style = "{ css属性名: 表达式 }"
    // 针对行内样式
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- 动态设置style -->
            <!-- 语法: :style={css属性名: 值} -->
            <!-- 驼峰命名法 -->
            <p :style="{ backgroundColor: '#e6004b' }">动态设置style</p>
            <p :style="{ color: colorStr }">鸡你太美</p>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    colorStr: "green",
                };
            },
        };
    </script>

六、计算属性

6.1 基础

  • 计算属性

    • 一个数据属性的值,依赖于另外的数据属性计算而来的结果
  • 语法:

    js 复制代码
    computed: {
        计算属性名() {
            // 必须要有return
            return 值;
        }
    }
  • 使用

    • 计算属性也是vue变量,使用的时候,直接当作vue数据属性,直接使用即可。
  • 注意:

    • 计算属性也是vue数据属性,所以不要和data里的变量重名;
    • 计算属性 必须要有 return
    • 计算属性 声明 的时候是 方法,但是在 使用 的时候是 属性(有return);
    • 当依赖发生变化的时候,计算属性会重新执行,返回新的结果
  • 使用场景

    • 当一个变量的值,需要通过另外的变量计算而来就使用计算属性(单选和多选框);
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <!-- 计算属性也是vue变量,使用的时候,直接当作vue变量使用 -->
            <p>{{ add }}</p>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    a: 10,
                    b: 20,
                };
            },
            // 计算属性 - computed
            // 一个变量的值,需要用另外的变量计算得来
            // 	语法:
            // 	computed: {
            // 	    计算属性名() {
            // 	        return 值
            //          }
            // 	}
            computed: {
                add() {
                    return this.a + this.b;
                },
            },
        };
    </script>

6.2 计算属性缓存特性

  • 计算属性基于依赖的值进行缓存,依赖的变量不变,都直接从缓存中取结果。
  • 计算属性的优势:
    • 缓存特性;
    • 计算属性对应的函数执行后,会把 return 的值缓存起来;
    • 如果依赖项不发生变化,多次使用都是从缓存中取值;
    • 依赖项的值发生变化,函数会 自动 重新执行,并把最新的结果再次缓存起来。

6.3 进阶 - 完整写法

  • 计算属性 也是 vue数据属性,也可以使用 v-model 双向关联 表单数据 的 值;

  • 写法的选择:

    • 只是读取值:
      • 写简易写法(函数形式,必须要有 return );
    • 给计算属性赋值:
      • 必须写完整写法(对象形式);
  • 语法:

    js 复制代码
    computed: {
        计算属性名: {
            set(val) {
                // 不需要传递参数,自动接收要给计算属性赋值的数据
                // val => 要给计算属性赋值的数据
            },
            get() {
                // 对应的逻辑
                return 值
            }
        }
    }
  • 注意

    • 给计算属性 赋值 ,触发 set 方法;
    • 使用 计算属性的 ,触发 get 方法。
  • 代码展示:

    html 复制代码
    <template>
        <div>
            <p>
                <span>用户名:</span>
                <input type="text" v-model="full" name="" id="" />
            </p>
        </div>
    </template>
    
    <script>
        export default {
            // 给计算属性赋值
            // 计算属性完整写法:
            // computed: {
            //     属性名: {
            //          给full赋值触发set方法
            //          set(值) {},
            //          使用full的值触发get方法
            //          get() {
            //              return 值;
            //          },
            //      },
            // },
            computed: {
                full: {
                    // 给full赋值触发set方法
                    set(val) {
                        console.log(val);
                    },
                    // 使用full的值触发get方法
                    get() {
                        return "张三";
                    },
                },
            },
        };
    </script>
  • 单选、多选、反选 案例:

    html 复制代码
    <template>
        <div>
            <span>全选:</span>
            <input type="checkbox" v-model="isAll" />
            <button @click="opposite">反选</button>
            <ul>
                <li v-for="(item, key) in arr" :key="key">
                    <input type="checkbox" v-model="item.c" />
                    <span>{{ item.name }}</span>
                </li>
            </ul>
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    arr: [
                        {
                            name: "猪八戒",
                            c: false,
                        },
                        {
                            name: "孙悟空",
                            c: false,
                        },
                        {
                            name: "唐僧",
                            c: false,
                        },
                        {
                            name: "白龙马",
                            c: false,
                        },
                    ],
                };
            },
            methods: {
                opposite() {
                    this.arr.forEach((item) => (item.c = !item.c));
                },
            },
            // 计算属性
            computed: {
                isAll: {
                    set(val) {
                        this.arr.forEach((item) => (item.c = val));
                    },
                    get() {
                        return this.arr.every((item) => item.c === true);
                    },
                },
            },
        };
    </script>

七、侦听器

7.1 侦听基本数据类型

  • 作用

    • 侦听 datacomputed 属性值的改变。
  • 语法:

    js 复制代码
    // 侦听器的简易写法 - 监听基本数据类型
    watch: {
        被侦听的属性名(newVal, oldVal) {
            // 相关逻辑
        }
    }
    // newVal:当前最新的值
    // oldVal:上一次的值,旧值
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <input v-model="keyWord" type="text" />
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    keyWord: "",
                };
            },
            // 侦听器
            // 语法:
            // watch: {
            // 	被侦听的属性名或方法名(newValue, oldValue) {
            //		函数体
            // 	}
            // },
            watch: {
                keyWord(newValue, oldValue) {
                    console.log(newValue, oldValue);
                },
            },
        };
    </script>

7.2 侦听引用数据类型

  • 语法:

    js 复制代码
    // 如果使用简易写法,当给引用数据赋值的时候才能监测到
    // 如果想要知道引用数据类型里面的数据什么发生变化,就必须使用完整写法
    watch: {
        // 固定写法
        data / computed里要侦听的属性名: {
            // 深度侦听引用数据变化
            deep: true, 
            // 立即执行,侦听器函数立即执行,默认为false(一般为false)
            immediate: true,
            handler (newVal, oldVal) {
                // 具体逻辑
            }
        }
    }
  • 注意

    • 侦听引用数据类型,要加 deep: true 开启深度侦听;
    • 属性名都是固定写法
    • 新旧对象,原来的对象,三者指向同一地址。
  • 示例展示:

    html 复制代码
    <template>
        <div>
            <input v-model="uname" type="text" /> <br />
            <input v-model="msg.age" type="text" />
        </div>
    </template>
    
    <script>
        export default {
            data() {
                return {
                    uname: "",
                    msg: {
                        age: 0,
                    },
                };
            },
            // 侦听器
            watch: {
                // 侦听基本数据类型 - 简易写法 - 格式:方法
                // 语法:
                // "data或watch里侦听的属性名"(newVal, oldVal) {
                // 	                                                函数体
                //                                            }
                uname(newVal, oldVal) {
                        console.log(newVal, oldVal);
                },
    
                // 侦听引用数据类型 - 完整写法 - 格式:配置项
                // 侦听的是引用数据类型 - 只要有一个变化,整个引用数据都要变化
                // 语法:
                // "data或methods里侦听的属性名": {
                // 	    immediate: true,	// 立即执行,侦听器函数马上执行,默认为false(一般为false或直接不写)
                // 	    deep: true,
                // 	    handler (newVal, oldVal) {
                // 		函数体
                // 	    }
                // }
                msg: {
                    // deep, handler --  固定写法
                    deep: true, // 开启深度侦听
                    handler(newVal, oldVal) {
                        console.log(newVal, oldVal);
                        // 新旧对象,原来的对象 - 指向同一地址
                        console.log(newVal === oldVal); // true
                        console.log(this.msg === newVal); // true
                    },
                },
            },
        };
    </script>

八、事件处理

8.1 事件对象

  • 语法

    • 方法没有传递实参:
      • 事件处理函数不需要参数的时候;
      • 声明方法的时候,直接通过形参直接接收,在方法中就可以直接使用;
    • 方法有传递实参:
      • 事件处理函数还需要其他的参数;
      • 通过 $event 指代事件对象传给事件处理函数;
  • Vue事件处理函数,如何拿到事件对象?

    • 没有传递实参:
      • 直接在形参接收;
    • 有传递实参:
      • 手动传入$event对象;
  • 示例展示:

    html 复制代码
    <template>
      <div>
        <!-- 阻止事件默认行为 -->
        <!-- 
          语法:
            无传参:可以直接通过事件对象接收
            有传参:通过 $event 指代事件对象传递给事件处理函数
        -->
        <a v-on:click="one" v-bind:href="url">{{ text }}</a>
        <a @click="two(10, $event)" :href="url">{{ text }}</a>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          url: "http://www.baidu.com",
          text: "阻止去百度",
        };
      },
      methods: {
        one(e) {
          e.preventDefault();
        },
        two(num, e) {
          e.preventDefault();
        },
      },
    };
    </script>

8.2 事件修饰符

  • 语法

    js 复制代码
    @事件名.修饰符="方法名"
  • 常用修饰符

    修饰符 功能
    .stop 阻止事件冒泡
    .prevent 阻止事件默认行为
    .once 程序运行期间,事件处理函数只执行一次(事件还能触发,事件处理函数只执行一次)
    .native 监听原生事件(主要是和一些组件库一起使用)
    .self 只当在 event.target 是当前元素自身时触发事件处理函数(即事件不是从内部触发的)
    更多修饰符 见Vue2官方文档 - 事件修饰符
  • 注意

    • 多个修饰符可以一起使用;
    • .once修饰符还可以作用到组件的自定义事件上;
    • 使用修饰符的时候,顺序很重要,相应的代码会以同样的顺序产生;
      • v-on:click.prevent.self 会阻止所有的点击 ,而 v-on:click.self.prevent 只会阻止对元素自身的点击;
  • 示例展示:

    html 复制代码
    <template>
      <div>
        <!-- 事件修饰符 -->
        <!-- .stop:阻止 事件 冒泡 -->
        <!-- .prevent:阻止 事件 默认行为 -->
        <!-- .once:程序运行期间,只触发一次事件处理函数 -->
        <!--- 多个修饰符可以一起使用 -> 链式调用 -->
        <div @click="fatherFn" class="father">
          <button @click.stop="oneFn">{{ textStop }}</button>
          <br />
          <a @click.prevent.stop="prevent" :href="url">{{ textPrevent }}</a>
          <br />
          <input @input.once.stop="input" @click.stop type="text" />
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          textStop: ".stop - 阻止事件冒泡",
          url: "http://www.bilibili.com",
          textPrevent: ".prevent - 阻止事件默认行为",
          textOnce: ".once - 程序运行期间,只触发一次事件处理函数",
          i: 1,
        };
      },
      methods: {
        fatherFn(e) {
          console.log(`我是${e.target.tagName}的父级`);
        },
        oneFn(e) {
          console.log(`我点击了${e.target.tagName}`);
        },
        prevent() {
          console.log("阻止了a链接的默认跳转");
        },
        input() {
          console.log(this.i++);
        },
      },
    };
    </script>

8.3 键盘按键修饰符

  • 语法

    js 复制代码
    @键盘事件.enter ➡ 监测回车按键
    @键盘事件.esc ➡ 监测esc按键
  • 更多按键修饰符

  • 示例展示:

    html 复制代码
    <template>
      <div>
        <!--语法:-->
        <!--  @键盘事件.enter - 监测回车键 -->
        <!-- @键盘事件.esc - 监测Esc键 -->
        <input type="text" @keydown.enter="enterFn" @keydown.esc="escFn">
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {}
      },
      methods: {
        enterFn() {
          console.log('按下了回车键');
        },
        escFn() {
          console.log('按下了取消键');
        },
      },
    }
    </script>

8.4 鼠标按键修饰符

修饰符 功能
.left 按下鼠标左键
.middle 按下鼠标滚轮键
.right 按下鼠标右键

8.5 系统修饰符

  • 可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。

    • .ctrl
    • .alt
    • .shift
    • .meta
  • 注意

    • Mac 系统键盘上,meta 对应 command 键 (⌘)。
    • Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。
    • Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。
    • 在其他特定键盘上,尤其在 MITLisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为"META"。
    • Symbolics 键盘上,meta 被标记为"META"或者"Meta"。
  • 示例展示:

    html 复制代码
    <!-- Alt + C -->
    <input v-on:keyup.alt.67="clear">
    
    <!-- Ctrl + Click -->
    <div v-on:click.ctrl="doSomething">Do something</div>

请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCodekeyup.17

8.6 .exact修饰符

  • .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

  • 示例展示:

    html 复制代码
    <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->  
    <button v-on:click.ctrl="onClick">A</button>  
    
    <!-- 有且只有 Ctrl 被按下的时候才触发 -->  
    <button v-on:click.ctrl.exact="onCtrlClick">A</button>  
    
    <!-- 没有任何系统修饰符被按下的时候才触发 -->  
    <button v-on:click.exact="onClick">A</button>
相关推荐
kyriewen13 分钟前
折腾了半年 AI 编程工作流,最后发现效率瓶颈是桌上那块屏幕
前端·javascript·ai编程
蜗牛前端40 分钟前
codex 全流程开发上线的高颜值礼簿小程序
前端·微信小程序
大龄秃头程序员1 小时前
我在图文流 App 里落地双层缓存、弱网降级与 OOM 治理
前端
老王以为1 小时前
React Renderer 分离的多平台架构
前端·react native·react.js
hunterandroid1 小时前
Kotlin Coroutines 与 Flow:让异步任务更清晰
前端
Bigger2 小时前
从零搭建 AI 代码审查服务:一份前端也能看懂的 Python 学习笔记
前端·ci/cd·ai编程
lichenyang4532 小时前
JSAPI、NAPI、Biz、Imp:ASCF Demo 如何真正调用系统能力和 C++ 能力
前端
lichenyang4533 小时前
IPC、JSVM、UIThread、libuv:ASCF 架构图里最容易混的几个词
前端
用户059540174463 小时前
Redis记忆存储故障恢复测试踩坑实录:手动测试让我漏掉了2个一致性Bug
前端·css
用户2136610035723 小时前
Vue2脚手架工程化与Axios集成
前端·vue.js