03-v-on的事件修饰符

前言

本文主要内容:

  • v-model

  • v-for

  • v-if

  • v-show

v-model:双向数据绑定

重点:双向数据绑定,只能用于表单元素,或者用于自定义组件

之前的文章里,我们通过v-bind,给<input>标签绑定了data对象里的name属性。当data里的name的值发生改变时,<input>标签里的内容会自动更新。

可我现在要做的是:我在<input>标签里修改内容,要求data里的name的值自动更新。从而实现双向数据绑定。该怎么做呢?这就可以利用v-model这个属性。

区别

  • v-bind:只能实现数据的单向绑定,从 M 自动绑定到 V。

  • v-model:只有v-model才能实现双向数据绑定。注意,v-model 后面不需要跟冒号,

注意:v-model 只能运用在表单元素中,或者用于自定义组件。常见的表单元素包括:input(radio, text, address, email….) 、select、checkbox 、textarea。

代码举例如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="vue.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <form action="#">
  11. <!-- 将 input 标签中的value值双向绑定到 Vue实例中的data。注意,v-model 后面不需要跟冒号 -->
  12. <input type="text" id="username" v-model="myAccount.username">
  13. <input type="password" id="pwd" v-model="myAccount.userpwd">
  14. <input type="submit" v-on:click="submit1" value="注册">
  15. </form>
  16. </div>
  17. </body>
  18. <script>
  19. var vm = new Vue({
  20. el: '#app',
  21. //上面的标签中采用v-model进行双向数据绑定,数据会自动更新到data里面来
  22. data: {
  23. name: 'qianguyihao',
  24. myAccount: {username: '', userpwd: ''}
  25. },
  26. //在methods里绑定各种方法,根据业务需要进行操作
  27. methods: {
  28. submit1: function () {
  29. alert(this.myAccount.username + " pwd=" + this.myAccount.userpwd);
  30. }
  31. }
  32. });
  33. </script>
  34. </html>

此时,便可实现我们刚刚要求的双向数据绑定的效果。

v-model举例:实现简易计算器

题目:现在两个输入框,用来做加减乘除,将运算的结果放在第三个输入框。

实现代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <script src="vue2.5.16.js"></script>
  9. </head>
  10. <body>
  11. <div id="app">
  12. <input type="text" v-model="n1">
  13. <select v-model="opt">
  14. <option value="+">+</option>
  15. <option value="-">-</option>
  16. <option value="*">*</option>
  17. <option value="/">/</option>
  18. </select>
  19. <input type="text" v-model="n2">
  20. <input type="button" value="=" @click="calc">
  21. <input type="text" v-model="result">
  22. </div>
  23. <script>
  24. // 创建 Vue 实例,得到 ViewModel
  25. var vm = new Vue({
  26. el: '#app',
  27. data: {
  28. n1: 0,
  29. n2: 0,
  30. result: 0,
  31. opt: '+'
  32. },
  33. methods: {
  34. calc() { // 计算器算数的方法
  35. // 逻辑判断:
  36. switch (this.opt) {
  37. case '+':
  38. this.result = parseInt(this.n1) + parseInt(this.n2)
  39. break;
  40. case '-':
  41. this.result = parseInt(this.n1) - parseInt(this.n2)
  42. break;
  43. case '*':
  44. this.result = parseInt(this.n1) * parseInt(this.n2)
  45. break;
  46. case '/':
  47. this.result = parseInt(this.n1) / parseInt(this.n2)
  48. break;
  49. }
  50. //上面的逻辑判断,可能有点啰嗦,我们还可以采取下面的这种方式进行逻辑判断
  51. // 注意:这是投机取巧的方式,正式开发中,尽量少用
  52. // var codeStr = 'parseInt(this.n1) ' + this.opt + ' parseInt(this.n2)'
  53. // this.result = eval(codeStr)
  54. }
  55. }
  56. });
  57. </script>
  58. </body>
  59. </html>

