Vue.js应用基础
一 简介
1,什么是vue
vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。所谓渐进式即是指我们可以通过vue构建从简单到复杂的页面应用,并且vue.js压缩文件只有33k,构建简单的页面不会显得臃肿,同时vue构建的复杂页面也不会显得简陋。
vue实现了dom对象和数据的双向绑定,你不用直接操作dom,这项工作完全由vue来完成,你可以把更多的精力放到业务逻辑上来。
2,安装
vue目前最新的版本是2.6.x。当然,vue也提供了开发版和生产版两种文件。由于vue使用了ecmascript 5的特性,所以ie8及之前版本的浏览器不被支持。
vue支持多种方式安装,<script>标签、cdn,cli以及npm。学习阶段建议使用mdn或本地引入。
如果你想构建大型应用,请使用npm安装,方便配合webpack或类似的打包工具。如果你正在开发单页面应用(spa),那么vue提供的cli工具可能是更好的选择。这两种方式请关注vue官网。
1 //mdn 2 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 3 //本地 4 <script src="js/vue.js"></script>
二 vue实例
1,创建vue实例
通常,每个vue的应用都是通过创建一个vue实例开始的:
1 var vm = new vue({ 2 // some code 3 });
vm是viewmodel的缩写,许多文档或教程也使用app来接收返回的对象,这都无所谓了,你只要知道我们需要声明一个变量来接收vue实例就行了。
在创建vue实例时,你可以传递一个对象,这个对象包含了你可能要用到的数据、方法、vue实例生命周期钩子等。稍后将一一讲解。
2,数据
当一个 vue 实例被创建时,参数对象的data属性绑定的对象中的所有属性都被加入到 vue 的响应式系统中。当这些属性的值发生改变时,视图将会产生“响应”,即修改为新的值。一般这会体现到html页面上。
1 var obj = {name: 'ren'}; 2 var vm = new vue({ 3 data: obj 4 }); 5 //你可以直接使用vm代替data来访问其绑定的对象属性(这里是obj.name) 6 obj.name = 'pen'; 7 vm.name;//'pen' 8 9 vm.name = 'ken'; 10 obj.name;//'ken' 11 //以上即可验证vue的数据双向绑定
需要注意的是,要想实现数据的双向绑定,在创建vue实例之前,这些数据就应该已经被定义了。
1 //接上面的例子 2 obj.age = 12; 3 vm.age;//undefined
另一个需要注意的点是object.freeze(),该方法会冻结对象,阻止修改对象现有的属性,这就意味了vue的响应式系统无法再对该对象起作用了。
1 var obj = {}; 2 object.freeze(obj); 3 var vm = new vue({ 4 data: obj 5 }); 6 //这里vm和obj的双向绑定将失效
除了数据属性外,vue还提供了一些有用的实例属性和方法,他们都有前缀$,用以区分用户变量。
1 vm.$data === data;//true 2 vm.$el === document.getelementbyid();//true 3 vm.$watch(); 4 vm.props;
vue还有很多其他的属性和方法,详情请看vue实例属性。
3,方法
vue在初始化的时候,我们还可以添加几个属性,methods、computed、watch。
1 var vm = new vue({ 2 el:'#app', 3 data:{ 4 firstname:'', 5 lastname:'' 6 }, 7 methods:{ 8 handler1:function(){}, 9 handler2:function(){} 10 }, 11 computed:{ 12 fullname:fucntion(){ 13 return this.firstname + ' ' + this.lastname ; 14 }, 15 }, 16 watch:{ 17 fullname:function(){ 18 console.log('the name has changed again'); 19 } 20 } 21 });
methods中一般定义一些事件处理函数,使用v-on指令绑定;computed中一般定义需要复杂计算才能的出的值;watch一般用于侦听某些值的变化,比如例子中用于侦听fullname的变化,每当fullname发生变化,都会执行其绑定的函数。
4,生命周期
每个 vue 实例在被创建时都要经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到 dom 并在数据变化时更新 dom 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。下面列举了几个常用的生命周期钩子函数。
1 var vm = new vue({ 2 data:{}, 3 //实例创建之前 4 beforecreate:function(){}, 5 //实例创建之后 6 created:function(){}, 7 //实例挂载之前 8 beforemount:function(){}, 9 //实例挂载之后 10 mounted:function(){}, 11 //数据更新之前 12 beforeupdate:function(){}, 13 //数据更新之后 14 updated:function(){} 15 });
完整的vue实例生命周期示意图:
vue通过vm.el挂载指定dom元素,挂载dom元素实际上是用vm.$el替换原始的dom元素。这样我们就可以通过只操作虚拟的dom元素vm.$el,来实现操作真实的dom对象的目的了。
1 var vm = new vue({ 2 el: '#app', 3 data:{} 4 }); 5 //记住,el通过id定位元素
三 模板语法
1,插值
插值一般使用双大括号语法:{{ msg }},中间添加变量名,这个变量一般是data或computed中的一个属性名。这样就可以实现html内容跟随变量变化了。
双大括号把内部的变量解析为文本,而通过v-html指令,可以使浏览器把变量解析为html代码。v-html有一个特点:它必须添加到一个html元素上,变量生成的html代码最终都以该元素为祖先元素。
1 <!-- 文本 --> 2 <div id="app">{{ name }}</div> 3 <!-- html --> 4 <div id="app"> 5 <p v-html="html"></p> 6 </div> 7 <script> 8 var obj = { 9 name:'ren', 10 html:'<span style="color:red"></span>' 11 }; 12 var vm = new vue({ 13 el:'#app', 14 data:obj 15 }); 16 </script>
{{ }}里面不仅可以填写简单的变量表达式,它同时也支持更为复杂的计算表达式。
1 <p>{{ number + 1 }}</p> 2 <p>{{ ok ? 'yes' : 'no' }}</p> 3 <p>{{ message.split('').reverse().join('') }}</p>
2,指令
第一小节提到的v-html,和它类似的v-*什么的就时vue提供的指令。比如,你可以通过v-once指令来实现一次性的插值,当数据改变时,插值处的内容不会再更新。
1 <div id="app" v-once>{{ name }}</div>
再比如,你要给html元素添加属性,那么你可能会用到v-bind指令。
<div v-bind:class="myclass"></div> <!-- 元素将被添加一个mycalss变量保存的值的类,同时,它也可以是一个稍复杂的计算表达式,如'my'+msg。如果你想移除该属性,你只需把null赋值给对应的变量 -->
亦或是你要给html元素绑定事件,v-on指令可以帮你实现。
1 <a v-on:click="eventhandler">link</a> 2 <!-- eventhandler是事件处理函数 -->
v-model指令可以双向绑定元素的value值与指定的变量。
1 <input type='text' name='name' v-model='name'></input> 2 *********************************************** 3 var vm = vue({ 4 data:{ 5 name:'ren' 6 } 7 }); 8 //输入框中的值会与vm.name同步
指令的作用是当指令绑定的表达式的值改变时,将其产生的连带影响,响应式地作用于 dom。这里只需明白什么是vue指令即可,常用的指令将在稍后的章节一一说明。
3,动态参数
如果你觉得上面的方式有失灵活,那么vue的动态参数或许能够帮到你。vue从2.6.0开始,允许你使用复杂表达式来定义指令最终的参数,不过你应该用[]方括号把它括起来。
1 <a v-bind:[attributename]="url"> link </a> 2 <!-- 具体哪个属性会被添加,完全依赖方括号中的表达式的计算值 -->
vue指令还可以添加修饰符,使用.点来添加vue指令的修饰符。例如.prevent,它告诉指令调用event.preventdefault()阻止事件默认行为。
1 <button v-on:submit.prevent="onsubmit">form</button> 2 <!-- 点击按钮时使用自定义函数,并通过.prevent阻止默认行为 -->
其他指令也有相应的修饰符,接下来的学习中会慢慢接触到。
4,简写
对于使用频率极高的v-bind和v-on指令,vue提供了简写形式。
1 <!-- 完整语法 --> 2 <a v-bind:href="url">...</a> 3 <a v-on:click="dosomething">...</a> 4 <!-- 缩写 --> 5 <a :href="url">...</a> 6 <a @click="dosomething">...</a> 7 <!-- 使用:冒号代替v-bind:,使用@替代v-on: -->
四 计算属性和侦听器
1,计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
所以,如果需要经过复杂的逻辑才能得到最终的值,建议你使用vue的计算属性。
1 var vm = new vue({ 2 el: '#app', 3 data: { 4 name: 'ren' 5 }, 6 computed: { 7 reversedname: function () { 8 // `this` 指向 vm 实例 9 return this.name.split('').reverse().join(''); 10 } 11 } 12 }); 13 ******************************************************************** 14 <div id="app">{{reversednmae}}</div> 15 //计算属性专门用于处理数据计算,需要指定返回值
2,侦听器
侦听器的作用是动态的监测数据的变化。
1 <input type='text' name='name' v-model='name'></input> 2 ************************************************************* 3 var vm = vue({ 4 data:{ 5 name:'' 6 } 7 watch:{ 8 name:function(){ 9 console.log(the name has changed again); 10 } 11 } 12 }); 13 //每当vm.name属性发生改变时,控制台都会输出一条信息
五 class和style
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用 v-bind
处理它们:只需要通过表达式计算出字符串结果即可。
不过,字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
1,绑定class
绑定class属性有两种方式,对象和数组。
首先是对象方式,请看下面的例子:
1 <div class='class0' v-bind:class="{class1:isclass1,class2:isclass2}"></div> 2 ********************************************************* 3 data:{ 4 isclass1:true, 5 isclass2:false 6 } 7 //通过data对象的isclass1和isclass2属性控制class1和class2是否被添加到div上,同时div上原来定义的class0不受影响
如果需要操作的class列表很大,那么你可以在data里添加一个classobj对象,专门用来存储class控制变量。你当然也可以通过计算属性computed来动态的计算哪些class属性会被添加到div上。
1 <div v-bind:class="classobj"></div> 2 ****************************************************** 3 //数据对象 4 data:{ 5 classobj:{ 6 isclass1:true, 7 isclass2:true 8 } 9 } 10 //计算属性 11 computed:{ 12 classobj:function(){ 13 return { 14 //既然使用计算属性,返回的对象应该是复杂计算得来的结果,由于只是举例,所以这里也只是简单的赋值了 15 isclass1:true, 16 isclass2:true 17 } 18 } 19 }
除了对象绑定class属性外,vue还提供了数组绑定的方式。
1 <div v-bind:class="[class1,class2]"> 2 *************************************** 3 data:{ 4 class1:'myclass', 5 class2:'yourclass' 6 }
数组方式还支持动态的绑定class属性,这是通过三元运算实现的。
1 <div v-bind:class="[iscalss1 ? class1 : '' , isclass2 ? class2 : '',class3]"></div> 2 ***************************************************************** 3 data:{ 4 isclass1:true, 5 isclass2:false 6 class3:'myclass' 7 } 8 //通过三元运算动态的绑定也可以和静态绑定组合使用
2,绑定内联样式
内联样式使用过html标签的style属性实现的,所以vue同样使用v-bind指令来添加内联样式。
1 <div v-bind:style="{ color: mycolor, fontsize: fontsize + 'px' }"></div> 2 ************************************************ 3 data: { 4 mycolor: 'red', 5 fontsize: 30 6 }
注意,css属性名可以使用驼峰式或短横线分隔样式,若果使用短横线分隔方式,记得用引号把它引起来。
直接绑定一个样式对象通常更好,这会让模板更清晰,同时也可以和class一样,使用vue的计算属性conputed动态生成。
1 <div v-bind:style="styleobject"></div> 2 ************************************************* 3 data: { 4 styleobject: { 5 color: 'red', 6 fontsize: '13px' 7 } 8 }
最后,绑定style属性也有数组语法,使用方式和绑定class的数组语法一样,这里不再赘述。
六 条件渲染
有时候我们可能需要在特定情况才需要渲染某些html元素,另外一些情况希望隐藏它,vue提供了条件渲染的方式。
1,v-if
v-if指令根据绑定的条件,来决定是否渲染该元素。同时vue还提供了另外两个指令:v-else-if和v-else,这让条件渲染变得更加灵活和强大。
1 <div v-if="answer === 'a'">a</div> 2 <div v-else-if="answer === 'b'">b</div> 3 <div v-else-if="answer === 'c'">c</div> 4 <div v-else>d</div> 5 ******************************************** 6 computed:function(){ 7 //some code 8 return answer; 9 } 10 //根据answer的值,决定渲染那个元素
请注意,在同一个逻辑区域内,使用这三个指令的元素必须紧挨着,否者他们会失效。另外,v-else-if可以出现多次,而v-if和v-else只能在首位各出现一次。
如果你想一次控制多个元素,那么你可以把条件指令作用到<template>元素上,最终的渲染结果将不包含<template>元素,而只包含其内部的元素。
1 <template v-if="ok"> 2 <h1>title</h1> 3 <p>paragraph 1</p> 4 <p>paragraph 2</p> 5 </template> 6 //当v-if接收到真值时,<template>元素不会出现在页面上,而h1和p会出现
2,v-show
v-show并不是真正意义上的条件渲染,它只是简单的操控元素的display属性,来达到显示或隐藏元素的目的。而v-if不经保证元素隐藏,还能保证绑定的事件能被及时的销毁或重建。
1 <h1 v-show="ok">hello!</h1> 2 <!-- 当ok为真值时,h1将被显示,否则将被隐藏 -->
七 列表
在vue中渲染列表需要用到v-for指令。v-for可以通过数组或对象渲染列表。
1,数组渲染
1 <ul> 2 <li v-for="(value,index) in arr">{{index}}:{{value}}</li> 3 </ul> 4 ************************************************** 5 data:{ 6 arr:[1,2,3] 7 } 8 //value是元素,index是下标,下标是可选的参数
你甚至可以显示一个数组经过过滤或排序后的版本,而不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
1 <li v-for="n in newarr">{{ n }}</li> 2 ******************************************** 3 data: { 4 arr: [ 1, 2, 3, 4, 5 ] 5 }, 6 computed: { 7 newarr: function () { 8 return this.arr.filter(function (val) { 9 return val % 2 === 0; 10 }) 11 } 12 }
2,对象渲染
1 <ul> 2 <li v-for="(value,name,index) in arr">{{parentmsg}}:{{index}}:{{value}}</li> 3 </ul> 4 ************************************************** 5 data:{ 6 parendmsg:'parent', 7 arr:{ 8 name:'ren', 9 age:12 10 } 11 } 12 //结果: 13 //parent:0:ren 14 //parent:1:age 15 //value是属性值,name是属性名,index是序号(一般同object.keys()的顺序),name和key都是可选的
从上面例子可以看出,v-for指令不仅可以访问绑定的对象,还可以访问其父域内的变量。
3,渲染顺序
默认状态下,当绑定的数据项顺序被改变时,vue不会主动的去修改已渲染的列表,如果要保证列表顺序始终与数据项一致,你应该给每一项的属性key提供一个唯一值,建议是数字或字符串等原始值。
1 <div v-for="(item,index) in arr" v-bind:key="index"></div> 2 <!-- 数组可以使用index,对象可以使用name -->
4,更新检测
我们知道,在javascript中,有很多方法可以修改数组和对象。但是,并不是所有的方法都能触发vue的响应,即并不是所有的方法都能触发视图更新。
对于数组,vue 不能检测以下数组的变动:
a:当你利用索引直接设置一个数组项时,例如:vm.items[indexofitem] = newvalue;
b:当你修改数组的长度时,例如:vm.items.length = newlength;
对于对象,vue 不能检测对象属性的添加和删除。详情见本文2.2节。
幸运的是,vue额外提供了vm.set方法来解决该问题。
1 //vue.set(object, name, value); 2 var obj = { 3 name:'ren', 4 age:12 5 }; 6 var vm = new vue({ 7 data:{ 8 person:obj 9 } 10 }); 11 vm.set(vm.person,'sex','male'); 12 //新的sex属性是响应式的。
需要注意的是,第一个参数必须是一个对象,即该data的属性应该绑定的是一个对象,才能使用该方法。
八 表单
上面3.2小节简单介绍的v-model指令,这里将详细介绍表单与它的关系,及用法。
1,文本绑定
1 <!-- 单行文本 --> 2 <input v-model="message"> 3 <p>message is: {{ message }}</p> 4 <!-- 多行文本 --> 5 <p>{{ message }}</p> 6 <textarea v-model="message"></textarea>
请注意:在文本区域插值 <textarea>{{text}}</textarea>
并不会生效,应用 v-model
来代替。
2,单选
1 <input type="radio" id="one" value="one" v-model="picked"> 2 <label for="one">one</label> 3 <br> 4 <input type="radio" id="two" value="two" v-model="picked"> 5 <label for="two">two</label> 6 <br> 7 <span>picked: {{ picked }}</span> 8 ***************************************************** 9 data:{ 10 picked:'' 11 }
3,复选
1 <input type="checkbox" id="jack" value="jack" v-model="checkednames"> 2 <label for="jack">jack</label> 3 <input type="checkbox" id="john" value="john" v-model="checkednames"> 4 <label for="john">john</label> 5 <input type="checkbox" id="mike" value="mike" v-model="checkednames"> 6 <label for="mike">mike</label> 7 <br> 8 <span>checked names: {{ checkednames }}</span> 9 ***************************************************** 10 data:{ 11 checknames:[] 12 } 13 <!-- 如果只有一个复选项,那么不使用数组会更方便 -->
4,下拉列表
1 <select v-model="selected"> 2 <option disabled value="">请选择</option> 3 <option>a</option> 4 <option>b</option> 5 <option>c</option> 6 </select> 7 <p>selected: {{ selected }}</p> 8 ************************************************ 9 data:{ 10 selected:''11 }
如果下拉列表式多选的,你可以给<select>标签增加一个multiple属性,并且selected属性需要绑定一个数组。
请注意,如果你希望页面第一次载入时默认选中某一项,那么你应该给selected属性设置该默认值。
你也可以使用v-for指令,动态的渲染下拉列表的选项。
1 <select v-model="selected"> 2 <option v-for="option in options" v-bind:value="option.value"> 3 {{ option.text }} 4 </option> 5 </select> 6 <p>selected: {{ selected }}</p> 7 ***************************************************** 8 data: { 9 selected: 'a', 10 options: [ 11 { text: 'one', value: 'a' }, 12 { text: 'two', value: 'b' }, 13 { text: 'three', value: 'c' } 14 ] 15 }
5,修饰符
v-model指令的本质是监听用户输入事件,然后自动选取正确的方式来更新元素。v-model为不同的元素使用不同的属性、监听不同的事件。
-
- text 和 textarea 元素使用
value
属性和input
事件; - checkbox 和 radio 使用
checked
属性和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
- text 和 textarea 元素使用
请注意:v-model 会忽略所有表单元素的 value
、checked
、selected
特性的初始值,而总是将 vue 实例的数据作为数据来源。所以,你应该通过 javascript 在组件的 data
选项中声明初始值。
我们知道,默认情况下,v-model对text使用input事件,你可以通过修饰符lazy使vue对其使用change事件;
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符;
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符;
1 <!-- 在“change”时而非“input”时更新 --> 2 <input v-model.lazy="msg" > 3 <!-- 直接得到number类型值 --> 4 <input v-model.number="age" type="number"> 5 <!-- 获得首位没有空白字符的值 --> 6 <input v-model.trim="msg">
九 事件
v-on指令用来监听dom事件,并在事件触发时执行一些javascript代码。
1,用法
1 <button v-on:click="counter += 1">add 1</button> 2 <p>{{ counter}}</p> 3 ************************************************ 4 data:{ 5 counter:0 6 }
虽然v-on指令可以直接绑定javascript语句,但要实现稍复杂逻辑,使用vue方法才是更好的选择。
1 <button v-on:click="greet($event)">click me</button> 2 ************************************************ 3 var vm = new vue({ 4 el:'', 5 data:{ 6 name:'ren' 7 }, 8 methods:{ 9 greet:function(event){//event:原生dom事件对象 10 alert(this.name);//this:当前vue实例,这里是vm 11 } 12 } 13 });
方法也可以直接用javascript调用:vm.greet();
2,事件修饰符
在事件处理程序中调用 event.preventdefault()
或 event.stoppropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 dom 事件细节。
为了解决这个问题,vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
-
.stop 阻止事件冒泡
.prevent 阻止默认行为
.capture 使用捕获事件
.self 事件源对象
.once 仅执行一次的事件处理器
.passive 不阻止默认行为,会是.prevent失效
事件修饰符是可以链式使用的,不过需要注意他们的顺序:
1 <!-- 阻止事件冒泡和默认行为,然后执行一些操作 --> 2 <a v-on:click.stop.prevent="dosomthing"></a> 3 <!-- 阻止事件冒泡和默认行为,不执行其他操作 --> 4 <form v-on:submit.prevent></form>
3,系统修饰符
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
-
.ctrl
.alt
.shift
.meta (ios的command 键,windows的win键)
1 <!-- alt + c --> 2 <input @keyup.alt.67="clear"> 3 <!-- ctrl + click --> 4 <div @click.ctrl="dosomething">do something</div>
一个特别的修饰符:.exact,它用于精确的指定组合按键以触发相关事件。
1 <!-- 只要ctrl键被按下就会触发,不管有无其他按键 --> 2 <button @click.ctrl="onclick">a</button> 3 <!-- 有且只有 ctrl 被按下的时候才触发 --> 4 <button @click.ctrl.exact="onctrlclick">a</button> 5 <!-- 没有任何系统修饰符被按下的时候才触发 --> 6 <button @click.exact="onclick">a</button>
4,鼠标修饰符
鼠标修饰符只有3个:.left、.right、.middle。这些修饰符会限制处理函数仅响应特定的鼠标按钮。
1 <!-- 只响应左键 --> 2 <button @click.left="onclick">a</button> 3 <!-- 只响应右键 --> 4 <button @click.right="onclick">a</button> 5 <!-- 只响应中键 --> 6 <button @click.middle="onclick">a</button>
关于vue.js的基础应用就先介绍到这儿,下一次更新将带来vue的核心:组件。