Vue指令

158 阅读5分钟

vue指令:实质上就是特殊的html标签属性。

特点:v - 开头

一、插值表达式

作用:在dom标签中,直接插入内容

另一种叫法:声明式渲染/文本插值

语法:{{ 表达式 }}

<template>
  <div>
    <h1>{{ msg }}</h1>
    <h2>{{ obj.name }}</h2>
    <h3>{{ obj.age > 18 ? '成年' : '未成年' }}</h3>
  </div>
</template>

<script>
export default {
  data() { // 格式固定, 定义vue数据之处
    return {  // key相当于变量名
      msg: "hello, vue",
      obj: {
        name: "小vue",
        age: 5
      }
    }
  }
}
</script>

<style>
</style>

二、v-bind指令

作用:给标签属性绑定vue数据变量的值,可通过改变变量值来修改标签属性值

语法:v-bind:属性名="vue变量名"

简写::属性名="vue变量名"

<!-- vue指令-v-bind属性动态赋值 -->
<a v-bind:href="url">我是a标签</a>
<img :src="imgSrc">

三、v-on指令

作用:给标签绑定事件

语法:

  • v-on:事件名 = "要执行的(少量的)js代码"
  • v-on:事件名 = "methods 中的函数方法"
  • v-on:事件名 = "methods 中的函数(实参)"

简写: @事件名 = "methods 中的函数名"

<!-- vue指令:   v-on事件绑定-->
<p>你要买商品的数量: {{count}}</p>
<button v-on:click="count = count + 1">增加1</button>
<button v-on:click="addFn">增加1个</button>
<button v-on:click="addCountFn(5)">一次加5件</button>

<button @click="subFn">减少</button>

<script>
    export default {
        // ...其他省略
        methods: {
            addFn(){ 
                // this代表export default后面的组件对象(下属有data里return出来的属性)
                this.count++
            },
            addCountFn(num){
                this.count += num
            },
            subFn(){
                this.count--
            }
        }
    }
</script>

1、v-on事件对象

作用:使vue事件处理函数可以拿到事件对象

语法:

  • 无传参,通过形参直接接收
  • 传参,通过$event 指代事件对象传给事件处理函数
<template>
  <div>
    <a @click="one" href="http://www.baidu.com">阻止百度</a>
    <hr>
    <a @click="two(10, $event)" href="http://www.baidu.com">阻止去百度</a>
  </div>
</template>

<script>
export default {
  methods: {
    one(e){
      e.preventDefault()
    },
    two(num, e){
      e.preventDefault()
    }
  }
}
</script>

2、v-on修饰符

作用:在事件后面 .修饰符名 (给事件带来更强大的功能)

语法:@事件名.修饰符 = "methods里函数"

  • .stop:阻止事件冒泡
  • .prevent:阻止默认行为
  • .once:程序运行期间,只触发一次事件处理函数
<template>
  <div @click="fatherFn">
    <!-- vue对事件进行了修饰符设置, 在事件后面.修饰符名即可使用更多的功能 -->
    <button @click.stop="btn">.stop阻止事件冒泡</button>
    <a href="http://www.baidu.com" @click.prevent="btn">.prevent阻止默认行为</a>
    <button @click.once="btn">.once程序运行期间, 只触发一次事件处理函数</button>
  </div>
</template>

<script>
export default {
  methods: {
    fatherFn(){
      console.log("father被触发");
    },
    btn(){
      console.log(1);
    }
  }
}
</script>

v-on按键修饰符

作用:给键盘事件添加修饰符,增强事件能力

键盘事件的三种形式:

  • keyup:按键按下后松开时触发的事件
  • keydown:按键按下时触发的事件
  • keypress:按键长按时触发的事件

按键修饰符语法:

  • @keyup.enter:监测回车按键
  • @keyup.esc:监测返回按键
<template>
  <div>
    <input type="text" @keydown.enter="enterFn">
    <hr>
    <input type="text" @keydown.esc="escFn">
  </div>
</template>

<script>
export default {
 methods: {
   enterFn(){
     console.log("enter回车按键了");
   },
   escFn(){
     console.log("esc按键了");
   }
 }
}
</script>

四、v-model指令

作用:主要用来将vue数据和表单value值进行数据双向绑定

语法:v-model = "vue数据变量名"

