前言
Vue (读音 /vjuː/,类似于 view ) 是一套用于构建用户界面的渐进式框架 。
与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
另一方面,当与现代化的工具链 以及各种支持类库 结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
起步 下载 vue.js引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <body> <div id="app" >{{message}}</div> </ body> <script src="../js/vue.js" ></script> <script> / /let(变量) const(常量) const app = new Vue({ el: '#app', / /用于挂载要管理的元素 data: { / /定义数据 message: '你好!!!' } }) </ script>
“{ { } }”插值表达式用于获取data中定义的数据
Vue中的MVVM
案例,Vue计数器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <html > <head > <meta charset ="utf-8" > <title > </title > </head > <body > <div id ="app" > <h2 > 当前计数:{{counter}}</h2 > <button v-on:click ="add" > +</button > <button v-on:click ="sub" > -</button > </div > </body > <script src ="../js/vue.js" > </script > <script > const obj = { counter: 0, message: 'abc' } const app = new Vue({ el: '#app' , data: obj, methods:{ add:function () { console .log('add被执行' ) this .counter++ }, sub:function () { console .log('sub被执行' ) this .counter-- } } }) </script > </html >
Vue、生命周期 指令合集 { { } } Mustache(胡子,胡须)插值表达式,用于获取Vue对象中定义的数据
v-on 用于绑定事件
语法糖:@click
1 2 <button v-on:click ="sub" > -</button > <button @click ="sub" > -</button >
v-on参数
当通过methods中定义方法,以供@click调用,需要注意参数问题
情况一:如果该方法不需要额外参数,那么方法后的()可以不添加
但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
情况二:如果需要同时传入某个参数,同时需要even时,可以通过$event传入事件
v-on修饰符
在某些情况下,我们拿到event的目的可能是进行一些时间处理
Vue提供了修饰符来帮助我们方便的处理一些事件
.stop 调用event.stopPropagation()
.prevent 调用event.prevenDefault()
.{keyCode | keyAlias} 只当事件是从特定键触发时才触发回调
.native 监听组件根元素的原生事件
.once 只触发一次回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <body > <div id ="app" > <div @click ="divClick" > aaaaaa <button @click.stop ="btnClick" > 按钮</button > </div > <form action ="baidu" > <input type ="submit" value ="提交" @click.prevent ="submitClick" /> </form > <input type ="text" @keyup.enter ="keyUp" /> <button @click.once ="btn2Click" > 按钮2</button > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' }, computed: {}, methods: { btnClick(){ console .log("btnClick" ) }, divClick(){ console .log("divClick" ) }, submitClick(){ console .log('submitClick' ) }, keyUp(){ console .log("keyUp" ) }, btn2Click(){ console .log('btnClick' ) } } }) </script > </body >
v-once
该指令后面不需要跟任何表达式
该指令表示元素和组件只渲染一次,不会随着数据的改变而改变
1 <h2 v-once > {{message}}</h2 >
v-html 用于将数据解析成html页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <body > <div id ="app" > <h2 > {{url}}</h2 > <h2 v-html ="url" > </h2 > </div > <script > const vm = new Vue({ el: '#app' , data: { message: '你好' , url: '<a href ="http://www.baidu.com" > 百度一下</a > ' }, methods: {} }) </script > </body >
v-text 和Mustache作用差不多,但是如果需要在标签内再添加数据时,v-text的数据会覆盖掉其他数据
1 <h2 v-text ="message" > </h2 >
v-pre 不解析特殊字符比如{ { } }
1 <h2 v-pre > {{message}}</h2 >
v-cloak 当用户网络状况不好的时候页面可能很久不能加载完成,可能会出现不友好的页面
使用v-cloak消除不友好页面
设置style样式
1 2 3 4 5 <style > [v-cloak] { display : none; } </style>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="app" v-cloak > <h2 > {{message}}</h2 > </div > <script > setTimeout(function () { const vm = new Vue({ el: '#app' , data: { message: '你好' }, methods: {} }) },2000) </script >
v-bind 语法糖: ‘:’
动态绑定属性
属性不像文本值一样能够通过{ { } }绑定,这时可以通过v-bind来绑定
1 <img v-bind:src ="imgURL" alt ="" />
动态绑定class(对象语法)
1 <h2 v-bind:class ="{active: isActive,line: isLine}" > {{message}}</h2 >
{} 中的属性为键值对,active和line为样式名,其中 isActive和isLine的值为boolean值,可以控制boolean来控制是否使用样式,Boolean为true就使用样式,则反。
但是 这样写感觉代码会很拥挤,可以使用方法的方式来简化代码
1 <h2 v-bind:class ="getClasses()" > {{message}}</h2 >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <script> const app = new Vue({ el: '#app' , data: { message: '你好' , isActive: true , isLine: true }, methods: { btnClick(){ this .isActive = !this .isActive }, getClasses: function ( ) { return {active : this .isActive,line : this .isLine} } } }) </script>
注意使用v-bind绑定方法需要加 ()
动态绑定class(数组语法)
1 <h2 class ="title" :class ="['active','line']" > {{message}}</h2 >
这个效果和下面是一样的,不能实现动态绑定
1 <h2 class ="title active line" > {{message}}</h2 >
实现动态绑定,将数组中的单引号去除,表示active和line为变量,它就会去data中去找
1 <h2 class ="title" :class ="[active,line]" > {{message}}</h2 >
或者通过绑定的方法来实现
1 <h2 class ="title" :class ="getClasses()" > {{message}}</h2 >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script> const app = new Vue({ el: '#app' , data: { message: '你好' , active: 'aaa' , line: 'bbb' }, methods: { getClasses: function ( ) { return [this .active,this .line] } } }) </script>
动态绑定样式 (对象)
1 2 <h2 :style ="{fontSize: '50px'}" > {{message}}</h2 >
动态绑定样式 (数组)
1 <h2 :style ="[baseStyle,baseStyle1]" > {{message}}</h2 >
1 2 3 4 5 6 7 8 9 10 11 <script> const app = new Vue({ el: '#app' , data: { message: '你好' , baseStyle: {backgroundColor : 'red' }, baseStyle1: {fontSize : '100px' } }, methods: {} }) </script>
v-if、v-else、v-if-else 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <body > <div id ="app" > <h2 v-if ="score >= 90" > 优秀</h2 > <h2 v-else-if ="score >= 80" > 良好</h2 > <h2 v-else-if ="score >= 60" > 及格</h2 > <h2 v-else > 不及格</h2 > <h1 > {{result}}</h1 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { score: 99 }, computed: { result() { let showMessage = '' ; if (this .score >= 90 ) { showMessage = '优秀' } return showMessage } }, methods: { } }) </script > </body > html
v-show
v-show的用法和v-if的用法非常相似,也用于决定一个元素是否渲染
该如何选择呢?
v-if当条件为false时,压根不会有对应的元素在DOM中
v-show当条件为false,仅仅是将元素的display属性设置为none而已
当需要在显示与隐藏之间切换很频繁时使用v-show,否则使用v-if
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <body > <div id ="app" > <h2 v-if ="isShow" id ="aaa" > {{message}}</h2 > <h2 v-show ="isShow" id ="bbb" > {{message}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , isShow: true }, computed: {}, methods: {} }) </script > </body >
v-for 遍历数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <body > <div id ="app" > <ul > <li v-for ="item in names" > {{item}}</li > </ul > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { names: ['why' ,'kobe' ,'james' ,'curry' ] }, computed: {}, methods: {} }) </script > </body >
遍历对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <body > <div id ="app" > <ul > <li v-for ="item in info" > {{item}}</li > </ul > <ul > <li v-for ="(value,key) in info" > {{key}}-{{value}}</li > </ul > <ul > <li v-for ="(value,key,index) in info" > {{index}}-{{key}}--{{value}}</li > </ul > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { info:{ name: 'wht' , age: 18, height: 1.88 } }, computed: {}, methods: {} }) </script > </body >
v-model 如何使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <body > <div id ="app" > <input v-model ="message" /> <h2 > {{message}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' }, computed: {}, methods: {} }) </script > </body >
v-model相当于是一个双向绑定,意思是input值如果被修改了,那么被绑定的message的值也会被修改,同理message的值被修改了,input的值也会被修改
原理
v-model其实是一个语法糖,它的背后本质上是包含两个操作:
v-bind绑定一个value属性
v-on指令给当前元素绑定input事件
也就是说下面的代码:等同于下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <body > <div id ="app" > <input v-model ="message" v-on:input ="valueChange" /> <h2 > {{message}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' }, computed: {}, methods: { valueChange(event){ this .message = event.target.value } } }) </script > </body >
v-model结合radio 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <body > <div id ="app" > <h2 > {{message}}</h2 > <label for ="man" > <input type ="radio" id ="man" v-model ="sex" value ="男" /> 男 </label > <label for ="woman" > <input type ="radio" id ="woman" v-model ="sex" value ="女" /> 女 </label > <h1 > 你选择的是: {{sex}}</h1 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , sex: '' }, computed: {}, methods: {} }) </script > </body >
以前写单选按钮的时候需要设置 input 的 name属性 为相同,才能达到单选按钮效果,现在使用v-model也是一样的,同时还完成了双向绑定的效果
v-model结合checkbox 单选
1 2 3 4 5 <label for ="agreement" > <input type ="checkbox" id ="agreement" v-model ="isAgreement" /> 同意协议</label > <h1 > 你选择的是:{{isAgreement}}</h1 > <button :disabled ="!isAgreement" > 下一步</button >
多选
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <input type ="checkbox" value ="唱" v-model ="hobbies" /> 唱<input type ="checkbox" value ="跳" v-model ="hobbies" /> 跳<input type ="checkbox" value ="rap" v-model ="hobbies" /> rap<input type ="checkbox" value ="篮球" v-model ="hobbies" /> 篮球<input type ="checkbox" value ="music" v-model ="hobbies" /> music<h2 > 你的爱好是:{{hobbies}}</h2 > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , isAgreement: '' , hobbies: [] }, computed: {}, methods: {} }) </script >
v-model结合select 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <body > <div id ="app" > <h2 > {{message}}</h2 > <select name ="abc" v-model ="fruit" > <option value ="aaa" > aaa</option > <option value ="bbb" > bbb</option > <option value ="ccc" > ccc</option > <option value ="ddd" > ddd</option > <option value ="eee" > eee</option > </select > <h1 > 你选中的是:{{fruit}}</h1 > <select name ="abc" v-model ="fruits" multiple ="multiple" > <option value ="aaa" > aaa</option > <option value ="bbb" > bbb</option > <option value ="ccc" > ccc</option > <option value ="ddd" > ddd</option > <option value ="eee" > eee</option > </select > <h1 > 你选中的是:{{fruits}}</h1 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , fruit: 'aaa' , fruits: [] }, computed: {}, methods: {} }) </script > </body >
值绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <label v-for ="item in orginHobbies" :for ="item" > <input type ="checkbox" :value ="item" :id ="item" v-model ="hobbies" /> {{item}} </label > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , isAgreement: '' , hobbies: [], orginHobbies: ['唱' ,'跳' ,'rap' ,'篮球' ,'music' ] }, computed: {}, methods: {} }) </script >
给value动态绑定
修饰符 lazy,number,trim 1 2 3 4 5 6 7 8 9 10 11 <input type ="text" v-model.lazy ="message" /> <h2 > {{message}}</h2 > <input type ="number" v-model.number ="age" /> <h2 > {{typeof age}}</h2 > <input type ="text" v-model.trim ="name" /> <h2 > {{name}}</h2 >
计算属性 computed: 计算属性()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <div id ="app" > <h2 > {{fullName}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { firstName: 'Lebron' , lastName: 'James' }, computed:{ fullName: function () { return this .firstName + ' ' + this .lastName } }, methods: {} }) </script >
以属性的方式来调用
案例计算总价:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <div id ="app" > <h2 > 总价格:{{totalPrice}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { books: [ {id: 1 ,name: 'aaa' ,price: 119 }, {id: 2 ,name: 'bbb' ,price: 23 }, {id: 3 ,name: 'ccc' ,price: 4125 }, {id: 4 ,name: 'ddd' ,price: 645 }, {id: 5 ,name: 'eee' ,price: 23 }, {id: 6 ,name: 'fff' ,price: 7 } ] }, computed:{ totalPrice: function () { let result = 0 /* for(let i=0; i < this.books.length; i++){ result += this .books[i].price } return result */ /* for(let i in this.books){ result += this .books[i].price } return result */ for (let book of this .books){ result += book.price } return result } }, methods: { } }) </script >
计算属性的setter和getter
计算属性的本质,完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <body > <div id ="app" > <h2 > {{fullName}}</h2 > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { firstName: 'Kobe' , lastName: 'Bryant' }, computed: { fullName: { set : function (newValue) { console .log('-------' ,newValue); const names = newValue.split(' ' ); this .firstName = names[0 ]; this .lastName = names[1 ]; }, get : function () { return this .firstName + ' ' + this .lastName } } }, methods: {} }) </script > </body >
但是这样写没有必要,缩写
1 2 3 fullName: { return this .firstName + ' ' + this .lastName }
计算属性computed和方法methods的区别
两种方式语法没有太大区别,但是性能有很大差异
computed中定义的的函数如果在重复调用的时候,它会检测需求数据是否改变,如果没有,将显示上一次结果,而methods不会
计算属性的缓存
let/var
ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们的必须借助于function的作用域来解决外面变量的问题
ES6中加入了let,let它是有if和for的块级作用域
没有作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <body > <button > 1</button > <button > 2</button > <button > 3</button > <button > 4</button > <button > 5</button > </body > <script > var btns = document .getElementsByTagName('button' ) for (var i=0 ; i<btns.length; i++){ btns[i].addEventListener('click' ,function () { console .log('第' + i + '个按钮被点击' ) }) } </script >
当点击第一个按钮的时候
输出的却是第五个按钮
ES5中改正写法
闭包写法,因为function是有块级作用域的
1 2 3 4 5 6 7 8 9 10 <script > var btns = document .getElementsByTagName('button' ) for (let i=0 ; i<btns.length; i++){ (function (i) { btns[i].addEventListener('click' ,function () { console .log('第' + i + '个按钮被点击' ); }) })(i) } </script >
ES6中写法
将var改成let
1 2 3 4 5 6 7 8 <script > var btns = document .getElementsByTagName('button' ) for (let i=0 ; i<btns.length; i++){ btns[i].addEventListener('click' ,function () { console .log('第' + i + '个按钮被点击' ) }) } </script >
就恢复正常了
因为使用var声明i的时候,它是没有作用域的,在for循环的时候当循环到最后一个数时,就将i改成了最终值,而let是有块级作用域的,其他函数的改变并不会影响自身
const
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const obj = { name: 'why' , age: 18 , height: 1.88 } console .log(obj); obj.name = 'kobe' ; obj.age = 40 ; obj.height = 1.87 ; console .log(obj)
增强写法 对象字面量增强写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 const obj = new Object () const obj = { name: 'why' , age: 18 , fun: function ( ) { console .log('在奔跑' ) }, eat: function ( ) { console .log('在吃东西' ) } } const name = 'why' ;const age = 18 ;const height = 1.88 const obj = { name: name, age: age, height: height } const obj = { name, age, height } console .log(obj) const obj = { run: function ( ) { }, eat: function ( ) { } } const obj = { run(){ }, eat(){ } }
事件监听
在前端开发中,我们需要经常和用户交互。
这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等
在Vue中如何使用监听事件呢?使用v-on指令
v-on介绍
作用:绑定事件监听器
缩写:@
预期:Function | Inline Statement | Object
参数:event
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <body > <div id ="app" > <span v-if ="isUser" > <label for ="username" > 用户账号</label > <input type ="text" id ="username" placeholder ="用户账号" key ="username" /> </span > <span v-else > <label for ="email" > 用户邮箱</label > <input type ="text" id ="email" placeholder ="用户邮箱" key ="email" /> </span > <button @click ="isUser = !isUser" > 切换类型</button > </div > <script src ="../js/vue.js" > </script > <script > const app = new Vue({ el: '#app' , data: { message: '你好' , isUser: true }, computed: {}, methods: { btnClick() { this .isUser = !this .isUser } } }) </script > </body >
点击切换,用户之前在输入框中输入的数据没有被清除,给input标签加一个key属性,属性值不同及不会保留
组件的key属性 key属性使用item,不然达不到效果
高阶函数 filter 如果有一个需求是需要你将一个数组里大于 n 的数字取出来,那么你可以使用 filter函数
1 2 3 4 5 let nums = [10 , 20 , 50 , 40 , 100 ]let nums2 = nums.filter(function (n ) { return n < 50 }) console .log(nums2)
filter 的参数为回调函数,意思就是你的数组有多少位,这个函数就回调几次,回调函数中的 n 为数组的值
filter的返回值只能是一个boolean 值 ,为true则将返回的值添加到一个新的数组中,声明 nums2 接收
map 接着上述需求,还需要将刚刚求出来的值进行 * 2 的操作,那么就可以使用map函数
1 2 3 4 let nums3 = nums2.map(function (n ) { return n * 2 }) console .log(nums3)
参数也是回调函数,n 的值也是为数组的值,只不过返回值可以做运算
reduce 接着上述要求,还需要进行一个汇总,那么就可以使用 reduce函数
这个函数和上面两个有点不同
1 2 3 4 let nums4 = nums3.reduce(function (prevValue,n ) { return prevValue + n },0 ) console .log(nums4)
参数依然是回调函数,但是回调函数中多了一个参数,prevValue 表示上一次运行的结果,n 表示 数组里面的值
后面的 0 表示为 prevValue 的初始值,
简洁写法 上述要求简洁写法(链式调用)
1 2 3 4 5 6 7 8 let nums2 = nums.filter(function (n ) { return n < 50 }).map(function (n ) { return n * 2 }).reduce(function (prevValue,n ) { return prevValue + n }) console .log(nums2)
更简洁写法(箭头函数)
1 console .log(nums.filter(n => n < 50 ).map(n => n * 2 ).reduce((prevValue,n ) => prevValue + n))