收获
在实例化 Vue 对象时,data 属性所引用的 data 对象的属性,在实例时就固定下来了;即如果后续给 data 对象添加的新属性,并不会出现在 Vue 对象中;
在 HTML 标签上可以使用 v-bind 等指令,来将某个标签的属性值和某个 vue 对象的属性值进行绑定;
在 input 标签上使用 v-model 指令,可以实现在输入框中,对 vue 对象属性值的修改,从而实现双向绑定;
组件绑定的对象,如果使用了 Object.freeze 方法处理过,则绑定将失效,即对象属性的更新,将不再会反应到视图上面;
生命周期钩子 Vue 实例由若干个阶段组成它的生命周期,它带来一些内置的方法,可以在这些阶段插入一些想要实现的函数,即所谓的钩子,包括 created、mounted、updated、destroyed 等;
模板语法 插值 文本 用双大括号绑定 Vue 实例的 data;如果在 HTML 标签上添加 v-once 属性,则插值只会赋值一次,之后不会动态更新;
1 2 3 <span > Message: {{ msg }}</span > <span v-once > 这个将不会改变: {{ msg }}</span >
原始 HTML 当 Vue 实例的 data 不是普通的字符串,而是原始 html 格式字符串时,如果使用常规的双大括号,这些 html 格式的字符串,将被当成普通的文本处理;此时需要改成给标签增加 v-html 属性来绑定值,它才会被当作 HTML 处理;
1 2 3 <p > Using mustaches: {{ rawHtml }}</p > <p > Using v-html directive: <span v-html ="rawHtml" > </span > </p >
Attribute 双大括号的写法,无法将 data 值赋给 HTML 标签的属性,此时需要使用 v-bind 指令来达到预期效果
1 2 3 <div v-bind:id ="dynamicId" > </div > <div :id ="dynamicId" > </div >
使用 javascript 表达式 在双大括号的内部,除了给绑定 data 值外,也是可以使用 javascript 表达式的;
1 2 3 4 5 6 7 {{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <div v-bind:id ="'list-' + id" > </div >
指令 “指令”指的是在 HTML 标签中使用 v- 前缀的特殊属性;除了 v-for 外,指令的值应为单个 javascript 表达式;它的作用是当表达式的值发生改变时,能够将新值作用于 DOM 元素,使其产生预期的变化;
1 <p v-if ="seen" > 现在你看到我了</p >
参数 有些指令能够接收参数,用来将表达式与参数所代表的属性值或者事件进行绑定
1 2 3 <a v-bind:href ="url" > ...</a > <a v-on:click ="doSomething" > ...</a >
动态参数 参数早期是一个静态的字符串,如果想让它变成动态的,则可以通过增加中括号来实现;这个时候参数实际上是一个表达式,通过表达式的求值,获得绑定目标,一般来说,这个目标应该是字符串类型的值,除了 null 外,其他非字符串的结果都会引发错误;
另外表达式存在一些约束,例如不能使用空格或者引号、不能使用大写字符来定义键名(会被强制转化小写,可能导致表达式求值失败);
1 <a v-bind: [attributeName ]="url" > ... </a >
修饰符 指令允许接以点号为标记的后缀,用来表达该指令需要以特殊的方式进行绑定;
例如:.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():
1 <form v-on:submit.prevent ="onSubmit" > ...</form >
缩写 v-bind 缩写 1 2 3 4 5 6 7 8 <a v-bind:href ="url" > ...</a > <a :href ="url" > ...</a > <a : [key ]="url" > ... </a >
v-on 缩写 1 2 3 4 5 6 7 8 <a v-on:click ="doSomething" > ...</a > <a @click ="doSomething" > ...</a > <a @[event ]="doSomething" > ... </a >
计算属性和侦听器 双大括号适合用来放置一些简单的变量,虽然它也支持内置表达式,但是如果表达式很长,或者逻辑比较复杂,则看起来比较困难,此时可以使用 Vue 实例中的 computed 属性,在这个属性中,同样可以内置变量,但这些变量实际上是函数,当 HTML 标签绑定到这些变量后,它实际上是会执行函数并将最终结果赋值给标签;
1 2 3 4 <div id ="example" > <p > Original message: "{{ message }}"</p > <p > Computed reversed message: "{{ reversedMessage }}"</p > </div >
1 2 3 4 5 6 7 8 9 10 11 var vm = new Vue ({ el : '#example' , data : { message : 'Hello' }, computed : { reversedMessage : function ( ) { return this .message .split ('' ).reverse ().join ('' ); } } });
计算属性 vs 方法 事实上,前面的例子,也可以通过给 HTML 标签绑定 Vue 实例的方法来实现;
1 <p > Reversed message: "{{ reversedMessage( ) }}"</p >
1 2 3 4 5 6 7 var vm = new Vue ({ methods : { reverseMessage : function ( ) { return this .message .split ('' ).reverse ().join ('' ); } } });
虽然二者的结果是相同的,但是背后却有所区别;如果是绑定 Vue 实例的方法,每次访问变量,都会执行方法计算结果;但计算属性则使用缓存来返回结果,直到所绑定的标签发生变化后,才会重新求值,因此它的性能更加好;对于简单的计算二者区别不明显,但是如果计算量很大,则可能产生明显差别;
计算属性 vs 监听属性 监听属性可以用来监听 data 中的属性值变化,当发生变化时,就会调用提前写好的监听函数;当有某个变量是由多个其他变量合成的时候,则将该变量放置在计算属性中是更加简单的做法;
1 <div id ="demo" > {{ fullName }}</div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var vm = new Vue ({ el : '#demo' , data : { firstName : 'Foo' , lastName : 'Bar' , fullName : 'Foo Bar' }, watch : { firstName : function (val ) { this .fullName = val + ' ' + this .lastName }, lastName : function (val ) { this .fullName = this .firstName + ' ' + val } } });
1 2 3 4 5 6 7 8 9 10 11 12 13 var vm = new Vue ({ el : '#demo' , data : { firstName : 'Foo' , lastName : 'Bar' }, computed : { fullName : function ( ) { return this .firstName + ' ' + this .lastName ; } } });
计算属性的 setter 计算属性默认只有 getter,但其实它也支持 setter 的做法;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 computed : { fullName : { get : function ( ) { return this .firstName + ' ' + this .lastName }, set : function (newValue ) { var names = newValue.split (' ' ) this .firstName = names[0 ] this .lastName = names[names.length - 1 ] } } }
侦听器 可以用来监听实例 data 属性中某个变量值的变化;当监听到某个变量值变化时,相应的函数就会被触发;大多数情况下使用计算属性更合适,但偶尔有时候,使用侦听属性更方便;监听器特别适合用来执行一些异步或计算开销大的函数;
1 2 3 4 <div id ="watch-example" > <p > Ask a yes/no question: <input v-model ="question" > </p > <p > {{ answer }}</p > </div >
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 var watchExampleVM = new Vue ({ el : '#watch-example' , data : { question : '' , answer : 'I cannot give you an answer until you ask a question!' }, watch : { question : function (newQuestion, oldQuestion ) { this .answer = 'Waiting for you to stop typing...' ; this .debouncedGetAnswer (); } }, created : function ( ) { this .denounceGetAnswer = _.denounce (this .getAnswer , 500 ); }, methods : { getAnswer : funcion () { this .answer = 'Thinking...' var vm = this ; axios.get ('https://yesno.wtf/api' ) .then (function (response ) { vm.answer = _.capitalize (response.data .answer ) }) .catch (function (error ) { vm.answer = 'Error! Could not reach the API. ' + error }); } } });
Class 与 Style 绑定 绑定 HTML class 使用 v-bind 进行表达式与属性的绑定时,表达式的计算结果是字符串,多数情况下这是OK的,但是如果是要动态的改变 CSS 的 Class 时,拼接字符串就显得麻烦而且容易出错;此时可以通过给 v-bind:class 传递一个对象,来实现对 CSS Class 的动态增加和减少(即让 HTML 是否拥有哪几个 Class);
1 2 3 <div v-bind:class ="{ active: isActive }" > </div > <div class ="active" > </div >
另外上面的例子,还可以写成如下的样子
1 <div v-bind:class ="classObj" > </div >
1 2 3 4 5 6 7 var vm = new Vue ({ data : { classObj : { active : isActive } } });
甚至 classObj 还可以放在计算属性中,实现更高级和复杂的场景;
1 <div v-bind:class ="classObj" > </div >
1 2 3 4 5 6 7 8 9 10 data : { isActive : true },computed : { classObj : function ( ) { return { active : this .isActive } } }
数组语法 除了对象外,v-bind:class 还支持数组类型的值,以实现同时绑定多个 class
1 <div v-bind:class ="[activeClass, errorClass]" > </div >
1 2 3 4 data : { activeClass : 'active' , errorClass : 'text-danger' }
用在组件上 在定义组件时,允许在 template 上面提前写入一些 class,之后在引用组件时,还可以再定义 class,此时的定义不会覆盖前面的定义;
1 2 3 Vue .component ('my-component' , { template : '<p class="foo bar">Hi</p>' });
1 <my-component class ="baz boo" > </my-component >
最终的渲染结果如下:
1 <p class ="foo bar baz boo" > Hi</p >
绑定内联样式 对象语法 1 <div v-bind:style ="styleObject" > </div >
1 2 3 4 5 6 7 data : { styleObject : { color : 'red' , fontSize : '13px' } }
数组语法 1 <div v-bind:style ="[baseStyles, overridingStyles]" > </div >
自动添加前缀 如果某些 CSS 样式需要根据不同的浏览器格式要求,添加相应的前缀,例如 transform,该工作会由 Vue 自动侦测并处理;
多重值 支持数组提供多个备用值,Vue 会自动检查哪个值适用,如果都不适用,则使用最后那一个;
1 <div :style ="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }" > </div >
条件渲染 v-if 1 2 <h1 v-if ="awesome" > Vue is awesome!</h1 > <h1 v-else > Oh no 😢</h1 >
如果需要对多个 HTML 元素实现条件切换,则可以使用 把这些元素包起来形成一个组;
1 2 3 4 5 <template v-if ="ok" > <h1 > Title</h1 > <p > Paragraph 1</p > <p > Paragraph 2</p > </template >
v-else-if 如果有多个条件分支,则可以使用 v-else-if
1 2 3 4 <div v-if ="type === 'A'" > A </div > <div v-else-if ="type === 'B'" > B </div > <div v-else-if ="type === 'C'" > C </div > <div v-else > Not A/B/C </div >
用 key 管理可复用的元素 对于在 if-else 中重复出现的部分,Vue 会对其进行复用,以提高渲染的速度;如果有些情况复用是不必要的,则可以通过给每个标签增加不同 key 来实现;
1 2 3 4 5 6 7 8 <template v-if ="loginType === 'username'" > <label > Username</label > <input placeholder ="Enter your username" key ="username-input" > </template > <template v-else > <label > Email</label > <input placeholder ="Enter your email address" key ="email-input" > </template >
v-show v-if 用来决定是否渲染,v-show 则一定会渲染元素,但控制它是否显示;当某个元素可能出现频繁的切换时,使用 v-show 更加合理,性能开销更小;
列表渲染 v-for v-for 可以用来基于某个数组渲染出元素的列表
1 2 3 <ul id ="example-1" > <li v-for ="item in items" :key ="item.message" > {{ item.message }} </li > </ul >
1 2 3 4 5 6 7 8 9 var example1 = new Vue ({ el : '#example-1' , data : { items : [ { message : 'Foo' }, { message : 'Bar' } ] } });
除了 item 外,v-for 还支持增加一个 index 参数,另外可以在 v-for 中访问父作用域的属性值
1 2 3 4 5 <ul id ="example-2" > <li v-for ="(item, index) in items" > {{ parentMessage }} - {{ index }} - {{ item.message }} </li > </ul >
1 2 3 4 5 6 7 8 9 10 var example2 = new Vue ({ el : '#example-2' , data : { parentMessage : 'Parent' , items : [ { message : 'Foo' }, { message : 'Bar' } ] } });
在 v-for 里使用对象 v-for 除了可以用遍历数组外,还可以用来遍历对象的属性
1 2 3 4 5 <ul id ="v-for-object" class ="demo" > <li v-for ="value in object" > {{ value }} </li > </ul >
1 2 3 4 5 6 7 8 9 10 new Vue ({ el : '#v-for-object' , data : { object : { title : 'How to do lists in Vue' , author : 'Jane Doe' , publishedAt : '2016-04-10' } } });
类似数组支持 index 作为第二个参数,对象也支持键名作为第二个参数,index 作为第三个参数
1 2 3 <div v-for ="(value, name) in object" > {{ name }}: {{ value }}</div >
1 2 3 <div v-for ="(value, name, index) in object" > {{ index }}. {{ name }}: {{ value }} </div >
维护状态 默认情况下,当 v-for 所绑定的数组的数据发生变动时,v-for 会更新原生成的列表,但是为了提高渲染速度,它不是按照数组里面的新顺序来重新生成列表的,而是会复用原列表的顺序,然后仅仅替换其中的数据,这意味着列表的顺序仍然是旧的,只有数据是新的;
如果列表的顺序与数组的顺序保持一致,则需要给 v-for 增加一个 key 属性(应为字符串类型或数组类型的值)
1 2 3 <div v-for ="item in items" v-bind:key ="item.id" > </div >
一般来说,在使用 v-for 时,尽量同时使用 v-bind:key,因为这样的输出结果符合大多数情况下的预期;
数组更新检测 变更方法 数组有一些内置的方法,这些方法会改掉原有数组的内容;
push
pop
shift
unshift
reverse
sort
slice
非变更方法 以下方法不会改变原有的数组,而是返回一个新的数组
显示过滤/排序后的结果 如果想在不改变原有数组的情况下,显示一个过滤或排序后的数组,则可以考虑使用计算属性
1 <li v-for ="n in evenNumbers" > {{ n }}</li >
1 2 3 4 5 6 7 8 9 10 data : { numbers : [ 1 , 2 , 3 , 4 , 5 ] }, computed : { evenNumbers : function ( ) { return this .numbers .filter (function (number ) { return number % 2 === 0 }); } }
在 v-for 里面使用值范围 1 2 3 <div > <span v-for ="n in 10" > {{ n }} </span > </div >
在 上使用 v-for 1 2 3 4 5 6 <ul > <template v-for ="item in items" > <li > {{ item.msg }}</li > <li class ="divider" role ="presentation" > </li > </template > </ul >
v-for 与 v-if 一同使用 正常情况下,v-for 与 v-if 不建议同时使用,因为它们两个有优先级的差别,因此有可能产生预期外的结果;v-for 的优先级高于 v-if,因此当它们同时作用一个元素时,会先渲染出列表,之后再判断是否该某个列表条目;
1 2 3 <li v-for ="todo in todos" v-if ="!todo.isComplete" > {{ todo }} </li >
在组件上使用 v-for 数据不会自动被传递到组件里,需要使用组件的 prop 属性来传递数据;
1 2 3 4 5 6 <my-component v-for ="(item, index) in items" v-bind:item ="item" v-bind:index ="index" v-bind:key ="item.id" > </my-component >
事件处理 监听事件 v-on 可以用监听一些 DOM 事件,之后触发一些提前写好的操作;
1 2 3 4 <div id ="example-1" > <button v-on:click ="counter += 1" > Add 1</button > <p > The button above has been clicked {{ counter }} times.</p > </div >
1 2 3 4 5 6 var example1 = new Vue ({ el : '#example-1' , data : { counter : 0 } });
事件处理方法 操作除了可以作为表达式写在元素中,也可以作一个单独的函数,写在 Vue 实例的方法中;
内联处理器中的方法 除了给元素绑定方法外,还可以在元素中直接调用方法
1 2 3 4 <div id ="example-3" > <button v-on:click ="say('hi')" > Say hi</button > <button v-on:click ="say('what')" > Say what</button > </div >
1 2 3 4 5 6 7 8 new Vue({ el: '#example-3', methods: { say: function (message) { alert(message) } } });
原始的 DOM 事件可以使用 $event 进行引用,并且还可以作为参数传递给实例的方法或者内置方法;
1 2 3 <button v-on:click ="warn('Form cannot be submitted yet.', $event)" > Submit </button >
1 2 3 4 5 6 7 8 9 methods : { warn : function (message, event ) { if (event) { event.preventDefault () } alert (message); } }
事件修饰符 事件修饰符使用点符号来表示,接在事件名称的后面,常见的事件修饰包括:
stop:阻止事件传播
prevent:取消事件的默认行为
capture:优先捕获事件进行处理;
self:限制事件在当前元素;
once:控制事件只发生一次;
passive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <a v-on:click.stop ="doThis" > </a > <form v-on:submit.prevent ="onSubmit" > </form > <a v-on:click.stop.prevent ="doThat" > </a > <form v-on:submit.prevent > </form > <div v-on:click.capture ="doThis" > ...</div >
修饰符的顺序是很重要的,不同顺序意味着不一样的行为表现;
按键修饰符 按键修饰符用来监听键盘的按键,当某个按键被按下松开后,作出相应的响应;
1 2 <input v-on:keyup.enter ="submit" >
系统修饰键 系统修饰键比较特殊,它相当于要求在触发某个事件前,相应的系统键需要处于被按下的状态
.exact 修饰符 普通的系统修饰键仅关心某个按键是否被按下,但没有限制是否有多余按键被一起按了;如果要限制仅限某个按键被单独唯一的按下,没有多余的其他键,则可以添加 .exact 修饰符;
1 2 3 4 5 6 7 <button v-on:click.ctrl ="onClick" > A</button > <button v-on:click.ctrl.exact ="onCtrlClick" > A</button > <button v-on:click.exact ="onClick" > A</button >
鼠标按钮修饰符 用来限制仅某些鼠标按钮被按下时才会触发的事件
表单输入绑定 v-model 指令可以在表单输入元素上实现数据的双向绑定;