双向数据绑定:

  • 数据变化 ==> 视图自动同步
  • 视图变化 ==> 数据自动同步
<template>
  <div>
    <!-- 
    	v-model:是实现vuejs变量和表单标签value属性, 双向绑定的指令
    -->
    <div>
      <span>用户名:</span>
      <input type="text" v-model="username" />
    </div>
    <div>
      <span>密码:</span>
      <input type="password" v-model="pass" />
    </div>
    <div>
      <span>来自于: </span>
      <!-- 下拉菜单要绑定在select上 -->
      <select v-model="from">
        <option value="北京市">北京</option>
        <option value="南京市">南京</option>
        <option value="天津市">天津</option>
      </select>
    </div>
    <div>
      <!-- (重要)
      遇到复选框, v-model的变量值
      非数组 - 关联的是复选框的checked属性
      数组   - 关联的是复选框的value属性
       -->
      <span>爱好: </span>
      <input type="checkbox" v-model="hobby" value="抽烟">抽烟
      <input type="checkbox" v-model="hobby" value="喝酒">喝酒
      <input type="checkbox" v-model="hobby" value="写代码">写代码
    </div>
    <div>
      <span>性别: </span>
      <input type="radio" value="男" name="sex" v-model="gender"><input type="radio" value="女" name="sex" v-model="gender"></div>
    <div>
      <span>自我介绍</span>
      <textarea v-model="intro"></textarea>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
      pass: "",
      from: "",
      hobby: [], 
      sex: "",
      intro: "",
    };
    // 总结:
    // 特别注意: v-model, 在input[checkbox]的多选框状态
    // 变量为非数组, 则绑定的是checked的属性(true/false) - 常用于: 单个绑定使用
    // 变量为数组, 则绑定的是他们的value属性里的值 - 常用于: 收集勾选了哪些值
  }
};
</script>

1、v-model修饰符

语法:v-model.修饰符 = "vue数据变量名"

  • .number:将表单value值以parseFloat转成浮点数字类型
  • .trim:去除首尾空白字符
  • .lazy:在change时触发,而非input时
<template>
  <div>
    <div>
      <span>年龄:</span>
      <input type="text" v-model.number="age">
    </div>
    <div>
      <span>人生格言:</span>
      <input type="text" v-model.trim="motto">
    </div>
    <div>
      <span>自我介绍:</span>
      <textarea v-model.lazy="intro"></textarea>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      age: "",
      motto: "",
      intro: ""
    }
  }
}
</script>

六、v-text和v-html指令

作用:相当于DOM对象的innerTextinnerHTML作用

语法:

  • v-text = "vue数据变量名"
  • v-html = "vue数据变量名"
  • 注意:会覆盖插值表达式
<template>
  <div>
    <p v-text="str"></p>
    <p v-html="str"></p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      str: "<span>我是一个span标签</span>"
    }
  }
}
</script>

七、v-show和v-if指令

作用:控制标签的隐藏或出现

语法:

  • v-show = "vue变量"
  • v-if = "vue变量"

原理:

  • v-show:用的display:none/blokc控制DOM元素的显示隐藏
  • v-if:直接从DOM树上移除该元素(使用该方式频繁切换显示隐藏比较消耗性能)

v-if还可以配合v-else一起使用

<template>
  <div>
    <h1 v-show="isOk">v-show的盒子</h1>
    <h1 v-if="isOk">v-if的盒子</h1>

    <div>
      <p v-if="age > 18">我成年了</p>
      <p v-else>还得多吃饭</p>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isOk: true,
      age: 15
    }
  }
}
</script>

八、v-for指令

作用:在vue html模板上遍历数据 渲染 列表结构

语法:

  • v-for = "(值, 索引) in 数据变量名"
  • v-for = "值 in 数据变量名"

可以遍历数组 / 对象 / 数字/ 字符串(可遍历结构)

注意:v-for的零时变量名不能用到v-for范围外,使用时需配合 :key=""来使用

