1,选项资源: directives, filters, components
directives: Object;Vue实例可用指令的哈希表;directive实质上是个拥有几个生命周期的对象,不同周期阶段执行相应的逻辑;指令用于对普通DOM元素的底层操作,就像v-on指令对元素进行事件监听的操作一样;directives是个对象,属性名是每个指令的name,每个属性值是指令的定义,可以是定义了指令生命周期钩子回调的对象,也可以是函数,若是函数,则该函数被当作bind和update的生命周期钩子的回调;与全局API Vue.directive一样的定义;
指令生命周期钩子:bind(只调用一次,在指定绑定到元素上时调用,在这里可以进行一次性的初始化设置,比如style,比如innerHTML等),inserted(在被绑定元素插入父节点时调用,只能保证父节点的存在,不能保证父节点已插入文档中),update(在所在组件开始更新时调用,可能发生在子组件更新前,指令的值可能发生了改变,也可能没有),componentUpdated(所在组件及其所有子组件都完成更新之后调用),unbind(在所在组件被销毁时调用,只调用一次);
指令生命周期钩子函数的参数:el(被绑定的元素),binds,vnode(虚拟节点),oldVnode(update和componentUpdated,可用,其他情况下是个没有信息的VNode对象);
参数binds是个对象拥有这些属性:def(是个Object,包含指令生命周期钩子函数,算是存储指令的定义),rawName(绑定在元素上的除了expression的部分如v-test:[value].bar), name(指令的名称,如test), arg(传给指令的参数,一般指冒号后的部分,不包括修饰符和表达式), oldArg(update和componentUpdated中可用), value(指令绑定的值,表达式的值), oldValue(同oldArg,是value的旧值), expression(指令绑定的表达式),modifiers(修饰指令的修饰符)
//用以下例子作为分析数据------------------
//例1html,动态参数名,有修饰符,表达式是实例的一个状态value,值是'for test'
//此时的binds:{arg='value',value='for test',expression:'value',modifiers:{bar:true},
//name: 'test',rawName:'v-test:[argName].bar',def:{...} }
<input v-test:[argName].bar="value"/>
//改变组件状态,引起组件的更新,此时的binds:
//{arg='color',value='white',oldArg='value',oldValue='for test',expression:'value',
//modifiers:{bar:true},name: 'test',rawName:'v-test:[argName].bar',def:{...} }
<button @click="changeProps">click</button>
//例2html ---------------
//此时的binds:{arg='haha',value='for test',expression:'value',modifiers:{bar:true},
//name: 'test',rawName:'v-test:haha.bar',def:{...} }
<input v-test:haha.bar="value">
//此时的binds:
//{arg='haha',value='white',oldArg='haha',oldValue='for test',expression:'value',
//modifiers:{bar:true},name: 'test',rawName:'v-test:haha.bar',def:{...} }
<button @click="changeProps">click</button>
{
data: {
argName: 'value',
value: 'for test',
},
methods: {
changeProps: function(){
this.argName = "color";
this.value="white";
}
},
directives: {
test: { //每一个生命周期钩子都是可选的;
bind: function(el, binds, vnode, oldVnode){
el.style.backgroundColor = 'pink';
if(binds.arg === 'value'){
el.value = binds.value;
}
},
inserted: function(el, binds, vnode, oldVnode){
el.focus();
},
updated: function(el, binds, vnode, oldVnode){
if(binds.arg === 'value'){
el.value = binds.value;
}
if(binds.arg === 'color'){
el.style.color = binds.value;
}
},
componentUpdated: function(el, binds, vnode, oldVnode){
},
unbind: function(el, binds, vnode, oldVnode){
}
},
hello: function(el, binds, vnode, oldVnode){ //会被赋给生命周期钩子bind和update
///do something
}
}
}
filters:Object;Vue实例可用指令的哈希表;filter实质上是一个可以接受参数的函数,用于管道符后面,一般是用于对传入的数据进行修改,返回一个任意值;跟Vue.filter定义一个过滤器一样;filter除了接收管道的数据流之后,还可以接收手动传递的数据,所以在使用fliter时,可以传参数;
//定义filter -----------------------
{
filters: {
camelToKebabCase: function(val){
if(!val || typeof val !== 'string'){
return val;
}
return val.replace(/[(A-Z)]/g, '-' + '$&').toLowerCase();
}
}
}
//使用filter, 字符串'testForCase'将作为第一个参数传入 filter
<div>{{ 'testForCase' | camelToKebabCase }}</div>
//最终的编译结果是
<div> test-for-case </div>
//若想额外在传入一些参数,可以这样使用filter:字符串'test'将作为filter的第二个参数
<div>{{ 'testForCase' | camelToKebabCase('test') }}</div>
components:Vue实例可用组件的哈希表;组件选项的component是个组价选项对象也可以是继承于Vue的组件构造器;跟Vue.component一样,另外如果传入的是个Promise的回调函数,可以定义一个异步组件;
//component的定义:可以是由Vue.extend生成的Vue的子类(作为该类组件的构造函数),
//也可以是一个定义了组件选项的对象:
//其实还有很多其他的组件选项可设置,可以参考其他文档;
var compCtor = Vue.extend({
template: '<div>test</div>'
data: function(){
return {test: 'test', obj: {hello:'hello'}};
}
});
var compFn = {
functional: true, //当functional === false,它是个由状态有实例的组件
render(h){
return h('div', ['test text']);
}
},
//
var parentComp = {
//...
components: {
compFn,
compCtor
}
//...
}
2, 选项组合:parent(parent是什么,做什么用的), extends, mixins, provide/inject(这两个又是做什么)
parent:Vue instance;父实例,一般用不到(若使用,该怎么用?为什么用?);
extends:Object|Function;组件扩展,实质上也是组件选项合并;
mixins:Array<Object>;组件选项合并;
provide/inject:两者需要一起使用,provide是在父组件中提供的内容,inject是在子组件注入父组件提供的内容(主要是用key搜索);provide/inject的绑定不是响应的,但如果传入了一个可监听的对象,那么这个对象的property是响应式的;这意味着,传入provide的非响应式数据(无论是原始数据还是对象)的更新都不会触发inject的更新;
provide:Object|()=>Object;
inject:Array<string>|{[key: string]: string|symbol|Object};若是key是string或symbol,则属性值是在provide提供的对象能找得到的属性;若是Object则它的值是个拥有from、default属性的对象{from: string|symbol, default: string|symbol};from property的值是提供内容的对象的属性,default是当找不到key时使用的降级策略,即使用default作为数据;
//使用例子:
//当provide是个返回对象的函数时可以访问实例的状态(data,props, computed, methods),
//因为provide在state初始之后初始的,在created钩子执行之前;
var perentComp={
data: function(){
return {obj: {prop: 'prop'}}
},
provide: {
test: 'hello',
obj: this.obj //provide传入了一个响应式对象,若该对象属性改变,会触发响应inject的更新
}
}
//以下对inject的使用需要在2.2.1版本以及之后,否则在props和data中会拿不到injections,
//因为它们会在data/props初始化之后拿到;
//之后版本会在生命周期钩子beforeCreate之后,initState(props、data、computed、methods)之前
var childComp = {
inject: ['test']; //还能是{test: {from: 'test', default: 'default value'}}
//当provide不存在key'test'时,默认使用default的值this.test = default
//default的支持是在2.5以及之后的版本。
props: {
value: {
default: function(){
return this.test; //'hello'
}
}
},
data: function(){
return {putong: this.test};//hello
}
}
//使用场景:用于父组件向子孙组件传递数据,在需要跨多个嵌套的组件传递数据时,使用provide/inject
//定义组件可以做到;就不用手动地向下地向子组件一层层地通过prop传递数据了,可以直接跳过中间的组件
//就像这样:childComp可利用provide/inject直接从parentComp拿到数据;
<parent-comp>
<child>
<child-level2>
<child-level3>
<child-comp>
<!--something here-->
<div><div>
</child-comp>
</child-level3>
</child-level2>
</child>
</parent-comp>
3, 选项其他:name, inheritAttrs, comments(这是做什么用的), funtional, model(model是什么,做什么用的?), delimiters(这是什么,又是什么类型的)
name:string;组件的名称,可以跟父组件的components选项的属性名不一样;只有作为组件选项时起作用;允许组件模板递归地调用自身,不过要小心造成无限递归,要有条件地递归调用;
inheritAttrs:Boolean;表示组件模板的根元素要不要继承组件上的attributes,inheritAttrs不影响style和class的继承;可以与实例属性$attrs一起使用;
comments:Boolean,默认值false; 当它为true时,保留并渲染模板中的HTML的注释,否则舍弃这些注释;使用限制在完整构建版中的浏览器内编译时有效(啊,这什么情况?);
functional:Boolean;表示该组件是否是函数组件,函数组件没有实例,因此也没有实例缓存数据(函数组件在keep-alive下不可用),所以函数组件比较简单,就只有{funtional:true,render: fn, props: [],inject:[] }可用;render是必须的,render返回虚拟节点可使它们的渲染代价更小;props可选,在2.3.0版本之前,若要使用props需要显式指定props,2.3.0之后不需要,Vue会将函数组件上非事件绑定非class非style非指令非特殊attributes(特殊attributes会作为上下文的data属性的属性传入)作为上下文的props,也存在上下文的data的attrs;如果提供了props了,那么只会传入指定的props,不在props的attributs在继续留在attrs中;绑定的事件会存储在上下文的listeners(data.on的别名)以及data.on里,用.native修饰的事件监听会存储在data.nativeOn中,只是有一点需要注意的是,如果用render创建的根元素不是组件而不是原生DOM元素则会报错说.native修饰的v-on指定应该绑定在组件上;对函数组件的引用 ref会是个HTMLElement,因为函数组件没有实例;
//函数组件的使用;函数组件,render中的this不可用,所以render函数有第二个参数context;----
函数组件中render函数;
var functionalComp= {
functional: true, //这是必须的
//props: [], 可选;
//inject: [], //若提供,则context的injections有值
render( h, context){
//context.data会作用在div上,
//传参给context.scopedSlots.foo,参数是插槽内容的作用域
return h('div', context.data, [...context.scopedSlots.foo({test: 'hahaha'}), ...context.slots().default]);
}
};
//函数组件的使用
<functional-comp>
<template v-slot:foo="item">
<span>{{item.test}}</span>
</template>
<div>
<button>click</button>
</div>
</functional-comp>
//context有哪些主要的属性: -----------------
//data(Object,包含很多数据,主要是组件上的attributes,除scopedSlots外),
//slots(Function,返回包含非作用域插槽的对象,插槽具名作为对象key,值是VNode数组;总包含default),
//$slots(Object,同上)
//scopeSlots(Object,插槽具名作为对象的key,值是返回插槽内容(Array<VNode>)的函数,可给函数传参),
//props(当没有指定选项的props时,它是函数组件的普通attributes,若是指定,则只含指定的props),
//listeners(用v-on绑定在组件上的事件及其监听器,不包括用.native修饰的事件)
//parent(父实例或父元素),
//children(那些没有绑定v-slot和slot-scope的函数组件的子节点,否则为undefined),
//injections;组件选项inject注入的父组件提供的内容,是个对象,键值对,值来自父组件提供的内容;
//data的主要属性:---------------------
//attrs(Object,属性来自组件上的attributes,若props指定某些props,
//那么这些props不会出现在attrs对象中.
//on(Object, 绑定在组件上的事件监听器,不包含由.native修饰的事件)
//nativeOn(Object, 由.native修饰的v-on事件监听器)
//ref(组件上的ref attr)
//key等特殊attributes,
//class(动态绑定的,可能是个数组或字符串,如['testCls']),
//style(动态绑定的,是个对象,如{color'white'}),
//staticStyle(静态的,是个对象,如{'background-color': 'pink'}),
//staticClass(静态的,可能是个字符串或者数组),
//scopedSlots(Object,是个对象,每个属性值都是个函数);
delimiters:Array<string>;改变纯文本插入分隔符,默认是['{{', '}}'];只在完整构建版中地浏览器编译有效;改成ES6模板字符串的风格:delimiters: ['${', '}'];ES6中用反引号``括起`${test}`,test是个变量;
model:Object({prop:?string, event:?string});与组件上的v-model指令有挂;可以改变组件上的v-model的默认行为,自定义组件上的v-model默认把value当作prop把input事件当作event,这样用在type=text控件上没什么问题(当然用修饰符.lazy改成监听change事件而不是input),但是在复选框或单选框会有些出入,因为它们希望用checked prop和change事件;于是
//
var myComp = {
name: 'my-comp',
model: {
prop: 'checked', //改变v-model默认绑定的prop
event: change //改变v-model默认绑定的事件
},
props: ['checked'], //总是要用props接收组件上的props;
template: '<input :checked="checked" @change="$emit('change', $event.target.checked)" />'
}
//原本在组件上的v-model
<my-comp v-model='test'></my-comp>
//经过model的修改,相当于以下这句;但如果直接用下面这句,那么也就不会使用model选项了;
<my-comp :checkd="test" @change="test=$event;"></my-comp>
4,参考文档: