文章目录
前言 ♥️
计算属性 computed 🥤
计算属性和methods对比 🍵
v-on的语法糖 🌿
v-on参数传递 💬
v-on的事件修饰符 ✨
v-if和v-else if和v-else使用 🤪
登录切换小案例 ⛹️♂️
v-show与v-if是情侣关系吗 🤪
v-for遍历数组和对象 ♻️
v-for 绑定 key 🧃
数组中哪些方法是响应式的?⚙️
购物车案例 🍓
过滤器 🍂
增强for (for in) 🥣
增强 for (for of) 💊
v-model的使用和原理 🌍
v-model结合radio🥳
v-model结合checkbox🥳
v-model结合select🥳
v-model修饰符 🎨
最后 💧
前言 ♥️
大家好,大家好,我又来了,这次还是基础部分的知识,快来学习吧,下一篇将学习Vue组件化的使用以及组件通信,插槽等知识,原创不易,如果觉得写的不错,可以点赞评论支持一下 🥳
计算属性 computed 🥤
简单上手
假如要实现两个变量的计算,目前可以使用拼接,使用 methods 方法来实现,现在将引入一个新的 option ,计算属性,computed,你可能会疑问,有什么不一样吗?不着急,慢慢来,你会理解的 🤪
<body> <div id="app"> <h2>使用拼接 {{firstName + " " + lastName}}</h2> <h2>使用方法 {{getFullName()}}</h2> <h2>计算属性 {{fullName}}</h2> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { firstName: 'liu', lastName: 'xiao sen', }, methods: { getFullName() { return this.firstName + " " + this.lastName; } }, computed: { fullName: function () { return this.firstName + " " + this.lastName; } } }) </script> </body>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="app"> <h2>计算属性 {{fullName}}</h2> </div> <script src="./vue.js"></script> <script> var app = new Vue({ el: '#app', data: { firstName: 'liu', lastName: 'xiao sen', }, computed: { // 只用get方法时,可以简写 /*fullName: function () { return this.firstName + " " + this.lastName; } */ // 完成写法是对象,我们通过 fullName 访问,会直接调用 get 方法,所以写成 fullName fullName: { set: function (newVal) { console.log(newVal); const names = newVal.split(' '); this.firstName = names[0]; this.lastName = names[1]; }, get: function () { return this.firstName + ' ' + this.lastName; } } } }) </script> </body> </html>
计算属性和methods对比 🍵
计算属性的优势就是它是使用缓存机制了的,如果多次使用,计算属性只执行一次
下面是对比的代码,一目了然
<body> <div id="app"> <h3>{{getFullName()}}</h3> <h3>{{getFullName()}}</h3> <h3>{{getFullName()}}</h3> <h3>{{getFullName()}}</h3> <hr /> <h3>{{fullName}}</h3> <h3>{{fullName}}</h3> <h3>{{fullName}}</h3> <h3>{{fullName}}</h3> </div> <script src="./vue.js"></script> <script> var app = new Vue({ el: '#app', data: { firstName: 'liu', lastName: 'xiao sen', }, methods: { getFullName() { console.log("method执行了"); return this.firstName + ' ' + this.lastName; } }, computed: { fullName() { console.log("计算属性执行了"); return this.firstName + ' ' + this.lastName; } } }) </script> </body>
结果
v-on的语法糖 🌿
因为 v-on 使用较多,因此添加了语法糖,语法糖就是简写
普通写法
<body> <div id="app"> <button v-on:click="count ++">{{count}}</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", data: { count: 0, }, }); </script> </body>
使用了语法糖,使用@代替重复的 v-on:
<body> <div id="app"> <button @click="count ++">{{count}}</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", data: { count: 0, }, }); </script> </body>
v-on参数传递 💬
◼️ 1. 无参数,不传
◼️ 2. 有一个参数或多个参数,但不包含时间对象参数时,加括号,参数按照顺序写
◼️ 3. 当不仅要传普通参数,还要传递事件参数时,获取事件对象通过 $event
例子
<body> <div id="app"> <button @click="f1">按钮1</button> <button @click="f2('小u')">按钮2</button> <button @click="f3('小R',$event)">按钮3</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", methods: { f1() { console.log("无参数"); }, f2(name) { console.log("name is:" + name); }, f3(name, event) { console.log("name is:" + name + " and event is:" + event); console.log(event); }, }, }); </script> </body>
v-on的事件修饰符 ✨
事件修饰符,简化编码,比如阻止事件冒泡,阻止默认事件等等……
.stop 阻止事件冒泡
.prevent 阻止事件的默认行为
.键别名/键代码 特定键触发
.once 只触发一次回调
事件冒泡
微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
<body> <div id="app"> <div @click="f2"> <div @click="f1">点击事件冒泡</div> </div> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", methods: { f1() { console.log("f1"); }, f2() { console.log("f2"); }, }, }); </script> </body>
js冒泡和捕获是事件的两种行为,使用event.stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。
<body> <div id="app"> <div @click="f2"> <div @click="f1">点击事件冒泡</div> </div> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", methods: { f1(e) { console.log("f1"); e.stopPropagation(); }, f2() { console.log("f2"); }, }, }); </script> </body>
如果使用 vue 提供的事件修饰符,会更方便,可读性更好
<div id="app"> <div @click="f2"> <!-- 事件后点加修饰符 --> <div @click.stop="f1">点击事件冒泡</div> </div> </div>
v-if和v-else if和v-else使用 🤪
<body> <div id="app"> <li v-if="count == 10">如果count=10我就显示</li> <li v-if="count > 20">如果count大于20我就显示</li> <li v-else>如果都不对我就显示</li> </div> <script src="./vue.js"></script> <script> new Vue({ el: "#app", data: { count: 15, }, }); </script> </body>
登录切换小案例 ⛹️♂️
<!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> body { display: flex; align-items: center; justify-content: center; min-height: 100vh; } span { cursor: pointer; background-color: #69F; color: #FFF; border-radius: 5px; } input { margin-top: 30px; border: none; outline: none; border-bottom: 1px solid #ccc; width: 250px; } input[type='submit'] { border: none; height: 25px; background-color: #69F; color: #fff; } </style> </head> <body> <div id="app"> <span @click="f1">账号登录</span> <span @click="f2">手机登录</span> <form action="" method="post"> <input type="text" placeholder="请输入账号" v-if="flag == 10"> <input type="text" placeholder="请输入手机" v-else><br /> <input type="password" placeholder="请输入密码"><br /> <input type="submit" value="登录"> </form> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { flag: 0 }, methods: { f1() { this.flag = 10; }, f2() { this.flag = 20; } }, }) </script> </body> </html>
有一个小问题,生活中的注册登录,在切换登录方式时,里面的输入会被清空,但是我们上面的案例,并不会,为什么,这就涉及 vue 的底层了,它为了提高性能,使用了 diff 算法,说白了,就是找不同算法,结合虚拟 DOM ,实现最大化的复用,如果 key 相同,能复用,就原地复用,如果不能,再创建 DOM渲染视图,我们可以设置不同的 key,以达到每次都重新渲染的效果
<div id="app"> <span @click="f1">账号登录</span> <span @click="f2">手机登录</span> <form action="" method="post"> <input type="text" placeholder="请输入账号" v-if="flag == 10" key="account"> <input type="text" placeholder="请输入手机" v-else key="phone"><br /> <input type="password" placeholder="请输入密码"><br /> <input type="submit" value="登录"> </form> </div>
v-show与v-if是情侣关系吗 🤪
v-show 和 v-if 都是控制元素是否展示的,我想问他们是情侣吗?哈哈,跑偏了,回归正题,通过下面代码,你会秒懂,并知道啥时候该用啥
<!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"> <p v-if="1==1">v-if {{message}}</p> <p v-show="1==1">v-show {{message}}</p> <hr/> <p v-if="1==2">v-if {{message}}</p> <p v-show="1==2">v-show {{message}}</p> </div> <script src="./vue.js"></script> <script> new Vue({ el:'#app', data:{ message:'Hello King' } }) </script> </body> </html>
上图能发现,使用 v-show 为假隐藏元素时,他是通过css的 display:none 隐藏的,使用 v-for 为假隐藏元素时,他是直接将元素从 DOM 树里移除
什么时候使用 v-for,什么时候用 v-show
◼️ 当需要在隐藏和显示之间来回跳的话,推荐你使用 v-show,性能更好
◼️ 当只有一次或很少次的切换时,推荐使用 v-if
v-for遍历数组和对象 ♻️
<body> <div id="app"> <ul> <li>普通遍历数组</li> <li v-for="item in arrs">{{item}}</li> <hr /> <li>遍历数组,同时打印索引</li> <li v-for="(item,index) in arrs">{{index + 1}} - {{item}}</li> <hr /> <li>普通遍历对象</li> <li v-for="(value,key) in obg">{{key}} - {{value}}</li> <hr /> <li>遍历对象,同时获取index</li> <li v-for="(value,key,index) in obg">{{index}} - {{key}} - {{value}}</li> </ul> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { arrs: ['你的名字', '天气之子', '萤火之森'], obg: { name: '小爱', sex: '女', age: 8 } } }) </script> </body>
v-for 绑定 key 🧃
key的主要作用是高效的更新虚拟 DOM
使用index作为key
<body> <div id="app"> <ul> <li v-for="(item,index) in arrs" :key="index"> {{item.id}} - {{item.name}} - {{item.age}} <input type="text"> </li> </ul> <button @click="add">添加一个小张</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { arrs: [ { id: '001', name: '小艾', age: 18 }, { id: '002', name: '小兵', age: 24 }, { id: '003', name: 'Sirie', age: 26 } ] }, methods: { add(){ const xiaozhang = {id:'004',name:'小张',age:8}; this.arrs.unshift(xiaozhang); } }, }) </script> </body>
使用 index 作为 key,当你在前面添加时,就导致 index 重新编排,最坏的就是从头插
入,这时虚拟dom的diff算法,就不能就地复用了
当我们使用id作为 key 时,避免v-for“就地更新”策略导致的问题。
数组中哪些方法是响应式的?⚙️
◼️ 因为 Vue 是响应式的,所以当数据有变化时,Vue会自动检测到数据的变化,视图会发生对应的更新
◼️ Vue 包含了一组观察数组变化的方法,使用这些方法操作数组才会被 Vue 检测到,从而更新视图
◼️ 使用下标操作数组,不会被 Vue 检测到,因为代价较大,所以不是响应式的,而下面的这些方法都是被 Vue 重写过的,在实现功能的基础上,添加了响应式的代码
⚙️ push()
⚙️ pop()
⚙️ shift()
⚙️ unshift()
⚙️ splice()
⚙️ sort()
⚙️ reverse()
源码863行定义了这些响应式方法
购物车案例 🍓
*** <!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> * { margin: 0; padding: 0; box-sizing: border-box; } #app { display: flex; width: 100vw; height: 100vh; } table { margin: auto; width: 40%; border-collapse: collapse; } th, td { height: 35px; line-height: 35px; text-align: center; border: 1px solid rgb(222, 222, 222); } th { background-color: rgb(238, 238, 238); color: #454545; } button { width: 40px; height: 25px; border: 1px solid #cfcfcf; border-radius: 6px; background-color: transparent; } p { position: absolute; bottom: 200px; left: 50%; transform: translateX(-50%); } </style> </head> <body> <div id="app"> <p v-show="shoppings.length == 0">什么都没有呀</p> <table> <tr> <th v-show="shoppings.length != 0" v-for="item in names">{{item}}</th> </tr> <tr v-for="(item,index) in shoppings"> <td>{{item.name}}</td> <td>{{item.date}}</td> <td>{{item.price}}</td> <td> <button @click="subNum(index)">-</button> {{item.num}} <button @click="addNum(index)">+</button> </td> <td> <button @click="moveShop(index)">移除</button> </td> </tr> <p v-show="shoppings.length != 0">总价:{{priceSum}}</p> </table> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { names: ['商品名称', '出版日期', '价格', '购买数量', '操作'], shoppings: [ { id: 1, name: '卫龙辣条', date: '2012-12-12', price: 10, num: 1 }, { id: 2, name: '嘿嘿C语言', date: '2012-2-10', price: 100, num: 1 }, { id: 3, name: '别想嫩多啦', date: '2021-2-2', price: 20, num: 1 }, { id: 4, name: '球衣', date: '2009-12-12', price: 1000, num: 1 }, ], totalPrice: 0 }, methods: { addNum(index) { this.shoppings[index].num++; }, subNum(index) { if (this.shoppings[index].num > 1) { this.shoppings[index].num--; } }, moveShop(index) { this.shoppings.splice(index, 1); } }, computed: { priceSum() { this.totalPrice = 0; for (let i = 0; i < this.shoppings.length; i++) { this.totalPrice += this.shoppings[i].price * this.shoppings[i].num; } return this.totalPrice; } } }) </script> </body> </html>
过滤器 🍂
定义在配置对象中添加 filters 配置项,然后写过滤函数,传入要处理的参数
使用在参数后 {{price | showDecimalPoint}}
可以使用多个过滤器
<body> <div id="app"> <ul> <li v-for="price in prices">{{price | showDecimalPoint}}</li> </ul> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { prices: [100, 200, 300, 10] }, filters: { showDecimalPoint(price) { return '¥' + price.toFixed(2); } } }) </script> </body>
增强for (for in) 🥣
使用增强 for 方便我们对数组和对象的遍历
使用 for in 遍历对象数组时,返回的是数组下标
<body> <div id="app"> <button @click="heightenFor">点击使用增强for(for in)</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { arrs: [ { id: 1, age: 56 }, { id: 2, age: 34 }, { id: 3, age: 24 }, { id: 4, age: 22 }, ] }, methods: { heightenFor() { for (let arr in this.arrs) { console.log(this.arrs[arr].age); } } }, }) </script> </body>
增强 for (for of) 💊
使用 for of 遍历对象数组时,会直接返回我们的对象,这就非常的方便了
<body> <div id="app"> <button @click="heightenFor">点击使用增强for(for of)</button> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { arrs: [ { id: 1, age: 56 }, { id: 2, age: 34 }, { id: 3, age: 24 }, { id: 4, age: 22 }, ] }, methods: { heightenFor() { for (let arr of this.arrs) { console.log(arr.id); console.log(arr.age); } } }, }) </script> </body>
v-model的使用和原理 🌍
<body> <div id="app"> <p>用户账号 <input type="text" v-model="username"> </p> <p>username: {{ username}}</p> </div> <script src="./vue.js"></script> <script> var vm = new Vue({ el: '#app', data: { username: '' } }) </script> </body>
模拟实现双向绑定
v-model其实是一个语法糖
🧃 1. 使用 v-bind 绑定一个 value 属性
🧃 2. v-on 指令给当前元素绑定 input 事件
<body> <div id="app"> <input type="text" :value="message" @input="message = $event.target.value">{{message}} </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { message: 'abc' } }) </script> </body>
v-model结合radio🥳
<body> <div id="app"> <label for="male"> <input type="radio" v-model="gender" value="男" id="male">🚹 </label> <label for="female"> <input type="radio" v-model="gender" value="女" id="female">🚹 </label> <p>{{gender}}</p> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { gender: '男' } }) </script> </body>
v-model结合checkbox🥳
<body> <div id="app"> <label for="agreement"> <input type="checkbox" id="agreement" v-model="isAgree">同意协议 </label> {{isAgree}} <hr /> <label for="1"> <input type="checkbox" v-model="hobbys" value="看动漫" id="1">看动漫 </label> <label for="2"> <input type="checkbox" v-model="hobbys" value="学java" id="2">学java </label> <label for="3"> <input type="checkbox" v-model="hobbys" value="打豆豆" id="3">打豆豆 </label> <label for="4"> <input type="checkbox" v-model="hobbys" value="起飞" id="4">起飞 </label> <p>你的爱好是: {{hobbys}}</p> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { isAgree: false, hobbys: [] } }) </script> </body>
v-model结合select🥳
<body> <div id="app"> <select name="" id="" v-model="me"> <option value="青果">青果</option> <option value="香蕉">香蕉</option> <option value="山楂">山楂</option> <option value="草莓">草莓</option> <option value="西瓜">西瓜</option> </select> <p>你选择的水果是: {{me}}</p> <hr /> <select name="" id="" v-model="mes" multiple> <option value="青果">青果</option> <option value="香蕉">香蕉</option> <option value="山楂">山楂</option> <option value="草莓">草莓</option> <option value="西瓜">西瓜</option> </select> <p>你选择的水果是: {{mes}}</p> </div> <script src="./vue.js"></script> <script> new Vue({ el: '#app', data: { me: '西瓜', mes: [] } }) </script> </body>
v-model修饰符 🎨
lazy修饰符,使用 lazy 修饰符可以让数据在失去焦点或者回车时才更新
number修饰符,可以让输入框中的内容自动转换成数字类型
trim修饰符,可以过滤输入内容左右两边的空格