Vue组件
组件需要注册后才可以使用,注册分为全局注册和局部注册。
全局注册
全局注册后任何Vue
实例都可以使用,子组件必须在父实例创建前注册。
Vue.component('component-name', {
template: '<div>{{ message }}</div>',
data: function () {
return {message: '组件内容'}
}
});
component-name
是组件的自定义标签名称,推荐使用小写字母加减号分割的形式命名。
Vue.component
方法的第二个参数是一个对象字面量,可以包含template
、data
、computed
、methods
等选项。其中data
定义组件数据,必须是函数;template
选项的值必须被一个html元素包裹
局部注册
app = new Vue({
el: '#app',
components: {
'component-name': {
template: ''
}
}
});
在Vue
实例中使用components
选项局部注册组件,注册后的组件只在该实例作用域下有效。
组件通信
所谓通信即组件之间传递数据,组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信。
父组件向子组件传递数据
组件的props
选项声明从父级接受的数据,props
选项既可以是字符串数组也可以是对象。
父级向子组件传递数据,可分为3步:
- 父组件使用子组件时,在子组件标签添加数据属性
- 子组件
props
选项声明从父级接受的数据 - 在子组件中应用从父级接受的数据
<div id="app">
<my-component message="来自父组件的数据"></my-component>
</div>
<script>
Vue.component('my-component', {
template: '<div>{{ message }}</div>',
props: ['message']
});
var app = new Vue({
el: '#app'
});
</script>
props
选项传入一个对象类型,对从父级接受的数据进行校验。
子组件向父组件传递数据
Vue通过自定义事件,实现子组件向父组件传递数据:
- 子组件通过
$emit(eventName, eventArgument)
方法触发自定义事件 - 父组件使用子组件时,在子组件标签使用
v-on
指令监听自定义事件
<div id="app">
<my-component @shownumber="handleShownumber"></my-component>
<p>数值:{{ total }}</p>
</div>
<script>
Vue.component('my-component', {
template: '<div @click="handleAdd"></div>',
data : function () {
return {counter : 0};
},
methods : {
handleAdd: function () {
this.counter++;
this.$emit('shomnumber', this.counter);
}
}
});
var app = new Vue({
el: '#app',
data: {
total: 0
},
methods: {
handleShownumber: function (total) {
this.total = total;
}
}
});
</script>
可以通过v-model
替代步骤2中的v-on
的事件监听
<div id="app">
<my-component v-model="total"></my-component>
<p>数值:{{ total }}</p>
</div>
<script>
Vue.component('my-component', {
template: '<div @click="handleAdd"></div>',
data : function () {
return {counter : 0};
},
methods : {
handleAdd: function () {
this.counter++;
this.$emit('shomnumber', this.counter);
}
}
});
var app = new Vue({
el: '#app',
data: {
total: 0
}
});
</script>
中央事件总线
- 创建空的Vue实例,作为中央事件总线
- 子组件触发事件时,指定事件发起者为中央事件总线($emit方法的调用方是中央事件总线实例)
- 父组件在
mounted
钩子函数里监听来自中央事件总线的事件
<div id="app">
<my-component></my-component>
<p>数值:{{ total }}</p>
</div>
<script>
var bus = new Vue();
Vue.component('my-component', {
template: '<div @click="handleAdd"></div>',
data : function () {
return {counter : 0};
},
methods : {
handleAdd: function () {
this.counter++;
bus.$emit('shomnumber', this.counter);
}
}
});
var app = new Vue({
el: '#app',
data: {
total: 0
},
mounted: function () {
var _this = this;
bus.$on('shownumber', function (total) {
_this.total = total;
})
}
});
</script>
内容分发:slot
具名插槽
子组件模板中的<slot>
标签添加name
属性指定插槽名字
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
父组件分发的内容包裹在<template>
中,使用 v-slot
指令 指定分发的插槽名字
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
<template>
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot
的 <template>
中的内容都会被视为默认插槽的内容 .
v-slot
只能添加在 <template>
元素上
作用域插槽
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
为了让父级中的插槽内容能访问子组件数据,引入作用域插槽:
- 子组件
<slot>
元素绑定子组件数据
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
绑定在 <slot>
元素上的 attribute 被称为插槽 prop
- 父组件使用
v-slot
访问子组件绑定的插槽prop
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
所有插槽prop会绑定到slotProps
变量上