基础
Vue实例
使用vm这个边联名表示Vue实例。
所有的Vue组件都是Vue实例,并且接受相同的选项对象(一些根实例特有的选项除外)。
当一个Vue实例被创建时,它将data对象中的所有的property加入到Vue的响应式系统中。当这些值发生改变时,视图将会产生"响应",更新为新的值。这里唯一的例外是使用 Object.freeze()
,这会阻止修改现有的 property,也意味着响应系统无法再追踪变化。
除了数据property,Vue实例还暴露了一些有用的实例property与方法,它们都有前缀$,以便于用户定义的property区分开来。
每个Vue实例在被创建时都要经历一系列的初始化过程,在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
生命周期钩子的this上下文指向调用它的Vue实例。
Vue.js使用了基于HTML的模板语法,允许开发者声明式的将DOM绑定至底层Vue实例的数据。所有vue.js的模板都是合法的HTML,所有能被遵循规范的浏览器和HTML解析器解析。在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应系统,Vue能够只能的计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
数据绑定最常见的形式就是使用"Mustache"语法(双大括号)的文本插值。Mustache 标签将会被替代为对应数据对象data上 property 的值。
通过使用v-once指令,你能执行一次性的插值,当数据改变时,插值处的内容不会更新。
双大括号会将数据解释为普通文本而非HTML代码,为了输出真正的HTML,你需要使用v-html指令。不要对用户提供的内容使用插值。
对于用户界面UI,组件更适合作为可重用和可组合的基本单位。
Mustache语法(双大括号)不能作用在HTML attribute上,遇到这种情况应该使用v-bind指令。
指令
指令(Directives)是带有v-前缀的特殊attribute。指令attribute的值预期是单个javascript表达式(v-for是个例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM上。
参数
一些指令能够接收一个"参数",在指令名称之后用冒号表示。例如v-bind指令可以用于响应式地更新HTML attribute。
动态参数
**从2.6.0开始,可以用方括号括起来的javascript表达式作为一个指令的参数。**同样的,可以使用动态参数为一个动态的事件名绑定处理函数。
对动态参数的值的约束
动态参数预期会求出一个字符串,异常情况下值为 null
。这个特殊的 null
值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
对动态参数表达式的约束
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML attribute 名里是无效的。变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂表达式。
修饰符
修饰符 (modifier) 是以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
缩写
v-前缀作为一种视觉提示,用来识别模板中Vue特定的attribute。
v-bind缩写为: v-on缩写为@
计算属性和侦听器
对于任何复杂逻辑,都应当使用计算属性。
我们可以将同一函数定义为一个方法而不是一个计算属性,两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生变化时它们才会重新求值。相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
你可以像绑定普通property一样在模板中绑定计算属性。
计算属性VS侦听属性 computed VS watch
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:侦听属性。
计算属性默认只有getter,不过在需要时你也可以提供一个setter。
computed:{
property:{
get:function(){}
set:function(newValue){}
}
}
当需要在数据变化时执行异步或开销较大的操作时,侦听器(watch)是最有用的。
Class与Style绑定
操作元素的class列表和内联样式是数据绑定的一个常见需求。因为它们都是attribute,所以我们可以用v-bind处理它们:只需要通过表达式计算出字符串结果即可。在将v-bind用于class和style时,Vue.js做了专门的增强。表达式结果的类型除了字符串之外,还可以是数组或对象。
绑定HTML Class
v-bind:class 指令可以与普通class attribute共存。
//对象语法 将一个对象传给v-bind:class
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
//v-bind:class 也可以指向绑定一个返回对象的计算属性。
//数组语法 将一个数组传给v-bind:class
<div v-bind:class="[activeClass, errorClass]"></div>
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
当在一个自定义组件上使用class property时,这些class将被添加到该组件的根元素上,这个元素上已经存在的class不会被覆盖。
绑定内联样式
对象语法
v-bind:style 的对象语法十分直观,看着非常像CSS,但其实是一个js对象。用法同class
数组语法
v-bind:style
的数组语法可以将多个样式对象应用到同一个元素上。
//对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
//数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
自动添加前缀
当v-bind:style使用需要添加浏览器引擎前缀的CSS property时,Vue.js会自动侦测并添加相应的前缀。
条件渲染
v-if/v-else/v-else-if
v-if 指令用于条件性的渲染一块内容,这块内容只会在指令的表达式返回truthy值得时候被渲染。
因为v-if是一个指令,所以必须将它添加到一个元素上。如果一次渲染多个元素,可以把一个元素当做不可见的包裹元素,并在上面使用v-if,最终的渲染结果将不包含元素。
v-else元素必须紧跟在带v-if或者v-else-if(2.1.0新增)的元素后面,否则它将不会被识别。
用key管理可复用的元素
vue会尽可能高校的渲染元素,通常会复用已有元素而不是从头开始渲染。可以为元素添加具有唯一值的key属性来使元素进行重新渲染而不是重用。
v-show
带有v-show的元素始终会被渲染并保留在DOM中。v-show只是简单切换元素的CSS property display。 v-show不支持元素,也不支持v-else。
v-if VS v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
当v-if与v-for一起使用时,v-for具有比v-if更高的优先级。
列表渲染
用v-for把一个数组对应为一组元素
我们可以用v-for指令基于一个数组来渲染一个列表。v-for指令需要使用item in items形式的特殊语法,其中items是源数据数组,item则是被迭代的数组元素的别名。
<ul>
<li v-for="item in/of items" :key="...">
<li v-for="(item,index) in/of items" :key="...">
...
</li>
</ul>
在v-for块中,我们可以访问所有父作用域的property。v-for还支持一个可选的第二个参数,即当前项的索引。你也可以用of 替代 in作为分隔符,因为它更接近js迭代器的语法。
在v-for里使用对象
你也可以用v-for来遍历一个对象的property。
可以提供第二个参数作为property名称(键名)。
还可以使用第三个参数作为索引。
<div v-for="value in object">...</div>
<div v-for="(value, name) in object">...</div>
<div v-for="(value, name, index) in object"></div>
当 Vue 正在更新使用 v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素。你需要为每项提供一个key属性。建议尽可能在使用v-for时提供key属性,除非遍历输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是Vue识别节点的一个通用机制,key并不仅与v-foryou特别关联,它还有其他用途。
不要使用对象或数组之类的非基本类型作为v-for的key。请用字符串或数值类型的值。
数组更新检测
变更方法
vue将被侦听的数组的变更方法进行了包裹,所有它们也将会触发视图更新。这个被包裹的方法包括:push/pop/shift/unshift/splice/sort/reverse。
替换数组
像filter/concat/slice不会变更原始数组,而总是返回一个新数组。对于新数组渲染DOM,Vue为了是使DOM元素最大范围的重用而实现了一些智能的启发式办法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
由于js的限制,vue不能检测数组和对象的变化。
可以创建一个计算属性来返回需要过滤或排序后的数组。在计算属性不适用的情况下,可以使用方法methods。
在v-for里使用值范围
v-for也可以接受整数。在这种情况下,它会把模板重复对应次数。
在上使用v-for
类似于v-if ,可以利用带有v-for的来循环渲染一段包含多个元素的内容。
v-for与v-if一同使用
当v-for/v-if处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用。
<li v-for='item of items' v-if="!item...">
content
</li>
在组件上使用v-for
在自定义组件上,你可以像在任何普通元素上一样使用v-for。
<component-name v-for='item in items' :key='...'></component-name>
2.2.0+的版本中,在组件上使用v-for时,key现在是必须的。
然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了吧迭代数据传递到组件里,我们要使用prop。不自动将 item
注入到组件里的原因是,这会使得组件与 v-for
的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。
事件处理
监听事件
可以用v-on指令监听DOM事件,并在触发时运行一些js代码。
事件处理方法
许多事件处理逻辑会很复杂,所以直接把js写在v-on指令中是不可行的。因此,v-on还可以接收一个需要调用的方法名称。可以添加参数。
事件修饰符
方法只有纯粹的数据逻辑,而不是去处理dom事件细节。vue.js为v-on提供了事件修饰符,修饰符是由点开头的指令后缀来表示的。使用修饰符时,顺序很重要。
.stop/.prevent/.capture/.self/.once/.passive/.once
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue允许为v-on在监听键盘事件时添加按键修饰符。
系统修饰键
可以用如下修饰符来实现仅在按下相应按键时才出发鼠标或键盘事件的监听器:.ctrl/.alt/.shift/.meta
.exact修饰符允许你控制由精确的系统修饰符组合触发的事件。
表单输入绑定
你可以用v-model指令再表单、、元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。v-model本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model会忽略所有表单元素的value、checked、selected attribute的初始值而总是将Vue实例的数据作为数据来源。你应该通过js在组件的data选项中声明初始值。
v-model在内部为不同的输入元素使用不同的property并抛出不同的事件:
- text和textarea元素使用value property和input事件
- checkbox和radio使用ckecked property和change事件
- select字段将value作为prop并将change作为事件
修饰符
.lazy
在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步。你可以添加lazy修饰符,从而转为在change事件之后进行同步。
.number
将用户的输入值自动的转为数值类型。如果这个值无法被parseFloat()解析,则会返回原始的值。
.trim
自动过滤用户输入的首尾空白字符
Vue组件系统允许你创建具有完全自定义行为且可复用的输入组件。这些输入组件甚至可以和v-mode一起使用。
组件基础
组件是可复用的Vue实例,且带有一个名字。一个组件的data选项必须是一个函数,每个实例维护一份被返回对象的独立的拷贝。
通过Prop向子组件传递数据
每个组件必须只有一个根元素
在组件上使用v-model
自定义事件也可以用于创建支持v-model的自定义输入组件。
<input v-model='searchText'>
等价于
<input :value='searchText' @input="...">
<custom-input :value='' @input=''></custom-input>
<custom-input v-model="..."></custom-input>
为了让自定义组件正常工作,这个组件内的<input>必须:
1、将其value attribute绑定到一个名叫vaule的prop上
2、在其input事件被触发时,将新的值通过自定义的input事件抛出
动态组件
简单的来说,因为vue模板就是dom模板,使用的是浏览器原生的解析器进行解析,所以dom模板的限制也就成为vue模板的限制了,要求vue模板是有效的HTML代码片段。但是由于dom的一些html元素对放入它里面的元素有限制,所以导致有些组件没办法放在一些标签中,比如
在我们平时使用vue中的模板的时候,许多时候都是直接定义成一个固定的模板,但是,vue中提供了一个动态模板,可以在任意模板中切换,就是用vue中用:is来挂载不同的组件。
<component :is='...'></component>
...可以是已注册组件的名字或者是一个组件的选项对象
深入了解组件
组件
组件注册
组件名
注册一个组件的时候,需要给组件一个名字。
Vue.component('name',{/*...*/})
组件名大小写
定义组件名的两种方式:
- 使用kebab-case,短横线分隔命名法。使用kebab-case命名组件引用的时候也要使用该法
- 使用PascalCase 首字母大写命名。在引用组件的时候可以使用该两种方法都行。
全局注册
Vue.component创建的组件是全局注册组件,它们在注册之后可以用在任何新创建的Vue根实例的模板中。全局注册的行为必须在根Vue实例(通过new Vue)创建之前发生。
局部注册
通过一个普通的js对象来定义组件,然后在components选项中使用定义的组件
var ComponentA = {/*...*/}
new Vue({
components:{
'component-a':ComponentA
}
})
//对于components对象中的每个property来说,property名就是组件的名称,值就是这个自定义的组件。
//局部注册的组件在其子组件中是不可用的。使用局部注册的方式,如果要在某个组件内使用自定义的组件,要把它通过components注册到组件中。
模块系统 babel/webpack/es6
import componentA from './componentA'
export default {
components:{
componentA,
...
}
}
全局通用基础组件注册:https://cn.vuejs.org/v2/guide/components-registration.html#%E5%9F%BA%E7%A1%80%E7%BB%84%E4%BB%B6%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E5%85%A8%E5%B1%80%E6%B3%A8%E5%86%8C
Prop
prop的大小写(camelCase vs kebab-case)
HTML中的attribute名是大小写不敏感的,浏览器把所有大写转成小写。驼峰命名法的prop使用其等价的短横线分隔命名法。
静态prop 字符串 / 动态prop v-bind:
传入数字、布尔值、数组、对象时,就算这些是静态的,也要通过v-bind:告诉Vue这些是js表达式而不是字符串。
可以使用不带参数的v-bind传入一个对象的所有propety 作为prop。
test:{
id:1,
text:'this is test'
}
<component-a v-bind="test"></component-a>
等价于
<component-a v-bind:id="test.id" v-bind:text="test.text"></component-a>
单向数据流
所有的prop都使得其父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中,但是反过来不行!!!每次父级组件发生变更时,子组件中的prop值会刷新为最新的值。不要在子组件中改变prop!!!
两种常见的视图变更一个prop的情形:
1、使用prop传递进来一个初始值,子组件希望将其作为一个本地的数据使用,可以定义一个本地data property传入prop的值使用。
2、prop以原始值传入后需要进行转换,可以使用计算属性(computed)来操作。
注意:在js中,对象和数组是通过引用传递的。所以对于一个数组或对象类型的prop来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态,不允许这么操作。
Prop验证
props:{
propA:{//这些验证的选项不固定,可自由搭配
type:类型 //可能是多个类型,用数组的形式说明
default :默认值
required:是否必须
validator:Function 自定义验证函数,将该prop的值作为唯一的参数传入。
}
}
prop的验证会发生在一个组件实例创建之前,所以实例的property(如data\computed)在default/validator中是不可用的。
非Prop的Attribute
一个非prop的attribute是指传向一个组件,但是该组件并没有相应prop定义的attribute。这些attribute会被添加到这个组件的根元素上。
对于大多数attribute来说,外部提供给组件的值会替换掉组件内部设置好的值。对于class和style ,Vue会将它们进行合并。
如果你不希望组件的根元素(顶层标签元素)继承attribute,可以设置组件选项inheritAttrs:false。不管inheritAttrs为true或者false,子组件中都能通过$attrs属性获取到父组件中传递过来的属性。$attrs存储非prop特性,inheritAttrs控制vue对非prop特性默认行为。
自定义事件
事件名
不同于组件和prop,事件名不存在任何自动化的大小写转换。触发的事件名要完全匹配监听的事件名。事件名推荐使用短横线分隔法。v-on事件监听器在DOM模板中会被自动转换为全小写导致使用驼峰法的事件无法被监听到。
自定义组件的v-model
一个组件上的v-model默认会利用名为value的prop和名为input的事件。event
带有.sync修饰符的v-bind不能和表达式一起使用,也无法作用在一个字面量的对象上。
插槽
2.6.0后为具名插槽和作用域插槽引入了一个新的统一的语法:v-slot指令。取代了slot和slot-scope。
Vue实现了一套内容分发的API,将元素作为承载分发内容的出口。
<component-a>
this is slot text
</component-a>
component-a 组件中模板内容为:
<template>
<tag></tag>
<slot></slot>
</template>
当组件渲染时,如果有slot,那么开始组件标签中间的内容会取代slot ,slot有点像是占位符的意思。
如果组件的模板中没有slot元素,那么该组件起始标签和结束标签之间的任何内容都会被抛弃。
编译作用域
父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的。
后备内容
插槽标签中间可以添加默认的内容作为备选,如果父级提供了数据则显示父级提供的数据,否则显示默认的内容。
具名插槽
元素具有一个特殊的属性:name,通过名字可以定义额外的具名插槽(不带name的默认的name是default)。
<slot name='...'></slot>
<slot></slot> //默认是default
在向具名插槽提供内容的时候,我们可以在一个元素上使用v-slot指令,并以v-slot的参数的形式提供其名称。v-slot只能添加在上。下面有唯一的例外情况,见下文。
<template v-slot:name1>
name1 content
</template>
content default
<template v-slot:name2>
name2 content
</template>
在<template>元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有v-slot的<template>中的内容会被视为默认插槽的内容。
<template v-slot:default> 默认插槽另一种具体写法
作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的。
为了让子组件的属性能在父级的插槽内容中可用,将属性作为元素的一个属性进行绑定。绑定在元素上的属性被称为插槽prop。然后在父级作用域,可以使用带值的v-slot来定义提供的查查prop名字。
子组件:
<div>
<slot :attr1='attr1' :attr2="attr2" ...>
</slot>
</div>
父组件:
<template v-slot:default="attrs">
{{attrs.attr1...}}
{{attrs.attr2...}}
</template>
通过在父组件中定义的attrs去引用子组件上绑定的attr属性。attr相当于变成了attrs的一个属性。
当被提供的内容只有默认插槽时,没有声明具名插槽,组件的标签才可以当做插槽的模板来使用,而不是使用 (这是上面👆说的另外情况)
<compoent-name v-slot:default="slotProps">
<compoent-name v-slot="slotProps">
{{slotProps....}}
</compoent-name>
注意:只要出现了多个插槽,请始终为所有的插槽使用完整的基于的语法
解构插槽Prop
作用域插槽内部的工作原理是将你的插槽内容包括在一个传入单个参数的函数里。这意味着v-slot的值实际上可以是任何能够作为函数定义中的参数的js表达式。所以可以使用es6解构来传入具体的插槽prop。
<template v-slot="{...}">
...
</template>
{}中的内容可以重新命名,也可以定义默认值。
动态插槽名
动态指令参数也可以用在v-slot上,来定义动态的插槽名
<template v-slot=[dynamicSlotName]>...</template>
具名插槽的缩写
像v-on/v-bind, v-slot缩写是# v-slot:header -->#header。缩写只在其有参数的时候才可用。#=无效,也就是说#后面带明确的插槽名 ,#default表示默认插槽。
动态组件 & 异步组件
将组件进行缓存,缓存的组件都要有自己的名字。
异步组件/webpack
Vue允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
Vue.component('component-name',functin(resolve,reject){
resolve({
...
})
require(['...'],resolve)
})
工厂函数会收到一个resolve回调,这个回调函数会在你从服务器得到组件定义的时候被调用。reject表示加载失败。
Vue.component('component-name',() => import('...'))
处理边界情况(少用)
访问根实例
在每个new Vue实例的子组件中,其根实例可以通过$root进行访问。
访问父级组件实例
$parent可以用来从一个子组件访问父组件的实例。
访问子组件实例或子元素
可以通过$ref为子组件赋予一个ID引用。父组件引用:this.$refs.ID。
$refs只会在组件渲染完成之后生效,并且他们不是响应式的。
依赖注入
两个新的实例选项:provide和inject。
provide选项允许我们制定我们想要提供给后代组件的数据/方法。
在任何后代组件里,我们可以使用inject选项来接收指定的我们想要添加在这个实例上的property。
父级组件:
provide:function () {
return {
name:...,
}
}
后代组件:
inject:['...']
依赖注入可以看作是"大范围有效的prop",注意:
- 祖先组件不需要知道哪些后代组件要使用它提供的property
- 后代组件不需要知道被注入的property来自哪里
循环引用
组件是可以在它们自己的模板中调用自身的,容易引起递归调用无线循环的情况。当你使用Vue.componet全局注册一个组件时,这个全局的ID会自动设置为该组件的name选项。
组件间的循环引用。A依赖B,B依赖A。
模板定义的替代品
内联模板(不好理解)
当inline-template这个特殊的attribute出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容。内联模板需要定义的在Vue所属的DOM元素内。
X-Template
x-template需要定义在Vue所属的DOM元素外。
<script type="text/x-template" id="template-name">
<tag></tag>
</script>
Vue.component('component-name',{
template:'#template-name'
})
过渡 & 动画
重新单独看!!https://cn.vuejs.org/v2/guide/transitions.html
进入/离开 & 列表过渡
Vue在插入、更新或者移除DOM时,提供多种不同方式的应用过渡效果。包括以下工具:
- 在CSS过渡和动画中自动应用class
- 可以配合使用第三方CSS动画库
- 在过渡钩子函数中使用js直接操作DOM
- 配合使用第三方JS动画库
单元素/组件的过渡
Vue提供了transition的封装组件给任何元素和组件在条件渲染(v-if)/条件展示(v-show)/动态组件/组件根节点添加进入/离开过渡。
当插入或删除包含在transition组件中的元素时,Vue将会做以下处理:
1、自动嗅探目标元素是否应用了CSS过渡或动画,如果是,在恰当的时机添加/删除CSS类名。
2、如果过渡组件提供了JS钩子函数,这些钩子函数将在恰当的时机被调用
3、上述两个都没有,DOM操作(插入/删除)在下一帧中立即执行。
过渡的类名
在进入/离开的过渡中,会有6个class切换。
1、v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2、v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类被用来定义进入过渡的过程事件,延迟和曲线函数。
3、v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效,在过渡/动画完成之后移除。
4、v-leave:定义离开过渡的状态。在离开过渡被触发时立刻生效,下一帧被移除。
5、v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
6、v-leave-to:定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效,在过渡/动画完成之后移除。
v-是默认前缀,可以在transition中自定义名字name。
CSS过渡/动画
常用的过渡都是使用CSS过渡。
CSS动画用户同CSS过渡,区别是在动画中v-enter类名在节点插入DOM后不会立即删除,而是在animationed事件触发时删除。
自定义过渡的类名
通过以下attribute来自定义过渡类名:
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
深入响应式原理
当你把一个普通的js对象传入Vue实例作为data选项,Vue将遍历此对象所有的propery,并使用Object.defineProperty将这些property全部转为getter/setter。Object.defineProperty是ES5中一个无法shim的特性。这些getter/setter对用户是不可见的,但是在内部它们让Vue能够追踪依赖,在property被访问和修改时通知变更。
每个组件实例都对应一个watch实例,它会在组件渲染的过程中把"接触"过的数据property记录为依赖。之后当依赖项的setter触发时,会通知watcher,从而使它关联的组件重新渲染。
由于JS的限制,Vue不能检测数组和对象的变化。通过一些办法可以回避这些限制并保证他们的响应性。
对于对象
Vue无法检测property的添加或移除。由于Vue会在初始化实例时对property执行getter/setter转化,所以property必须在data对象上存在才能让Vue将它转换为响应式的。对于已经创建的实例,Vue不允许动态添加根级别的响应式property。不过,可以使用Vue.set()方法向嵌套对象添加响应式property。Vue.set()等价于vm.$set()实例方法。
对于数组
Vue不能检测以下数组的变动:
1、利用索引直接设置一个数组项时。 使用Vue.set(vm.$set)/vm.items.splice
2、修改数组的长度时。使用vm.items.splice(newLength)
声明响应式propery
由于Vue不允许动态添加根级响应式property,所以你必须在初始化实例前声明所有根级响应式property,哪怕只是一个空值。
异步更新队列
Vue在更新DOM时是异步执行的。只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。然后,在下一个事件循环’tick’中,Vue刷新队列并执行实际工作。Vue在内部对异步队列尝试使用原生的Promise.then\MutationObserver\setInnediate。如果环境不支持,则用setTimeout替代。为了在数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即使用Vue.nextTick(callback)。这样回调函数将在DOM更新完成后被调用。
在组件内使用vm.$nextTick()实例方法特别方便,它不需要全局Vue,并且回调函数中this将自动绑定到当前的Vue实例上。
Vue.component('component-name',{
this.$nextTick(function(){...})//$nextTick()返回一个Promise对象。
Vue.nextTick(function(){...})
})
可复用性 & 组合
混入
混入(mixin)提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被"混合"进入该组件本身的选项。
选项合并
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行’合并’。
- 数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
- 同名钩子函数将合并为一个数组,因此都将被调用。混入对象的钩子将在组件自身钩子之前调用。
- 值为对象的选项,如methods,components,将被合并为同一个对象,对象键名冲突时,取组件对象的键值对。
var mixin = {
data:function () {return {...}},//数据对象
created:function(){...}, //钩子函数
methods:{ //对象选项
func:function(){...}
}
}
new Vue({
mixins: [mixin],
data:...,
created:function(){...}
methods:{
func:function(){...}
}
})
Vue.extend()使用同样的策略进行合并。
混入也可以进行全局注册,但是会影响之后创建的每个Vue实例,要谨慎使用。
自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以向Vue.config.optionMergeStrategies添加一个函数。
Vue.config.optionMergeStrategies.myOption = function(toVal,fromVal) {
//返回合并后的值。
}
自定义指令
https://cn.vuejs.org/v2/guide/custom-directive.html
Vue.directive(‘directive_name’,{…})注册一个全局自定义指令。
组件接收一个directives选项来注册局部指令。
钩子函数
一个指令定义对象可以提供如下几个钩子函数(都是可选):
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用。
- update:所在组件的VNode更新时调用。
- componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
渲染函数 & JSX!!!
Vue推荐在绝大多数情况下使用模板来创建你的HTML。也可以通过JS使用渲染函数,它比模板更接近编译器。
虚拟DOM
Vue通过建立一个虚拟DOM来追踪自己要如何改变真实DOM。
createElement返回的不是一个实际的DOM元素。它更准确的名字可能是CreateNodeDescription,它所包含的信息会告诉Vue月面需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为"虚拟节点(virtual node)",简称"VNode"。"虚拟DOM"是我们对由Vue组件树建立起来的整个VNode树的称呼。
createElement参数
createElement{ //返回VNode节点
//一个HTML标签名、组件选项对象或者resolve了上述任何一种的一个async函数,必填项。
{String | Object | Function},
{Object}, //一个与模板中attribute对应的数据对象。可选。
{String | Array} //子级虚拟节点(VNode),由'createElement'构建,也可以使用字符串来生成"文本虚拟节点",可选。
}
组件树中所有VNode必须是唯一的。
可以通过this.$slots 访问静态插槽的内容,每个插槽都是一个VNode数组。可以通过this.$scopedSlots访问作用域插槽,每个作用域插槽都是一个返回若干VNode的函数。如果要用渲染函数向子组件中传递作用域插槽,可以利用VNode数据对象中的scopedSlots字段。
JSX
将h作为createElement的别名是Vue生态系统中的一个通用惯例,也是JSX的要求。
注意:在 2.3.0 之前的版本中,如果一个函数式组件想要接收 prop,则 props
选项是必须的。在 2.3.0 或以上的版本中,你可以省略 props
选项,所有组件上的 attribute 都会被自动隐式解析为 prop。
当使用函数式组件时,该引用将会是HTMLElement,因为它们是无状态的也是无实例的。
插件
使用插件
通过全局方法Vue.user()使用插件。它需要在你调用new Vue()启动应用之前完成。
Vue.user会自动阻止多次注册相同插件,多次调用也只会注册一次该插件。
开发插件
Vue.js的插件应该暴露一个install方法。这个方法第一个参数是Vue构造器,第二个参数是一个可选的选项对象。
Vue.use(MyPlugin)
new Vue({...})
MyPlugin.install = function(Vue,options){
Vue.directive('...'{...}),
Vue.mixin({...})
}
过滤器
Vue.js允许你自定义过滤器,可被用于一些常见的文本格式化。
过滤器可以用在两个地方:双花括号插值和v-bind表达式。过滤器应该被添加在JS表达式的尾部,由"管道"符号指示。
可以通过选项在组件中定义过滤器,也可以在创建Vue实例之前全局定义过滤器。
filters:{
filterName:function(value){...}
}
Vue.filter('filtername',function(vaule){...})
new Vue({...})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
过滤器函数总是接收表达式的值作为第一个参数。过滤器可以串联。过滤器也可以自定义参数,管道传过来的值会作为第一个参数。