<template>
  <div id="app">
    <div id="app">
      <!-- v-for 把一组数据, 渲染成一组DOM -->
      <!-- 口诀: 让谁循环生成, v-for就写谁身上 -->
      <p>学生姓名</p>
      <ul>
        <li v-for="(item, index) in arr" :key="item">
          {{ index }} - {{ item }}
        </li>
      </ul>

      <p>学生详细信息</p>
      <ul>
        <li v-for="obj in stuArr" :key="obj.id">
          <span>{{ obj.name }}</span>
          <span>{{ obj.sex }}</span>
          <span>{{ obj.hobby }}</span>
        </li>
      </ul>

      <!-- v-for遍历对象(了解) -->
      <p>老师信息</p>
      <div v-for="(value, key) in tObj" :key="value">
        {{ key }} -- {{ value }}
      </div>

      <!-- v-for遍历整数(了解) - 从1开始 -->
      <p>序号</p>
      <div v-for="i in count" :key="i">{{ i }}</div>
    </div>
  </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>

1、v-for更新监测

概念:当v-for遍历的目标结构改变,Vue触发v-for的更新

口诀:

  1. 数组的变更方法,就会导致v-for更新,页面更新
  2. 数组非变更方法,返回新数组,就不会导致v-for更新,可采用覆盖数组或this.$set()

以下这些方法会触发数组改变,v-for会监测到并更新页面

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

这些方法不会触发v-for更新

  • slice()
  • filter()
  • concat()

注意:vue不能监测到数组赋值的动作而更新,如果需要请使用Vue.set() 或者 this.$set() ,或者覆盖整个数组

总结:改变原数组的方法才能让v-for更新

<template>
  <div>
    <ul>
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="revBtn">数组翻转</button>
    <button @click="sliceBtn">截取前3个</button>
    <button @click="updateBtn">更新第一个元素值</button>
  </div>
</template>

<script>
export default {
  data(){
    return {
      arr: [5, 3, 9, 2, 1]
    }
  },
  methods: {
    revBtn(){
      // 1. 数组翻转可以让v-for更新
      this.arr.reverse()
    },
    sliceBtn(){
      // 2. 数组slice方法不会造成v-for更新
      // slice不会改变原始数组
      // this.arr.slice(0, 3)

      // 解决v-for更新 - 覆盖原始数组
      let newArr = this.arr.slice(0, 3)
      this.arr = newArr
    },
    updateBtn(){
      // 3. 更新某个值的时候, v-for是监测不到的
      // this.arr[0] = 1000;

      // 解决-this.$set()
      // 参数1: 更新目标结构
      // 参数2: 更新位置
      // 参数3: 更新值
      this.$set(this.arr, 0, 1000)
    }
  }
}
</script>

<style>

</style>

2、v-for就地更新

v-for 的默认行为会尝试原地修改元素而不是移动它们。

这种 虚拟DOM对比方式,可以提高性能,但是还不够(对比Vue虚拟DOM,diff算法)

3、v-for之key的作用

key是唯一标识符

只能是唯一不重复的,字符串或数值

无key - 就地更新

v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key 来提供一个排序提示

有key - 值为索引

  1. v-for先循环产生新的DOM结构, key是连续的, 和数据对应
  2. 然后比较新旧DOM结构, 找到区别, 打补丁到页面上最后补一个li, 然后从第二个往后, 都要更新内容

口诀: key的值有id用id, 没id用索引

有key - 值为id或唯一标识符

key的值只能是唯一不重复的, 字符串或数值

v-for不会移动DOM, 而是尝试复用, 就地更新,如果需要v-for移动DOM, 你需要用特殊 attribute key 来提供一个排序提示

新DOM里数据的key存在, 去旧的虚拟DOM结构里找到key标记的标签, 复用标签

新DOM里数据的key存在, 去旧的虚拟DOM结构里没有找到key标签的标签, 创建

旧DOM结构的key, 在新的DOM结构里没有了, 则移除key所在的标签。

总结: 不用key也不影响功能(就地更新), 添加key可以提高更新的性能

4、v-for总结

v-for什么时候会更新页面呢?

  • 数组采用更新方法, 才导致v-for更新页面

vue是如何提高更新性能的?

  • 采用虚拟DOM+key提高更新性能

虚拟DOM是什么?

  • 本质是保存dom关键信息的JS对象

如何比较新旧虚拟DOM?

  • 根元素改变 – 删除当前DOM树重新建
  • 根元素未变, 属性改变 – 更新属性
  • 根元素未变, 子元素/内容改变
  • 无key – 就地更新 / 有key – 按key比较