Vue指令

51 阅读6分钟

指令修饰符

"." 指明一些指令 后缀,不同 后缀 封装了不同的处理操作 → 简化代码

  • ① 按键修饰符
    @keyup.enter → 键盘回车监听
  • ② v-model修饰符
    v-model.trim → 去除首尾空格
    v-model.number → 转数字
  • ③ 事件修饰符
    @事件名.stop → 阻止冒泡
    @事件名.prevent → 阻止默认行为
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h3>@keyup.enter → 监听键盘回车事件</h3>
      <input @keyup.enter="fn" type="text" v-model="username" />
    </div>

    <script src="./vue.js"></script>

    <script>
      const app = new Vue({
        el: "#app",
        data: {
          username: "",
        },
        methods: {
          // fn(e) {
          //   if (e.key === "Enter") {
          //     console.log(e);
          //     console.log("键盘回车时触发", this.username);
          //   }
          // },
          fn(e){
            console.log(e);
            console.log("键盘回车时触发", this.username);
          }
        },
      });
    </script>
  </body>
</html>
<!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>
      .father {
        width: 200px;
        height: 200px;
        background-color: pink;
        margin-top: 20px;
      }
      .son {
        width: 100px;
        height: 100px;
        background-color: skyblue;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h3>v-model修饰符 .trim .number</h3>
      姓名:<input v-model.trim="username" type="text" /><br />
      年纪:<input v-model.number="age" type="text" /><br />

      <h3>@事件名.stop → 阻止冒泡</h3>
      <div @click="fatherFn" class="father">
        <div @click.stop="sonFn" class="son">儿子</div>
      </div>

      <h3>@事件名.prevent → 阻止默认行为</h3>
      <a @click.prevent href="http://www.baidu.com">阻止默认行为</a>
    </div>
    <script src="./vue.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          username: "",
          age: "",
        },
        methods: {
          fatherFn() {
            alert("老父亲被点击了");
          },
          sonFn(e) {
            // e.stopPropagation()阻止冒泡
            alert("儿子被点击了");
          },
        },
      });
    </script>
  </body>
</html>

v-bind 对于样式控制的增强 - 操作class

语法 :class = "对象/数组"

  • ① 对象 → 键就是类名,值是布尔值。如果值为 true,有这个类,否则没有这个类
    <div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }"></div>
    适用场景:一个类名,来回切换
  • ② 数组 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
    <div class="box" :class="[ 类名1, 类名2, 类名3 ]"></div>
    适用场景:批量添加或删除类
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        width: 200px;
        height: 200px;
        border: 3px solid #000;
        font-size: 30px;
        margin-top: 10px;
      }
      .pink {
        background-color: pink;
      }
      .big {
        width: 300px;
        height: 300px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="box" v-bind:class="{pink:true,big:true}">哈哈哈</div>
      <div class="box" v-bind:class="cc">哈哈哈</div>
      <div class="box" v-bind:class="['big']">哈哈哈</div>
    </div>

    <script src="./vue.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          cc:{pink:true,big:false}
        },
      });
    </script>
  </body>
</html>
<!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;
      }
      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><a class="active" href="#">京东秒杀</a></li>
      <li><a href="#">每日特价</a></li>
      <li><a href="#">品类秒杀</a></li> -->
        <li v-for="(item, index) in list" :key="item.id" @click="fn(index)">
          <a href="#" :class="{active:index === activeIndex}">{{item.name}}</a>
        </li>
      </ul>

      <ul>
        <!-- <li><a class="active" href="#">京东秒杀</a></li>
      <li><a href="#">每日特价</a></li>
      <li><a href="#">品类秒杀</a></li> -->
        <li v-for="(item, index) in list" :key="item.id" @click="activeIndex=index">
          <a href="#" :class="{active:index === activeIndex}">{{item.name}}</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: "品类秒杀" },
          ],
        },
        methods: {
          fn(index) {
            this.activeIndex = index;
          },
        },
      });
    </script>
  </body>
</html>

v-bind 对于样式控制的增强 - 操作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>
    .box {
      width: 200px;
      height: 200px;
      background-color: rgb(187, 150, 156);
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="box" :style="{width:'100px',height:'100px','background-color':'pink'}"></div>
  </div>
  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>
</html>
<!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:p+'%'}">
        <span>{{p}}%</span>
      </div>
    </div>
    <button @click="p=25">设置25%</button>
    <button @click="p=50">设置50%</button>
    <button @click="p=75">设置75%</button>
    <button @click="p=100">设置100%</button>
  </div>
  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        p:0,
      }
    })
  </script>
</body>
</html>

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

常见的表单元素都可以用 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>Document</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="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username:'',
        isSingle:true,
        gender:'2',
        cityId:'104',
        desc:'textarea'
      },
      computed:{
        
      }
    })
  </script>
</body>
</html>

计算属性

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

  • 声明在 computed 配置项中,一个计算属性对应一个函数
  • 使用起来和普通属性一样使用 {{ 计算属性名 }}

计算属性 → 可以将一段 求值的代码 进行封装

computed: {
    计算属性名 () {
        基于现有数据,编写求值逻辑
        rerurn 结果
    }
},
<!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>
    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>

    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数:{{totalCount}} 个</p>
  </div>
  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 5 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed:{
        totalCount(){
          //基于现有的数据,编写求值逻辑
          //计算属性的函数内部,可以通过 this 访问到 app 实例 
          // list=this.list;
          // let t=0;
          // for(let i=0;i<list.length;i++){
          //   t+=list[i].num;
          // }
          // console.log(this.list.length);
          let total=this.list.reduce((sum,item) => sum + item.num,0)
          return total
        }
      }
    })
  </script>
</body>
</html>

image.png

image.png

<!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>
  </head>
  <body>
    <div id="app">
      姓:<input type="text" v-model="firstName" /><br />
      名:<input type="text" v-model="lastName" /><br />
      <p>姓名:{{fullName}}</p>
      <button @click="changeName">修改姓名</button>
    </div>
    <script src="./vue.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          firstName: "刘",
          lastName: "备",
        },
        computed: {
          // fullName() {
          //   return this.firstName + this.lastName;
          // },

          fullName:{
            get(){
              return this.firstName + this.lastName;
            },
            //当fullNmae 计算属性,被修改赋值时,执行set
            // 修改的值,传递给set方法的形参
            set(value){
              console.log(value);
              this.firstName=value.slice(0,1)
              this.lastName=value.slice(1)
            }
          }
        },
        methods: {
          changeName(){
            this.fullName='吕布'
          }
        },
      });
    </script>
  </body>
</html>

watch 侦听器(监视器)

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

  • 简单写法 → 简单类型数据,直接监视
  • 完整写法 → 添加额外配置项
    (1) deep: true 对复杂类型深度监视
    (2) immediate: true 初始化立刻执行一次handler方法

image.png

image.png

<!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 v-model="obj.lang">
          <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="./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: "小黑",
            lang: "italy",
          },
          result: "",
          // timer:null
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          // 该方法会在数据变化时调用执行
          // words(newValue, oldValue) {
          //   // 防抖: 延迟执行 → 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
          //   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)
          // },
          obj: {
            deep: true,
            immediate:true,
            handler(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: newValue
                });
                this.result = res.data.data;
                console.log(res.data.data);
              }, 300);
            },
          },
        },
      });
    </script>
  </body>
</html>