另一个结果是,自定义标签(包括自定义元素和特殊标签,如 <component>、<template>、 <partial> )不能用在 ul, select, table 等对内部元素有限制的标签内。放在这些元素内部的自定义标签将被提到元素的外面,因而渲染不正确。
对于自定义元素,应当使用 is 特性:
<table>
<tr is="my-component"></tr> </table> //<template> 不能用在 <table> 内,这时应使用 <tbody>,<table> 可以有多个 <tbody> <table> <tbody v-for="item in items"> <tr>Even row</tr> <tr>Odd row</tr> </tbody> </table>
Props
使用props传递数据
组件实例的作用域是孤立的,可以使用props把数组传给子组件,props是组件数据的一个字段,期望从父组件传下来,子组件需要显式地用props选项声明props:
Vue.component('child', { // 声明 props props: ['msg'], // prop 可以用在模板内 // 可以用 `this.msg` 设置 template: '<span>{{ msg }}</span>' })
然后向它传入一个普通字符串:
<child msg="hello!"></child>
动态props
用v-bind绑定动态props到父组件的数据,每当父组件的数据变化时,也会传导给子组件:
<div> <input v-model="parentMsg"> <child v-bind:my-message="parentMsg"></child> //<child :my-message="parentMsg"></child> </div>
props绑定类型
prop默认是单向绑定,当父组件的属性变化时,将传导给子组件,但是反过来不会,这是为了防止子组件无意修改了父组件的状态,可以使用.sync或.once绑定修饰符显式地强制双向或单次绑定:
<!-- 默认为单向绑定 --> <child :msg="parentMsg"></child> <!-- 双向绑定 --> <child :msg.sync="parentMsg"></child> <!-- 单次绑定 --> <child :msg.once="parentMsg"></child>
如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。
父子组件通信
父链
子组件可以用this.$parent访问它的父组件,根实例的后代可以用this.$root访问它,父组件有一个数组this.$children,包含它所有的子元素
自定义事件
Vue实例实现了一个自定义事件接口,用于在组件树中通信,这个事件系统独立于原生DOM事件,用法也不同,每一个Vue实例都是一个事件触发器:
使用 $on() 监听事件;
使用 $emit() 在它上面触发事件;
使用 $dispatch() 派发事件,事件沿着父链冒泡;
使用 $broadcast() 广播事件,事件向下传导给所有的后代。
不同于 DOM 事件,Vue 事件在冒泡过程中第一次触发回调之后自动停止冒泡,除非回调明确返回 true。
<!-- 子组件模板 --> <template> <input v-model="msg"> <button v-on:click="notify">Dispatch Event</button> </template> <!-- 父组件模板 --> <div> <p>Messages: {{ messages | json }}</p> <child></child> </div> // 注册子组件 // 将当前消息派发出去 Vue.component('child', { template: '#child-template', data: function () { return { msg: 'hello' } }, methods: { notify: function () { if (this.msg.trim()) { this.$dispatch('child-msg', this.msg) this.msg = '' } } } }) // 初始化父组件 // 将收到消息时将事件推入一个数组 var parent = new Vue({ el: '#events-example', data: { messages: [] }, // 在创建实例时 `events` 选项简单地调用 `$on` events: { 'child-msg': function (msg) { // 事件回调内的 `this` 自动绑定到注册它的实例上 this.messages.push(msg) } } })
效果:
使用v-on绑定自定义事件
在模板中子组件用到的地方声明事件处理器,为此子组件可以用v-on监听自定义事件:
<child v-on:child-msg="handleIt"></child>
当子组件触发了 "child-msg" 事件,父组件的 handleIt 方法将被调用。所有影响父组件状态的代码放到父组件的 handleIt 方法中;子组件只关注触发事件。
子组件索引
使用v-ref为子组件指定一个索引ID,可以直接访问子组件
<div> <user-profile v-ref:profile></user-profile> </div> var parent = new Vue({ el: '#parent' }) // 访问子组件 var child = parent.$refs.profile
使用Slot分发内容
内容分发:混合父组件的内容与子组件自己的模板的方式,使用特殊的<slot>元素作为原始内容的插槽。
编译作用域
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
绑定子组件内的指令到一个组件的根节点: