五、 计算属性和侦听器
5.1 计算属性
data 中的属性可以通过声明获得,也可以通过在 computed 计算属性的 getter 获得
特性:计算属性所依赖的属性值发生变化会影响计算属性的值同时发生变化
示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app-9"> <input type="text" v-model="message1"><br /> <input type="text" v-model="message2"><br /> {{message3}} </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-9', data: { message1: 'Hello', message2: 'World' }, computed: { message3: function () { return this.message1 + this.message2; } } }) </script> </body> </html>
5.2 侦听器
侦听器,就是 data 中属性的侦听器,当 data 中的属性值发生变化就会触发侦听器函数的执行
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app-10"> <input type="text" v-model="message1"><br /> <input type="text" v-model="message2"><br /> {{message3}} </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-10', data: { message1: 'Hello', message2: 'World', message3: 'Hello World' }, watch: { message1: function () { this.message3 = this.message1 + this.message2; }, message2: function () { this.message3 = this.message1 + this.message2; } } }) </script> </body> </html>
六、class 与 style 绑定
6.1 class 绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .my-style1 { width: 200px; height: 100px; background: orange; } .my-style2 { border-radius: 10px; } .my-style3 { width: 200px; height: 100px; background: black; } </style> <script src="js/vue.js"></script> </head> <body> <div id="app-11"> <!-- 如果 message1 为 true, 就加载 my-style1,如果 message2 为 true, 就加载 my-style2 --> <div :class="{'my-style1': message1, 'my-style2' : message2}"> </div><hr /> <!-- 为 class 属性加载多个样式名 --> <div :class="[booleanValue1, booleanValue2]"> </div><hr /> <!-- 如果 message3 为 true, 则 class = 'my-style3',否则 class = 'my-style1' 如果在三目运算中使用样式名则需要加单引号,不加单引号则表示从 data 变量中获取样式名 --> <div :class="[message3 ? 'my-style3' : 'my-style1']"> </div> <div :class="[message1 ? booleanValue1 : booleanValue3]"></div> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-11', data: { message1: true, message2: true, message3: true, booleanValue1: "my-style1", booleanValue2: "my-style2", booleanValue3: "my-style3" } }) </script> </body> </html>
6.2 style 绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app-12"> <!-- 当使用 v-bind 绑定内联样式时: 1. 使用 {} 定义 style 样式,才能获取 data 的值, {} 要遵循 JSON 格式 2. {} 中不在使用 style 样式属性名 “font-size”, 而要使用对应的 js 属性名 border-style-width --- borderStyleWidth --> <div v-bind:style="{color: colorName, fontSize: fontsize + 'px' }"> Hello World! </div> <!-- 我们可以直接为 style 属性绑定一个 data 中定义好的内联样式的字符串 --> <div v-bind:style="myStyle1"> Hello World!! </div> <!-- 我们可以直接为 style 属性绑定一个 data 中定义好的内联样式的对象 --> <div v-bind:style="myStyle2"> Hello World!!! </div> <!-- 我们可以在同一个 style 属性通过数组引用多个内联样式的对象 --> <div v-bind:style="[myStyle2, myStyle3]"> Hello World!!!! </div> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-12', data: { colorName: "yellow", fontsize: "40", myStyle1: "color: orange; font-size: 50px", myStyle2: { color: "blue", fontSize: "60px" }, myStyle3: { textShadow: "orange 3px 3px 5px" } } }) </script> </body> </html>
七、条件与列表渲染
7.1 条件渲染
条件判断语句:
v-if
v-else-if
v-else
7.1.1 v-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/vue.js"></script> </head> <body> <div id="app-13"> <h3 v-if="code == 1">Hello :可以看到</h3> <h3 v-if="flag">flag 为 true, 可以看到</h3> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-13', data: { code: 1, flag: false } }) </script> </body> </html>
7.1.2 v-else
v-else
指令来表示v-if
的“else 块”
<div id="app-13"> <!-- v-else 标签需要紧跟在 v-if 的标签之后,中间不能有其他标签, 否则它将不会被识别 --> <h3 v-if="code == 1">Hello :可以看到</h3> <h3 v-else>World :可以看到</h3> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-13', data: { code: 1 } }) </script>
7.1.3 v-else-if
<div id="app-13"> 分数 {{code}} 对应的等级: <h3 v-if="code >= 90">优秀</h3> <h3 v-else-if="code >= 80">良好</h3> <h3 v-else-if="code >= 70">中等</h3> <h3 v-else-if="code >= 60">及格</h3> <h3 v-else>挂科</h3> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-13', data: { code: 85 } }) </script>
7.1.4 v-show
v-show
:同样用于根据条件展示元素。从功能上 v-show 与 v-if 作用是相同的,只是渲染过程有区别。
v-if 与 v-show 的区别:
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。- 相比之下,
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
- 一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
7.2 列表渲染
编码过程中,发现网页出现报错:
Uncaught Error: Bootstrap's JavaScript requires jQuery at bootstrap.min.js:6
解决方法:在引进JQuery文件时,将其放在 bootstrap 前面即可。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script> <script src="js/vue.js"></script> </head> <body> <div id="app-14"> <ul> <li v-for="c in categories"> <a :href="'query?cid=' + c.cid">{{c.cname}}</a> </li> </ul> <table class="table table-bordered"> <tr> <th>学号</th> <th>照片</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>操作</th> </tr> <template v-for="(s, index) in stu"> <tr :id="'tr' + s.stuNum"> <td>{{s.stuNum}}</td> <td> <img height="30" :src="s.stuImg" /> </td> <td>{{s.stuName}}</td> <td> <!-- {{s.stuGender == 'M' ? '男' : '女'}} --> <img v-if="s.stuGender == 'M'" src="img/m.bmp"> <img v-else src="img/f.bmp"> </td> <td>{{s.stuAge}}</td> <td> <a class="btn btn-danger" :href="'stu/delete?cid=' + s.stuNum">删除</a> <a class="btn btn-success" :href="'stu/update?cid=' + s.stuNum">修改</a> </td> </tr> </template> </table> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-14', data: { categories:[ { cid: 1, cname: "华为" }, { cid: 2, cname: "小米" }, { cid: 3, cname: "OPPO" }, { cid: 4, cname: "VIVO" } ], stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 }, { stuNum: "10011", stuImg: "img/2.jpg", stuName: "Joker", stuGender: "M", stuAge: 21 }, { stuNum: "10012", stuImg: "img/3.jpg", stuName: "Ling", stuGender: "F", stuAge: 20 }, { stuNum: "10013", stuImg: "img/1.jpg", stuName: "Jack", stuGender: "F", stuAge: 18 }, ] } }) </script> </body> </html>
八、事件处理
- 在使用 vue 进行数据渲染时,如果使用原生 js 事件绑定 (例如 onclick),如果需要获取 vue 实例中的数据并传参则需要通过拼接来完成
- vue 提供了 v-on 指令用于绑定各种事件 (v-on:click),简化了从 vue 取值的过程,但是触发的方法需要定义在 vue 实例的 methods 中
<button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button> <script type="text/javascript"> var vm = new Vue({ el: '#app-15', data: { stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 } ] }, methods: { doDelete: function (sNum, sName) { alert("---delete:" + sNum + " " + sName) } } }) </script>
v-on:click
可以简写为@click
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script> <script src="js/vue.js"></script> </head> <body> <div id="app-15"> <ul> <li v-for="c in categories"> <a :href="'query?cid=' + c.cid">{{c.cname}}</a> </li> </ul> <table class="table table-bordered"> <tr> <th>学号</th> <th>照片</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>操作</th> </tr> <template v-for="(s, index) in stu"> <tr :id="'tr' + s.stuNum"> <td>{{s.stuNum}}</td> <td> <img height="30" :src="s.stuImg" /> </td> <td>{{s.stuName}}</td> <td> <!-- {{s.stuGender == 'M' ? '男' : '女'}} --> <img v-if="s.stuGender == 'M'" src="img/m.bmp"> <img v-else src="img/f.bmp"> </td> <td>{{s.stuAge}}</td> <td> <button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button> <button class="btn btn-success" @click="doUpdate" :data-snum="s.stuNum" :data-sname="s.stuName" :data-simg="s.stuImg">修改</button> </td> </tr> </template> </table> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-15', data: { categories:[ { cid: 1, cname: "华为" }, { cid: 2, cname: "小米" }, { cid: 3, cname: "OPPO" }, { cid: 4, cname: "VIVO" } ], stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 }, { stuNum: "10011", stuImg: "img/2.jpg", stuName: "Joker", stuGender: "M", stuAge: 21 }, { stuNum: "10012", stuImg: "img/3.jpg", stuName: "Ling", stuGender: "F", stuAge: 20 }, { stuNum: "10013", stuImg: "img/1.jpg", stuName: "Jack", stuGender: "F", stuAge: 18 }, ] }, methods: { doDelete: function (sNum, sName) { alert("---delete:" + sNum + " " + sName) }, doUpdate: function (event) { // 如果 v-on 绑定的 js 函数没有参数,调用的时候可以省略 (), 同时可以给 js 函数一个 event 参数(事件对象) // 1. event 表示触发当前函数的事件 // 2. event.srcElement 表示发生事件的元素 --- 修改按钮 // 3. event.srcElement.dataset 表示按钮上绑定的数据集 (data-开头的属性) alert("---update:"); let stu = event.srcElement.dataset; } } }) </script> </body> </html>
8.1 使用 JS 函数传值
<button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button> <script type="text/javascript"> var vm = new Vue({ el: '#app-15', data: { stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 } ] }, methods: { doDelete: function (sNum, sName) { alert("---delete:" + sNum + " " + sName) } } }) </script>
8.2 使用 dataset 对象传值 (推荐)
<button class="btn btn-success" @click="doUpdate" :data-snum="s.stuNum" :data-sname="s.stuName" :data-simg="s.stuImg">修改</button> <script type="text/javascript"> var vm = new Vue({ el: '#app-15', data: { stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 } ] }, methods: { doUpdate: function (event) { // 如果 v-on 绑定的 js 函数没有参数,调用的时候可以省略 (), 同时可以给 js 函数一个 event 参数(事件对象) // 1. event 表示触发当前函数的事件 // 2. event.srcElement 表示发生事件的元素 --- 修改按钮 // 3. event.srcElement.dataset 表示按钮上绑定的数据集 (data-开头的属性) alert("---update:"); let stu = event.srcElement.dataset; } } }) </script>
8.3 混合使用
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法
<button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName, $event)" :data-simg="s.stuImg">删除</button> <script type="text/javascript"> var vm = new Vue({ el: '#app-15', data: { stu: [ { stuNum: "10010", stuImg: "img/1.jpg", stuName: "Tom", stuGender: "M", stuAge: 20 } ] }, methods: { doDelete: function (sNum, sName, event) { alert("---delete:" + sNum + " " + sName) console.log(event.srcElement.dataset) } } }) </script>
8.4 事件修饰符
修饰符是由点开头的指令后缀来表示的。
当使用 v-on 进行事件绑定的时候,可以添加特定后缀,设置事件触发的特性
8.4.1 事件修饰符使用示例
<button type="submit" class="btn btn-success" @click.prevent="test">修改</button>
8.4.2 事件修饰符
常用的事件修饰符:
.stop
.prevent
.capture
.self
.once
.passive
.prevent 用来阻止标签的默认行为
<div id="app-16"> <form action="https://www.baidu.com"> <!-- 此处不加 .prevent ,网页会跳转到 https://www.baidu.com --> <button type="submit" class="btn btn-success" @click.prevent="test">修改</button> </form> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-16', data: {}, methods: { test: function (event) { alert("--test"); } } }) </script>
.stop 阻止事件冒泡
.self 设置只能自己触发事件(子标签不能触发)
<div id="app-16"> <!-- .prevent 示例 --> <form action="https://www.baidu.com"> <!-- 此处不加 .prevent ,网页会跳转到 https://www.baidu.com --> <button type="submit" class="btn btn-success" @click层="test">修改</button> </form> <!-- .stop 示例 .self 示例:只能点击自己触发 --> <div style="width: 200px; height: 200px; background: red;" @click.self="outside"> <div style="width: 100px; height: 100px; background: yellow;" @click="inside"> <!-- 此处加了 .stop , 网页的外层 div 父标签不会触发 --> <button @click.stop="itself">test stop 修饰符</button> </div> </div> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-16', data: {}, methods: { test: function (event) { alert("--test"); }, inside: function () { alert("--inside"); }, outside: function () { alert("--outside"); }, itself: function () { alert("--itself"); } } }) </script>
.once 限定事件只能触发一次
<!-- .once 示例:test()方法只执行一次, --> <form action="https://www.baidu.com"> <!-- 加了 .prevent,第一次点击执行 test(),默认跳转被阻止, 第二次点击按钮,直接跳转, test()不执行 --> <button type="submit" class="btn btn-success" @click.prevent.once="test">修改</button> </form>
8.5 按键修饰符
按键修饰符:针对键盘事件的修饰符,限定哪个按键会触发事件
常用的按键修饰符:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
.enter 只有在 key
是 Enter
时调用(触发 enter
按键之后触发事件)
<div id="app-17"> <input type="text" @keyup.enter="test"> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-17', data: {}, methods: { test: function () { alert("enter松开触发") } } }) </script>
还可以通过全局 config.keyCodes
对象自定义按键修饰符别名:
// 输入 按键 j 触发事件 test <input type="text" @keyup.aaa="test"> // 按键 j 的别名 Vue.config.keyCodes.aaa = 74
8.6 系统修饰符
组合键
示例:CTRL + J 触发事件
<div id="app-17"> <input type="text" @keyup.ctrl.j="test"> </div> <script type="text/javascript"> Vue.config.keyCodes.j = 74 var vm = new Vue({ el: '#app-17', data: {}, methods: { test: function () { alert("enter松开触发") } } }) </script>
常用的修饰符:
.ctrl
.alt
.shift
.meta
windows 键
九、表单输入绑定
表单输入绑定,即双向绑定:就是能够将 vue 实例的 data 数据渲染到表单输入视图 (input extareaselect),
也能够将输入视图的数据同步到 vue 实例的 data中。
<div id="app-18"> <!-- 文本输入框 密码输入框 --> <input type="text" v-model="name" /><br /> <input type="password" v-model="password" /> <hr /> <!-- 单选按钮 --> <input type="radio" v-model="radioTest" value="A" /> A <input type="radio" v-model="radioTest" value="B" /> B <input type="radio" v-model="radioTest" value="C" /> C <input type="radio" v-model="radioTest" value="D" /> D <hr /> <!-- 复选框,绑定的是一个数组 --> <input type="checkbox" v-model="checkBox" value="篮球" /> 篮球 <br /> <input type="checkbox" v-model="checkBox" value="足球" /> 足球 <br /> <input type="checkbox" v-model="checkBox" value="羽毛球" /> 羽毛球 <br /> <input type="checkbox" v-model="checkBox" value="乒乓球" /> 乒乓球 <br /> <!-- 下拉菜单 select:绑定一个字符串 --> <select v-model="city"> <option value="BJ">北京</option> <option value="SH">上海</option> <option value="SZ">深圳</option> <option value="GZ">广州</option> </select> <hr /> <!-- 下拉菜单 select:加上了 multiple ,表示可多选,需要绑定一个数组 --> <select v-model="cities" multiple> <option value="BJ">北京</option> <option value="SH">上海</option> <option value="SZ">深圳</option> <option value="GZ">广州</option> </select> <button type="button" @click="test">测试</button> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app-18', data: { name: "admin", password: "123456", radioTest: "C", checkBox: [], city: "", cities: [] }, methods: { test: function () { alert(vm.cities) } } }) </script>