2 Vue指令和Vue对象的配置项

  • Vue 会根据不同的指令,针对标签实现不同的功能
  • 指令:带有v-前缀 的特殊标签属性。

2.1 v-html

  • 作用:设置元素里的innerHTML;

  • 语法:v-html = "表达式"

  • 例:

    <div v-html="str"></div>
    

2.2 v-show

  • 作用:控制元素显示隐藏;

  • 语法:v-show = "表达式",表达式值为true时显示元素,为false时隐藏元素;

  • 原理:通过是否给元素添加display: none来控制显示隐藏;

  • 使用场景:需要频繁切换元素的显示隐藏的场景。例如下面的购物车元素,当鼠标放到该元素上时,显示购物车列表:

    在这里插入图片描述

2.3 v-if

  • 作用:基于条件判断来控制元素显示隐藏;

  • 语法:v-if = "表达式",表达式值为true时显示元素,为false时隐藏元素;

  • 原理:基于条件判断,来决定是否创建或移除元素;

  • 使用场景:对于要么显示,要么隐藏的元素。比如:

    在这里插入图片描述

2.4 v-else和v-else-if

  • 作用:辅助v-if进行判断渲染;

  • 语法:v-elsev-else-if = "表达式"

  • 注意: 需要紧挨着v-if一起使用;

  • 例:

    <div id="app">
      <p v-if="gender === 1">性别:男</p>
      <p v-else>性别:女</p>
      <hr>
      <p v-if="score >= 90">成绩评定A</p>
      <p v-else-if="score >= 70">成绩评定B</p>
      <p v-else-if="score >= 60">成绩评定C</p>
      <p v-else>成绩评定D</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: {
          gender: 2,
          score: 95 //通过改变score的值,来显示隐藏对应的元素
        }
      })
    </script>
    

2.5 v-on

  • 作用:注册事件,即添加数据监听后,提供数据处理逻辑;

  • 语法1:v-on:事件名 = "内联语句"或简写@事件名 = "内联语句"

    <button v-on:click = "count--">-</button>
    <span>{{ count }}</span>
    <button v-on:click = "count++">+</button>
    
    //简写
    <button @click = "count--">-</button>
    <span>{{ count }}</span>
    <button @click = "count++">+</button>
    
  • 语法2:v-on:事件名 = "methods中的函数名"或简写@事件名 = "methods中的函数名"

    • methods函数内的this指向 Vue 实例;
    <div id="app">
      <button @click = "fn">切换显示隐藏</button>
      <h1 v-show="isShow">嘿嘿</h1>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          isShow: true
        },
        methods: {
          fn () {
            //app.isShow = !app.isShow
            //或者
            this.isShow = !this.isShow
          }
        }
      })
    </script>
    
  • 基于语法2的调用传参:v-on:事件名 = "methods中的函数名(参数1, 参数2)"或简写@事件名 = "methods中的函数名(参数1, 参数2)"

    <div id="app">
      <div class="box">
        <h3>自动售货机</h3>
        <button @click = "buy(5)">可口可乐5元</button>
        <button @click = "buy(7)">百事可乐7元</button>
      </div>
      <p>账户余额:{{ money }}元</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: {
          money: 100
        },
        methods: {
          buy (price) {
            this.money -= price
          }
        }
      })
    </script>
    

2.6 v-bind

2.6.1 操作基本属性
  • 作用:动态地设置html元素的标签属性,如srcurltitle

  • 语法:v-bind:属性名="表达式"或简写:属性名="表达式"

  • v-bind是数据单向渲染,数据变化,会影响到视图;

  • 图片切换案例:

    <!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>图片切换案例</title>
    </head>
    
    <body>
      <div id="app">
        <button v-show="index > 0" @click="index--">上一页</button>
        <div>
          <img v-bind:src="list[index]" alt="">
        </div>
        <button v-show="index < list.length -1 " @click="index++">下一页</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: {
            index: 0,
            list: [
              './imgs/11-00.gif',
              './imgs/11-01.gif',
              './imgs/11-02.gif',
              './imgs/11-03.gif',
              './imgs/11-04.png',
              './imgs/11-05.png',
            ]
          }
        })
      </script>
    </body>
    
    </html>
    
2.6.2 操作class属性
  • 语法1:.class="对象"

    • 键是类名,值是布尔值。若值为true,则有这个类;若值为false,则无这个类;

      <div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>
      
    • 使用场景:来回切换一个类名时可以使用;

  • 语法2:.class="数组"

    • 数组中所有的类,都会添加到该元素上,本质就是一个class列表;

      <div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>
      
    • 批量添加或删除类时可以使用。

tab导航高亮
<!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>tab导航高亮</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      display: flex;
      border-bottom: 2px solid #e01222;
      padding: 0 10px;
    }

    li {
      width: 100px;
      height: 50px;
      line-height: 50px;
      list-style: none;
      text-align: center;
    }

    li a {
      display: block;
      text-decoration: none;
      font-weight: bold;
      color: #333333;
    }

    li a.active {
      background-color: #e01222;
      color: #fff;
    }
  </style>
</head>

<body>

  <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>
</body>

</html>
2.6.3 操作style
  • 语法::style = "样式对象"

    <div class="box" :style="{ CSS属性1: CSS属性值, CSS属性2: CSS属性值 }"></div>
    
  • 需要动态地设置某个具体属性时使用。

进度条效果
<!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>
    .progress {
      height: 25px;
      width: 400px;
      border-radius: 15px;
      background-color: #272425;
      border: 3px solid #272425;
      box-sizing: border-box;
      margin-bottom: 30px;
    }

    .inner {
      width: 50%;
      height: 20px;
      border-radius: 10px;
      text-align: right;
      position: relative;
      background-color: #409eff;
      background-size: 20px 20px;
      box-sizing: border-box;
      transition: all 1s;
    }

    .inner span {
      position: absolute;
      right: -20px;
      bottom: -25px;
    }
  </style>
</head>

<body>
  <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: 0
      }
    })
  </script>
</body>

</html>

2.7 v-for

  • 作用:基于数据循环, 多次渲染某个元素;

  • 语法:v-for = "(item, index) in 数组名

    • item对应每一项的元素,index对应下标;
    • 也可以省略index,直接写:v-for = "item in 数组名"
  • 例:

    <div id="app">
      <h3>书架</h3>
      <ul>
        <li v-for="(item, index) in booksList">
          <span>{{ item.name }}</span>
          <span>{{ item.author }}</span>
            <!-- 注册点击事件,通过id来删除数组中的对应项 -->
          <button @click="del(item.id)">删除</button>
        </li>
      </ul>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          booksList: [
            { id: 1, name: '《红楼梦》', author: '曹雪芹' },
            { id: 1, name: '《西游记》', author: '吴承恩' },
            { id: 1, name: '《水浒传》', author: '施耐庵' },
            { id: 1, name: '《三国演义》', author: '罗贯中' }
          ]
        },
        methods: {
          del (id) {
            //调用filter()函数,该函数会保留满足条件的对应项得到一个新数组,将该新数组赋给原数组即可
           this.booksList = this.booksList.filter(item => item.id !== id)
          }
        }
      })
    </script>
    
  • 要给v-for所在元素加一个==key属性==作为该列表项的唯一标识,便于Vue对列表项进行正确的排序复用,接上例:

    <li v-for="(item, index) in booksList" :key="item.id">
    
    • 若不加key属性,则v-for是对元素进行原地复用,即不删除原本的元素,只是将未被删除的数据重新渲染上去;
    • 若加了key属性,则v-for会将对应的元素删除,再将剩余的元素重新在页面上排列;
    • 注意:
      • key属性的值只能是字符串或数字类型;
      • key属性的值必须具有唯一性;
      • 推荐使用每一条数据对应的id作为key属性的值,不推荐使用index,因为index会变化、不对应。

