1. 过渡
Vue.js 提供过渡系统,为DOM元素在插入/删除时提供动画过渡效果。
http://www.w3school.com.cn/css3/css3_transition.asp
How to use:
<div v-if="show" transition="expand"></div>
1.尝试以 ID "expand" 查找 JavaScript 过渡钩子对象——通过 Vue.transition(id, hooks) 或 transitions 选项注册。如果找到了,将在过渡的不同阶段调用相应的钩子。
2.自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
3.如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作(插入/删除)在下一帧中立即执行。
方式 1. CSS:
/* 必需 */
.expand-transition {
transition: all .3s ease;
height: 30px;
padding: 10px;
background-color: #eee;
overflow: hidden;
}
/* .expand-enter 定义进入的开始状态 */
/* .expand-leave 定义离开的结束状态 */
.expand-enter, .expand-leave {
height: 0;
padding: 0 10px;
opacity: 0;
}
方式2. JS:
Vue.transition('expand', {
beforeEnter: function (el) {
el.textContent = 'beforeEnter'
},
enter: function (el) {
el.textContent = 'enter'
},
afterEnter: function (el) {
el.textContent = 'afterEnter'
},
enterCancelled: function (el) {
// handle cancellation
},
beforeLeave: function (el) {
el.textContent = 'beforeLeave'
},
leave: function (el) {
el.textContent = 'leave'
},
afterLeave: function (el) {
el.textContent = 'afterLeave'
},
leaveCancelled: function (el) {
// handle cancellation
}
})
正如前文所述,Vue.js 允许自定义组件,并以html的形式使用:
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>'
})
Vue.component('my-component', MyComponent)
<div id="example">
<my-component></my-component>
</div>
<!-- 将被渲染为 -->
<div id="example">
<div>A custom component!</div>
</div>
如果每个组件只是为其父组件使用,可以使用下述用法:
var Child = Vue.extend({ /* ... */ })
var Parent = Vue.extend({
template: '...',
components: {
// <my-component> 只能用在父组件模板内
'my-component': Child
}
})
为了简化Vue.extend的使用,可以使用下述用法,Vue.js将会自动检测并调用Vue.extend:
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// 局部注册也可以这么做
var Parent = Vue.extend({
components: {
'my-component': {
template: '<div>A custom component!</div>'
}
}
})
为了使得组件不共享同一份data,要求data属性必须返回一个函数对象:
var MyComponent = Vue.extend({
data: function () {
return { a: 1 }
}
})
- a 不能包含其它的交互元素(如按钮,链接)
- ul 和 ol 只能直接包含 li
- select 只能包含 option 和 optgroup
- table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup
- tr 只能直接包含 th 和 td
父子组件
事实上,组件的作用域是独立的,也就是子组件并不能直接访问父组件的属性。但可以使用Props显示声明需要被传递的属性,这样子组件就可以获取到父组件的属性。Vue.component('child', {
// 声明 props
props: ['msg'],
// prop 可以用在模板内
// 可以用 `this.msg` 设置
template: '<span>{{ msg }}</span>'
})
<child msg="hello!"></child>
如果需要传递一个动态地属性,那么需要使用v-bind:
<div>
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
</div>
<!-- 简写 -->
<child :my-message="parentMsg"></child>
动态属性默认是单向的,也就是父组件的变化会传递给子组件,但不会从子组件到父组件,但也可以通过选项开启:
<!-- 默认为单向绑定 -->
<child :msg="parentMsg"></child>
<!-- 双向绑定 -->
<child :msg.sync="parentMsg"></child>
<!-- 单次绑定 -->
<child :msg.once="parentMsg"></child>
虽然父子组件可以通过变量进行相互通讯,但显然这是不够的,也会让某些功能的实现显得生硬,例如:
子组件变更了属性A,父组件需要监听属性A的变化进行一系列动作。
但通常这种事情应该使用事件来完成,所幸Vue.js提供了事件通讯机制:
- 使用 $on() 监听事件;
- 使用 $emit() 在它上面触发事件;
- 使用 $dispatch() 派发事件,事件沿着父链冒泡;
- 使用 $broadcast() 广播事件,事件向下传导给所有的后代。
也可以使用events来快速绑定事件监听
events: {
'child-msg': function (msg) {
// 事件回调内的 `this` 自动绑定到注册它的实例上
this.messages.push(msg)
}
}
也可以使用v-on
<child v-on:child-msg="handleIt"></child>
对于父子组件而言,作用域是一个会让我们混淆的部分:
<child-component>
{{ msg }}
</child-component>
这是一个组件在调用子组件,并在子组件的HTML标签内嵌入了一段需要编译的内容,那么这段需要编译的内容属于谁?
答案是父组件,msg会被绑定到父组件的变量中,同样的:
<child-component v-show="someChildProperty"></child-component>
v-show对应的变量也需要在父组件中指定,如果需要在子组件指定,必须这样:
Vue.component('child-component', {
// 有效,因为是在正确的作用域内
template: '<div v-show="someChildProperty">Child</div>',
data: function () {
return {
someChildProperty: true
}
}
})
从而我们可以看到,内容是在当前的组件内进行编译的。
另一种父子内容传递的机制如下:
<!-- 子组件 -->
<div>
<slot name="one"></slot>
<slot></slot>
<slot name="two"></slot>
</div>
<!-- 父组件 -->
<multi-insertion>
<p slot="one">One</p>
<p slot="two">Two</p>
<p>Default A</p>
</multi-insertion>
<!-- 渲染结果 -->
<div>
<p slot="one">One</p>
<p>Default A</p>
<p slot="two">Two</p>
</div>
- prop 允许外部环境传递数据给组件;
- 事件 允许组件触发外部环境的 action;
- slot 允许外部环境插入内容到组件的视图结构内。