1 组件
- 组件可以扩展 HTML 元素,封装可重用的代码
- 组件参数的data值必须是函数,要求返回一个对象.。所以各个组件的数据私有,值相互独立,即每个实例可以维护一份被返回对象的独立的拷贝。
- 组件模板必须是单个根元素(html标签有一个顶级根元素,不能是兄弟节点)
- 组件模板的内容可以是模板字符串``((ES6语法))
- 命名:短横线(my-component)和驼峰式(MyComponent)—建议使用短横线
- 全局组件是component,没有s的;而局部组件是components,是有s的
全局组件
全局组件注册后,任何vue实例都可以用
定义:
Vue.component(组件名称, {
data: 组件数据(data的值必须是函数),
template: 组件模板内容
})
使用方式:
(1)注册
<script type="text/javascript">
//全局组件
// 注册一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function(){
return {
count: 0
}
},
template: '<button @click="handle">点击了{{count}}次</button>',
//组件里也可以定义自己的方法
methods: {
handle: function(){
this.count += 2;
}
}
});
//vm是一个vue实例
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
(2)使用
<div id="app">
<!-- 无论组件在注册时采用短横线还是驼峰命名,在html中使用组件必须使用短横线的命名方式 -->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
效果:
局部组件
只能在当前注册它的vue实例(它的父组件)中使用
定义:
var ComponentA = { /* data...template... */ }
var ComponentB = { /* data...template... */ }
var ComponentC = { /* data...template... */ }
new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB,
'component-c': ComponentC,
}
})
使用方式:
(1)注册
<script type="text/javascript">
//1 定义组件
var HelloWorld = {
data: function(){
return {
msg: 'HelloWorld111'
}
},
template: '<div>{{msg}}</div>'
};
var HelloTom = {
data: function(){
return {
msg: 'HelloTom222'
}
},
template: '<div>{{msg}}</div>'
};
var HelloJerry = {
data: function(){
return {
msg: 'HelloJerry333'
}
},
template: '<div>{{msg}}</div>'
};
var vm = new Vue({
el: '#app',
data: {
},
//2 局部注册
components: {
'hello-world': HelloWorld,
'hello-tom': HelloTom,
'hello-jerry': HelloJerry
}
});
</script>
(2)使用
<div id="app">
<hello-world></hello-world>
<hello-tom></hello-tom>
<hello-jerry></hello-jerry>
</div>
效果:
2 组件之间的数据传值
父组件向子组件传值
- 父组件通过属性将值传递给子组件
- 子组件用属性props接收(props传递数据原则:单向数据流 父->子)
<div id="app">
<div>{{pmsg}}</div>
<!--2 为子组件绑定父组件的属性值 -->
<!-- 父组件(vm实例)通过属性title将值传递给子组件(menu-item) -->
<menu-item title='来自父组件的值'></menu-item>
<!-- 父组件通过属性title和content将值传递给子组件 ,title的值ptitle来自父组件data 中的数据,
传的值可以是数字、布尔、字符串、对象、数组 -->
<menu-item :title='ptitle' content='hello'></menu-item>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('menu-item', {
//3 子组件用props接收数据
//子组件用属性props接收title和content
props: ['title', 'content'],
data: function() {
return {
msg: '子组件本身的数据'
}
},
template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
});
var vm = new Vue({
el: '#app',
data: {
//1 要传递给子组件的数据
pmsg: '父组件中内容',
ptitle: '动态绑定属性'
}
});
</script>
效果:
子组件向父组件传值
- 子组件通过自定义事件 $emit(arg1,arg2) 向父组件传递信息
- arg1是自定义的事件名称 ,arg2是需要传递的数据
- 父组件用 v-on:arg1或者@arg1 监听子组件的事件
<div id="app">
<div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
<menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
//子组件
//子组件用$emit(自定义的事件名称,传递的数据)触发事件
Vue.component('menu-item', {
props: ['parr'],
template: `
<div>
<ul>
<li :key='index' v-for='(item,index) in parr'>{{item}}</li>
</ul>
<button @click='$emit("enlarge-text",5)'>子组件1,扩大5px</button>
<button @click='$emit("enlarge-text",10)'>子组件2,扩大10px</button>
</div>
`
});
//父组件
var vm = new Vue({
el: '#app',
data: {
pmsg: '父组件中内容',
parr: ['apple','orange','banana'],
fontSize: 10
},
methods: {
handle: function(val){
// 扩大字体大小
this.fontSize += val;
}
}
});
</script>
效果:
兄弟组件之间的传值
- 单独的事件中心管理组件间的通信:var eventHub = new Vue()
- 监听事件:eventHub.$on(‘add-todo’, addTodo)
mounted时监听
- 触发事件:eventHub.$emit(‘add-todo’, id)
- 销毁事件:eventHub.$off(‘add-todo’)
<script type="text/javascript">
// 1 事件中心
var hub = new Vue();
//子组件1
Vue.component('test-one', {
data: function(){
return {
num: 0
}
},
template: `
<div>
<div>子组件1:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function(){
//3 触发事件(这里触发兄弟组件2的事件)
hub.$emit('second-event', 2);
}
},
mounted: function() {
//2 监听事件
hub.$on('first-event', (val) => {
this.num += val;
});
}
});
//子组件2
Vue.component('test-two', {
data: function(){
return {
num: 0
}
},
template: `
<div>
<div>子组件2:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function(){
// 触发事件(这里触发兄弟组件1的事件)
hub.$emit('first-event', 1);
}
},
mounted: function() {
hub.$on('second-event', (val) => {
this.num += val;
});
}
});
var vm = new Vue({
el: '#app',
data: {
},
methods: {
handle: function(){
// 4 销毁事件
hub.$off('first-event');
hub.$off('second-event');
}
}
});
</script>
<div id="app">
<div>父组件</div>
<div>
<button @click='handle'>销毁事件</button>
</div>
<test-one></test-one>
<test-two></test-two>
</div>
3 组件插槽
作用:父组件向子组件传递内容
<div id="app">
<!-- 这是在父组件中 -->
<!-- 插槽的内容在父组件里 -->
<alert-box>有bug发生</alert-box>
<alert-box>有一个警告</alert-box>
<alert-box></alert-box>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
//子组件
//插槽的位置在子组件的template里
Vue.component('alert-box', {
template: `
<div>
<strong>ERROR:</strong>
<slot>默认内容</slot>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
}
});
</script>
具名插槽
在组件base-layout的template中定义如下:
<div>
<header>
<slot name='header'></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name='footer'></slot>
</footer>
</div>
html中使用:
<!-- 使用方式一 -->
<base-layout>
<p slot='header'>标题信息</p>
<p>主要内容1</p>
<p>主要内容2</p>
<p slot='footer'>底部信息信息</p>
</base-layout>
<!-- 使用方式二 -->
<base-layout>
<template slot='header'>
<p>标题信息1</p>
<p>标题信息2</p>
</template>
<p>主要内容1</p>
<p>主要内容2</p>
<template slot='footer'>
<p>底部信息信息1</p>
<p>底部信息信息2</p>
</template>
</base-layout>
作用域插槽
应用场景: 父组件对子组件的内容进行加工处理
<div id="app">
<!--2 子组件中绑定属性,值为fruitlist -->
<fruit-list :list='fruitlist'>
<!-- 通过slotProps可以拿到子组件中插槽传过来的数据slotProps.info -->
<template slot-scope='slotProps'>
<!-- 如果id为3,加样式 -->
<strong v-if='slotProps.info.id==3' class="current">{{slotProps.info.name}}</strong>
<!-- 否则,显示普通样式 -->
<span v-else>{{slotProps.info.name}}</span>
</template>
</fruit-list>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component('fruit-list', {
// 3 子组件使用props属性接收传的值
props: ['list'],
template: `
<div>
<li :key='item.id' v-for='item in list'>
<slot :info='item'>{{item.name}}</slot>
</li>
</div>
`
});
var vm = new Vue({
el: '#app',
data: {
// 1 父组件中的数据fruitlist
fruitlist: [{
id: 1,
name: 'apple'
},{
id: 2,
name: 'orange'
},{
id: 3,
name: 'banana'
}]
}
});
</script>
.current {
color: orange;
}