2.8 v-model

  • 作用:表单元素使用,可以实现双向数据绑定,即可以快速获取或设置表单元素内容;

    • 双向数据绑定,也称数据双向渲染,即当数据变量则视图自动更新,当视图变化则数据自动更新;
  • 语法:v-model='变量'

  • 例:

    <div id="app">
      账户:<input type="text" v-model="username"> <br><br>
      密码:<input type="password" v-model="password"> <br><br>
      <button @click="login">登录</button>
      <button @click="reset">重置</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: {
          username: '',
          password: ''
        },
        methods: {
          login () {
            //可以获取到用户名和密码
            console.log(this.username, this.password)
          },
          reset () {
            this.username = ''
            this.password = ''
          }
        }
      })
    </script>
    
  • v-model会根据控件类型自动选取正确的方法来更新元素。如:

    • 输入框input:text,value;
    • 文本域textarea,value;
    • 复选框input:checkbox,checked;
    • 单选框input:radio,checked;
    • 下拉菜单select,value;
  • 例,表单信息收集:

    <!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>表单信息收集</title>
      <style>
        textarea {
          display: block;
          width: 240px;
          height: 100px;
          margin: 10px 0;
        }
      </style>
    </head>
    
    <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" value="1" v-model="gender"><input type="radio" name="gender" value="2" v-model="gender"><br><br>
    
        <!-- 
          前置理解:
            1. option 需要设置 value 值,提交给后台
            2. select 的 value 值,关联了选中的 option 的 value 值
          结合 Vue 使用 → v-model
        -->
        所在城市:
        <select v-model="cityId">
          <option value="101">北京</option>
          <option value="102">上海</option>
          <option value="103">成都</option>
          <option value="104">南京</option>
        </select>
        <br><br>
    
        自我描述:
        <textarea v-model="desc"></textarea>
    
        <button>立即注册</button>
      </div>
      <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            username: '',
            isSingle: true,
            gender: "2",
            cityId: '101',
            desc: ""
          }
        })
      </script>
    </body>
    
    </html>
    

2.9 指令修饰符

  • 通过.指明一些指令 后缀,不同后缀封装了不同的处理操作。
2.9.1 事件修饰符
  • @事件名.stop:调用event.stopPropagation(),阻止事件继续传播,或者说阻止事件冒泡;

    <!-- 阻止单击事件继续传播 -->
    <a @click.stop="doThis"></a>
    
  • @事件名.prevent:调用event.preventDefault(),阻止事件的默认行为;

    <!-- 提交事件不再重载页面 -->
    <form @submit.prevent="onSubmit"></form>
    
  • @事件名.capture:添加事件监听器时使用事件捕获模式,即在子组件中捕获父组件事件;

    <!-- 添加事件监听器时使用事件捕获模式 -->
    <div @click.capture="doThis">...</div>
    
  • @事件名.self:确保事件只在监听器绑定的元素上触发时,而不会冒泡到其子元素或祖先元素上;

  • @事件名.once:只触发一次。不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上;

  • @事件名.passive:告诉浏览器你不想阻止事件的默认行为,该修饰符尤其能够提升移动端的性能;

    • <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 onScroll 完成,即不会调用 preventDefault() -->
      <div @scroll.passive="onScroll">...</div>
      
    • 不要把.passive.prevent一起使用,因为.prevent将会被忽略,同时浏览器可能会向你展示一个警告,.passive会告诉浏览器你不想阻止事件的默认行为。

  • 注意:使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生。

    • 例:用@click.prevent.self会阻止所有的点击,而@click.self.prevent只会阻止对元素自身的点击。
2.9.2 按键修饰符
  • 按键修饰符有,即在@keyup后可以加:

    • .enter
    • .tab
    • .delete (捕获“删除”和“退格”键)
    • .esc
    • .space
    • .up
    • .down
    • .left
    • .right
  • 例:

    <!-- 只有在 key 是 Enter 时,即用户按下回车键后,调用 submit 方法 -->
    <input @keyup.enter="submit">
    
2.9.3 系统修饰符
  • 可以用以下修饰符来实现仅在按下相应按键时才触发事件的监听器:

    • .ctrl

    • .alt

    • .shift

    • .meta(Mac的Command键,Windows的Win键)

    • 例:

      <!-- Alt + C -->
      <input v-on:keyup.alt.67="clear">
      
      <!-- Ctrl + Click -->
      <div v-on:click.ctrl="doSomething">Do something</div>
      
  • .exact修饰符允许控制由精确的系统修饰符组合触发的事件:

    <!-- 以下这种情况,即使 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>
    
  • 鼠标按钮修饰符,这些修饰符会限制处理函数仅响应特定的鼠标按钮:

    • .left
    • .right
    • .middle
2.9.4 v-model修饰符
  • v-model.lazy:将输入事件由默认的input事件改为change事件。这意味着数据绑定将在change事件触发时更新,而不是在每次输入事件触发时更新;
  • v-model.number:转为数值类型;
  • v-model.trim:去除首尾空格。

2.10 计算属性