注意上方代码中的注释,可以了解下eval()的用法。

Vue中通过属性绑定为元素设置class 类样式

注意,是类样式

引入

我们先来看下面这段代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <style>
  9. .my-red {
  10. color: red;
  11. }
  12. .my-thin {
  13. /* 设置字体的粗细 */
  14. font-weight: 200;
  15. }
  16. .my-italic {
  17. font-style: italic;
  18. }
  19. .my-active {
  20. /* 设置字符之间的间距 */
  21. letter-spacing: 0.5em;
  22. }
  23. </style>
  24. </head>
  25. <body>
  26. <h1 class="my-red my-thin">我是千古壹号,qianguyihao</h1>
  27. </body>
  28. </html>

上面的代码中,我们直接通过正常的方式,给<h1>标签设置了两个 class 类的样式。代码抽取如下:

  1. <h1 class="my-red my-thin">我是千古壹号,qianguyihao</h1>

上面的效果,我们还可以用Vue来写。这就引入了本段要讲的方式。

方式一:数组

方式一:直接传递一个数组。注意:这里的 class 需要使用 v-bind 做数据绑定。

代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <script src="vue2.5.16.js"></script>
  9. <style>
  10. .my-red {
  11. color: red;
  12. }
  13. .my-thin {
  14. /* 设置字体的粗细 */
  15. font-weight: 200;
  16. }
  17. .my-italic {
  18. font-style: italic;
  19. }
  20. .my-active {
  21. /* 设置字符之间的间距 */
  22. letter-spacing: 0.5em;
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <div id="app">
  28. <!-- 普通写法 -->
  29. <h1 class="my-red my-thin">我是千古壹号,qianguyihao</h1>
  30. <!-- vue的写法1:数组的形式 -->
  31. <h1 :class="['my-red', 'my-thin']">我是qianguyihao,千古壹号</h1>
  32. </div>
  33. <script>
  34. var vm = new Vue({
  35. el: '#app'
  36. });
  37. </script>
  38. </body>
  39. </html>

代码抽取如下:

  1. <!-- vue的写法1:数组的形式 -->
  2. <h1 :class="['my-red', 'my-thin']">我是qianguyihao,千古壹号</h1>

上方代码中,注意,数组里写的是字符串;如果不加单引号,就不是字符串了,而是变量。

演示效果如下:

04-Vue的系统指令(二) - 图1

写法二:在数组中使用三元表达式

  1. <body>
  2. <div id="app">
  3. <!-- vue的写法2:在数组中使用三元表达式。注意格式不要写错-->
  4. <!-- 通过data中布尔值 flag 来判断:如果 flag 为 true,就给 h1 标签添加`my-active`样式;否则,就不设置样式。 -->
  5. <h1 :class="[flag?'my-active':'']">我是qianguyihao,千古壹号</h1>
  6. </div>
  7. <script>
  8. var vm = new Vue({
  9. el: '#app',
  10. data: {
  11. flag:true
  12. }
  13. });
  14. </script>
  15. </body>

上方代码的意思是,通过data中布尔值 flag 来判断:如果 flag 为 true,就给 h1 标签添加my-active样式;否则,就不设置样式。

注意,三元表达式的格式不要写错了。

写法三:在数组中使用 对象 来代替 三元表达式(提高代码的可读性)

上面的写法二,可读性较差。于是有了写法三。

写法三:在数组中使用对象来代替三元表达式

代码如下:

  1. <body>
  2. <div id="app">
  3. <!-- vue的写法3:在数组中使用对象来代替三元表达式。-->
  4. <h1 :class="[ {'my-active':flag} ]">我是qianguyihao,千古壹号</h1>
  5. </div>
  6. <script>
  7. var vm = new Vue({
  8. el: '#app',
  9. data: {
  10. flag: true
  11. }
  12. });
  13. </script>
  14. </body>

写法四:直接使用对象

写法四:直接使用对象。代码如下:

  1. <!-- vue的写法4:直接使用对象-->
  2. <!-- 在为 class 使用 v-bind 绑定 对象的时候,对象的属性是类名。由于 对象的属性名可带引号,也可不带引号,所以 这里我没写引号; 属性的值 是一个标识符 -->
  3. <h1 :class="{style1:true, style2:false}">我是qianguyihao,千古壹号</h1>

上方代码的意思是,给<h1>标签使用样式style1,不使用样式style2。注意:

1、既然class样式名是放在对象中的,这个样式名不能有中划线,比如说,写成:class="{my-red:true, my-active:false},是会报错的。

2、我们也可以对象通过存放在 data 的变量中。也就是说,上方代码可以写成:

  1. <body>
  2. <div id="app">
  3. <!-- vue的写法4:直接使用对象-->
  4. <!-- 在为 class 使用 v-bind 绑定 对象的时候,对象的属性是类名。由于 对象的属性名可带引号,也可不带引号,所以 这里我没写引号; 属性的值 是一个标识符 -->
  5. <h1 :class="classObj">我是qianguyihao,千古壹号</h1>
  6. </div>
  7. <script>
  8. var vm = new Vue({
  9. el: '#app',
  10. data: {
  11. classObj:{style1:true, style2:false}
  12. }
  13. });
  14. </script>
  15. </body>

Vue中通过属性绑定为元素设置 style 行内样式

注意,是行内样式(即内联样式)。

写法一

写法一:直接在元素上通过 :style 的形式,书写样式对象。

例如:

  1. <h1 :style="{color: 'red', 'font-size': '20px'}">我是千古壹号,qianguyihao</h1>

写法二

写法二:将样式对象,定义到 data 中,并直接引用到 :style 中。

也就是说,把写法一的代码改进一下。代码如下:

  1. <body>
  2. <div id="app">
  3. <h1 :style="styleObj">我是千古壹号,qianguyihao</h1>
  4. </div>
  5. <script>
  6. var vm = new Vue({
  7. el: '#app',
  8. data: {
  9. styleObj: { color: 'red', 'font-size': '20px' }
  10. }
  11. });
  12. </script>
  13. </body>

写法三

写法二只用到了一组样式。如果想定义多组样式,可以用写法三。

写法三:在 :style 中通过数组,引用多个 data 上的样式对象。

代码如下:

  1. <body>
  2. <div id="app">
  3. <h1 :style="[ styleObj1, styleObj2 ]">我是千古壹号,qianguyihao</h1>
  4. </div>
  5. <script>
  6. var vm = new Vue({
  7. el: '#app',
  8. data: {
  9. styleObj1: { color: 'red', 'font-size': '20px' },
  10. styleObj2: { 'font-style': 'italic' }
  11. }
  12. });
  13. </script>
  14. </body>

v-for:for循环的四种使用方式

作用:根据数组中的元素遍历指定模板内容生成内容。

引入

比如说,如果我想给一个ul中的多个li分别赋值1、2、3…。如果不用循环,就要挨个赋值:

  1. <body>
  2. <div id="app">
  3. <ul>
  4. <li>{{list[0]}}</li>
  5. <li>{{list[1]}}</li>
  6. <li>{{list[2]}}</li>
  7. </ul>
  8. </div>
  9. </body>
  10. <script>
  11. var vm = new Vue({
  12. el: '#app',
  13. data: {
  14. list: [1, 2, 3]
  15. }
  16. });
  17. </script>

效果:

04-Vue的系统指令(二) - 图2

为了实现上面的效果,如果我用v-for进行赋值,代码就简洁很多了:

  1. <body>
  2. <div id="app">
  3. <ul>
  4. <!-- 使用v-for对多个li进行遍历赋值 -->
  5. <li v-for="item in list">{{item}}</li>
  6. </ul>
  7. </div>
  8. </body>
  9. <script>
  10. var vm = new Vue({
  11. el: '#app',
  12. data: {
  13. list: [1, 2, 3]
  14. }
  15. });
  16. </script>

接下来,我们详细讲一下v-for的用法。需要声明的是,Vue 1.0的写法和Vue 2.0的写法是不一样的。本文全部采用Vue 2.0的写法。

方式一:普通数组的遍历

针对下面这样的数组:

  1. <script>
  2. new Vue({
  3. el: '#app',
  4. data: {
  5. arr1: [2, 5, 3, 1, 1],
  6. }
  7. });
  8. </script>

将数组中的赋给li:

  1. <li v-for="item in arr1">{{item}}</li>

将数组中的值和index赋给li:

  1. <!-- 括号里如果写两个参数:第一个参数代表值,第二个参数代表index 索引 -->
  2. <li v-for="(item,index) in arr1">值:{{item}} --- 索引:{{index}}</li>

效果如下:

04-Vue的系统指令(二) - 图3

方式二:对象数组的遍历

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <script src="vue2.5.16.js"></script>
  9. <style>
  10. </style>
  11. </head>
  12. <body>
  13. <div id="app">
  14. <ul>
  15. <!-- 对象数组的遍历。括号里如果写两个参数:第一个参数代表数组的单个item,第二个参数代表 index 索引-->
  16. <li v-for="(item, index) in dataList">姓名:{{item.name}} --- 年龄:{{item.age}} --- 索引:{{index}}</li>
  17. </ul>
  18. </div>
  19. <script>
  20. var vm = new Vue({
  21. el: '#app',
  22. data: {
  23. //对象数组
  24. dataList: [
  25. { name: 'smyh', age: '26' },
  26. { name: 'vae', age: '32' },
  27. { name: 'xiaoming', age: '20' }
  28. ]
  29. }
  30. });
  31. </script>
  32. </body>
  33. </html>

效果如下:

04-Vue的系统指令(二) - 图4

方式三:对象的遍历

针对下面这样的对象:

  1. <script>
  2. new Vue({
  3. el: '#app',
  4. data: {
  5. obj1: {
  6. name: 'qianguyihao',
  7. age: '26',
  8. gender: '男'
  9. }
  10. }
  11. });
  12. </script>

将上面的obj1对象的数据赋值给li,写法如下:

  1. <body>
  2. <div id="app">
  3. <ul>
  4. <!-- 括号里如果写两个参数:则第一个参数代表value,第二个参数代表key -->
  5. <li v-for="(value,key) in obj1">值:{{value}} --- 键:{{key}} </li>
  6. <h3>---分隔线---</h3>
  7. <!-- 括号里如果写三个参数:则第一个参数代表value,第二个参数代表key,第三个参数代表index -->
  8. <li v-for="(value,key,index) in obj1">值:{{value}} --- 键:{{key}} --- index:{{index}} </li>
  9. </ul>
  10. </div>
  11. </body>

效果如下:

04-Vue的系统指令(二) - 图5

方式四:遍历数字

in后面还可以直接放数字。举例如下:

  1. <ul>
  2. <!-- 对象数组的遍历 -->
  3. <!-- 注意:如果使用 v-for 遍历数字的话,前面的 myCount 值从 1 开始算起 -->
  4. <li v-for="myCount in 10">这是第 {{myCount}}次循环</li>
  5. </ul>

效果如下:

04-Vue的系统指令(二) - 图6

v-for中key的使用注意事项

注意:在 Vue 2.2.0+ 版本里,当在组件中使用 v-for 时,key 属性是必须要加上的。

这样做是因为:每次 for 循环的时候,通过指定 key 来标示当前循环这一项的唯一身份

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

key的类型只能是:string/number,而且要通过 v-bind 来指定。

代码举例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <script src="vue2.5.16.js"></script>
  9. </head>
  10. <body>
  11. <div id="app">
  12. <div>
  13. <label>Id:
  14. <input type="text" v-model="id">
  15. </label>
  16. <label>Name:
  17. <input type="text" v-model="name">
  18. </label>
  19. <input type="button" value="添加" @click="add">
  20. </div>
  21. <!-- 注意: v-for 循环的时候,key 属性只能使用 number 或者 string -->
  22. <!-- 注意: key 在使用的时候,必须使用 v-bind 属性绑定的形式,指定 key 的值 -->
  23. <!-- 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果 v-for 有问题,必须 在使用 v-for 的同时,指定 唯一的 字符串/数字 类型 :key 值 -->
  24. <p v-for="item in list" :key="item.id">
  25. <input type="checkbox">{{item.id}} --- {{item.name}}
  26. </p>
  27. </div>
  28. <script>
  29. // 创建 Vue 实例,得到 ViewModel
  30. var vm = new Vue({
  31. el: '#app',
  32. data: {
  33. id: '',
  34. name: '',
  35. list: [
  36. { id: 1, name: 'smyh' },
  37. { id: 2, name: 'vae' },
  38. { id: 3, name: 'qianguyihao' },
  39. { id: 4, name: 'xiaoming' },
  40. { id: 5, name: 'xiaohong' }
  41. ]
  42. },
  43. methods: {
  44. add() { // 添加方法
  45. this.list.unshift({ id: this.id, name: this.name })
  46. }
  47. }
  48. });
  49. </script>
  50. </body>
  51. </html>

v-if:设置元素的显示和隐藏(添加/删除DOM元素)

作用:根据表达式的值的真假条件,来决定是否渲染元素,如果为false则不渲染(达到隐藏元素的目的),如果为true则渲染。

在切换时,元素和它的数据绑定会被销毁并重建。

举例如下:(点击按钮时,切换和隐藏盒子)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="vue.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <button v-on:click="toggle">显示/隐藏</button>
  11. <div v-if="isShow">我是盒子</div>
  12. </div>
  13. </body>
  14. <script>
  15. new Vue({
  16. el: '#app',
  17. data: {
  18. isShow: true
  19. },
  20. methods: {
  21. toggle: function() {
  22. this.isShow = !this.isShow;
  23. }
  24. }
  25. });
  26. </script>
  27. </html>

效果如下:

04-Vue的系统指令(二) - 图7

v-show:设置元素的显示和隐藏(在元素上添加/移除style="display:none"属性)

作用:根据表达式的真假条件,来切换元素的 display 属性。如果为false,则在元素上添加 display:none属性;否则移除display:none属性。

举例如下:(点击按钮时,切换和隐藏盒子)

我们直接把上一段代码中的v-if改成v-show就可以了:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="vue.js"></script>
  7. </head>
  8. <body>
  9. <div id="app">
  10. <button v-on:click="toggle">显示/隐藏</button>
  11. <div v-show="isShow">我是盒子</div>
  12. </div>
  13. </body>
  14. <script>
  15. new Vue({
  16. el: '#app',
  17. data: {
  18. isShow: true
  19. },
  20. methods: {
  21. toggle: function() {
  22. this.isShow = !this.isShow;
  23. }
  24. }
  25. });
  26. </script>
  27. </html>

效果如下:

04-Vue的系统指令(二) - 图8

v-if和v-show的区别

v-ifv-show都能够实现对一个元素的隐藏和显示操作。

区别:

  • v-if:每次都会重新添加/删除DOM元素

  • v-show:每次不会重新进行DOM的添加/删除操作,只是在这个元素上添加/移除style="display:none"属性,表示节点的显示和隐藏。

优缺点:

  • v-if:有较高的切换性能消耗。这个很好理解,毕竟每次都要进行dom的添加/删除操作。

  • v-show:有较高的初始渲染消耗。也就是说,即使一开始v-show="false",该节点也会被创建,只是隐藏起来了。而v-if="false"的节点,根本就不会被创建。

总结

  • 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show

  • 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if