2.10.1 概念及语法
  • 概念:基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算;

  • 语法:

    • 声明在Vue对象的computed配置项中,用一个计算函数来返回计算的结果,这个计算的结果就是计算属性名;

      computed: {
        计算属性名 () {
          基于现有数据,编写求值逻辑
          return 结果
        }
      },
      
    • 使用方法和普通属性一样,即{{ 计算属性名}}

  • 例:

    <!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>计算属性</title>
      <style>
        table {
          border: 1px solid #000;
          text-align: center;
          width: 240px;
        }
    
        th,
        td {
          border: 1px solid #000;
        }
    
        h3 {
          position: relative;
        }
      </style>
    </head>
    
    <body>
    
      <div id="app">
        <h3>小黑的礼物清单</h3>
        <table>
          <tr>
            <th>名字</th>
            <th>数量</th>
          </tr>
          <tr v-for="(item, index) in list" :key="item.id">
            <td>{{ item.name }}</td>
            <td>{{ item.num }}个</td>
          </tr>
        </table>
    
        <!-- 目标:统计求和,求得礼物总数。注意下面的totalCount不要加(),因为计算属性本质上还是属性 -->
        <p>礼物总数:{{totalCount}} 个</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: {
            totalCount() {
              //利用reduce方法对数组进行求和计算,0是初始值,先赋值给sum,然后将数组元素对sum进行累加
              let total = this.list.reduce((sum, item) => sum + item.num, 0)
              return total
            }
          }
        })
      </script>
    </body>
    
    </html>
    

    在这里插入图片描述

2.10.2 computed VS methods
  • computed计算属性:
    • 作用:封装了一段对于数据的处理,求得一个结果;
    • 语法:
      • 写在computed配置项中;
      • 作为属性,直接使用;
  • methods方法:
  • 作用:给实例提供一个方法,调用以处理业务逻辑;
  • 语法:
    • 写在methods配置项中;
    • 作为方法,需要调用。
  • computedmethods的好处在于:computed缓存特性,可以提升性能;
    • 缓存特性:计算属性会将计算出来的结果缓存,再次使用直接读取缓存即可。若依赖项变化了,会自动重新计算,并再次缓存。
2.10.3 完整写法
  • 计算属性默认的简写,只能读取计算属性的值,不能"修改"。 如果要"修改",需要写计算属性的完整写法。如下:

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

    <!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>计算属性完整写法</title>
    </head>
    
    <body>
    
      <div id="app">
        姓:<input type="text" v-model="firstName"><br>
        名:<input type="text" v-model="lastName"><br>
        <p>姓名:</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: '备'
          },
          methods: {
            changeName() {
              this.fullName = '吕布'
            }
          },
          computed: {
            fullName: {
              get() {
                return this.firstName + this.lastName
              },
              set(value) {
                //在数组上调用 slice() 方法会返回一个新的数组,包含从开始索引到结束索引(但不包括结束索引处的元素)的部分。
                //在字符串上调用 slice() 方法同样会返回一个新的字符串,包含从开始索引到结束索引(但不包括结束索引处的字符)的部分。
                this.firstName = value.slice(0, 1)
                this.lastName = value.slice(1)
              }
            }
          }
        })
      </script>
    </body>
    
    </html>
    
    • 当点击按钮时,会执行 changeName 方法,该方法会更新 fullName 的值,从而触发计算属性的 set 方法,进而更新 firstNamelastName

2.11 watch侦听器(监听器)

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

  • 简单语法:直接监视简单类型数据

    data: {
      words: '苹果',
      obj: {
        words: '苹果'
      }
    },
    watch: {
      //以下的方法会在监听的数据发生变化时被触发执行
      //newValue表示新值,oldValue表示旧值
      数据属性名(newValue, oldValue) {
        一些业务逻辑或异步操作
      },
      '对象.属性名'(newValue, oldValue) {
        一些业务逻辑或异步操作
      }
    }
    
  • 完整写法:添加额外配置项

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

    • immediate: true:一进页面就立刻执行一次handler方法。该属性不是一定要有,依需求而定;

      data: {
        obj: {
          words: '苹果',
          lang: 'italy'
        }
      },
      watch: {
        //以下的方法会在监听的数据发生变化时被触发执行
        obj: { //注意此处不写 '对象.属性名',而是直接写对象
          deep: true, //深度监视
          immediate: true, //一进页面就立刻执行一次handler方法
          handler (newValue) {
            一些业务逻辑或异步操作
          }
        }
      }
      

更多推荐