什么是组件:
组件的出现是为了拆分vue实例的代码量,能够让我们以不同的组件来划分不同的功能。这样我们需要什么样的功能只需要调用对应的组件即可
定义组件名的方式:
//短横线分隔命名,单词之间使用短横线相连
Vue.component('my-component-name', { /* ... */ })
//首字母大写命名,每个单词的首字母大写
Vue.component('MyComponentName', { /* ... */ })
全局注册(常用)
全局注册的组件在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。除此之外组件在各自内部也都可以相互使用
Vue.component('my-component-name', {
// ... 选项 ...
})
局部注册(不常用)
局部注册可以减少用户下载的 JavaScript (用不到的全局注册的组件)的无谓的增加。用法格式:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
补充:
无论是全局注册还是局部注册,模板可以单独定义,然后引用即可
//模板
<template id="name">
<div>
<h2>这样也可以</h2>
</div>
</template>
//全局注册为例
Vue.component('my-component-name', {
template:'#name'
})
示例:全局注册
<!-- 把这个组件作为自定义元素来使用 -->
<div id="app">
<button-count></button-count>
<button-count></button-count>
</div>
<script>
Vue.component('button-count', { //定义一个名为 button-counter 的新组件
data: function() {
return { //返回一共对象
count: 0
}
},
template: '<button v-on:click="count++">您点击了{{count}}次</button>' //定义该组件的模板
})
var vm = new Vue({
el: '#app'
})
</script>
1、 组件是可复用的vue实例,且带有一个名字。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用。
2、 因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。
3、 组件可以进行任意次数的复用,并且相互之间独立,因为你每用一次组件,就会有一个它的新实例被创建。
4、 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
示例:局部注册
<div id="app">
<button-counter></button-counter>
</div>
<script>
var ComponentA = {
data: function() {
return {
count: 0
}
},
template: '<button v-on:click="count++">{{count}}</button>'
}
new Vue({
el: '#app',
components: {
'button-counter': ComponentA
}
})
</script>
对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
注: 局部组件局部注册的组件在其子组件中不可用。
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织,一个组件同时可以嵌套其它的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的
Vue.component('my-component-name', {
// ... options ...
})
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
组件切换
vue提供了component来展示不同的组件,component是一个占位符,:is用来指定要展示组件的名称(要加单引号引起来,组件名是字符串,而双引号代表表达式)
<component :is="'login'"></component>
实例:登录与注册组件的切换
<template id="login">
<p>这里是登录页面</p>
</template>
<template id="register">
<p>这里是注册页面</p>
</template>
<div id="app">
<a href="" @click.prevent="change('login')">登录</a>
<a href="" @click.prevent="change('register')">注册</a>
<component :is="component_name"></component>
</div>
<script type="text/javascript">
Vue.component('login', {
template: '#login'
})
Vue.component('register', {
template: '#register'
})
new Vue({
el: '#app',
data: {
component_name: 'login'
},
methods: {
change(name) {
this.component_name = name
}
}
})
</script>
通过 Prop 向子组件传递数据
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property
示例一: 给博文组件传递一个标题
<div id="app">
<blog-post title="标题一"></blog-post>
<blog-post title="标题二"></blog-post>
</div>
<script>
Vue.component('blog-post', {
props: ['title'],
template: '<h2>{{title}}</h2>'
})
var vm = new Vue({
el: '#app'
})
</script>
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。并且我们能够在组件实例中访问这个值,就像访问 data 中的值一样。
除此之外我们还可以使用 v-bind 来动态传递 prop
示例二: data 里有一个博文的数组
<div id="app">
<blog-post v-for="item in message" v-bind:id="item.id" v-bind:title="item.title"></blog-post>
</div>
<script>
Vue.component('blog-post', {
props: ['title'],
template: '<h2>{{title}}</h2>'
})
var vm = new Vue({
el: '#app',
data:{
message:[
{id:1,title:"Javascript"},
{id:2,title:"Jquery"},
{id:3,title:"Vue"}
]
}
})
</script>
单个根元素
当构建一个组件时,模板中不可能只有单个元素,所以这时我们可以将这些元素包裹在一个父元素内。
其次为每个相关的信息定义一个 prop 会变得很麻烦,我们可以让组件变成接受一个单独的 post prop
示例: 小说展示页(比较简洁😊)
<div id="app">
<div style="width: 500px;height: 400px;">
<novel-post v-for="prop in props" v-bind:item="prop"></novel-post>
</div>
</div>
<script>
Vue.component('novel-post', {
props: ['item'],
template: '<div>' +
'<img v-bind:src="item.src" style="width: 200px;height: 300px; border: 1px solid red;float: left;" />' +
'<h2 style="float: left;margin-left: 50px;">{{item.title}}</h2>' +
'<div style="font-size: 22px;float:left;width:280px;margin-left: 10px;">{{item.content}}</div>' + '</div>'
})
var vm = new Vue({
el: '#app',
data: {
props: [{
title: "剑来",
src: "img/1496234539057.jpg",
content: '大千世界,无奇不有。我陈平安,唯有一剑,可搬山,倒海,降妖,镇魔,敕神,摘星,断江,摧城,开天!我叫陈平安,平平安安的平安。我是一名剑客'
}]
}
})
</script>
样式弄起来比较复杂,就这样了
基本逻辑是:自定义属性item,通过v-for循环props内的数据,将每个对象赋值给prop,然后将prop绑定到item属性上
监听子组件事件(向父组件传参)
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!我们可以使用 v-on 绑定自定义事件,
使用 $emit(eventName) 触发事件,$event接收数据
示例一:触发父组件事件
//方式一
<div id="app">
<aaa v-on:add="addSize" v-bind:style='{fontSize:size +"px"}'></aaa>
</div>
<script type="text/javascript">
Vue.component('aaa', {
data: function() {
return {
msg: '我是全局组件'
}
},
template: `
<div>
{{msg}}
<button @click='$emit("add")'>点击</button>
</div> `,
})
new Vue({
el: '#app',
data: {
size: 12
},
methods: {
addSize: function() {
this.size += 2;
}
}
})
</script>
//或 方式二
<div id="app">
<aaa v-on:add="addSize" v-bind:style='{fontSize:size +"px"}'></aaa>
</div>
<script type="text/javascript">
Vue.component('aaa', {
data: function() {
return {
msg: '我是全局组件'
}
},
template: `
<div>
{{msg}}
<button @click='aa'>点击</button>
</div> `,
methods:{
aa:function(){
this.$emit("add");
}
}
})
new Vue({
el: '#app',
data: {
size: 12
},
methods: {
addSize: function() {
this.size += 2;
}
}
})
</script>
button是子组件,当点击按钮后,触发父组件(aaa组件)的自定义add事件;然后add事件执行绑定的addSize函数,从而增大字体
推荐使用第一种方式,更直观
实例二:向父组件传递参数
格式:$emit("事件",参数1,参数2,...)
传递一个参数:$event
<div id="app">
<aaa v-on:add="addSize($event)" v-bind:style='{fontSize:size +"px"}'></aaa>
</div>
<script type="text/javascript">
Vue.component('aaa', {
data: function() {
return {
msg: '我是全局组件'
}
},
template: `
<div>
{{msg}}
<button @click='$emit("add",2)'>点击</button>
</div> `,
})
new Vue({
el: '#app',
data: {
size: 12
},
methods: {
addSize: function($event) {
this.size += $event;
}
}
})
</script>
传递多个参数:arguments
<div id="app">
<aaa @astyle="change(arguments)" :style="{fontSize:size+'px',color:color}"></aaa>
</div>
<script type="text/javascript">
Vue.component('aaa', {
data: function() {
return {
msg: '我是全局组件'
}
},
template: `
<div>
{{msg}}
<button @click='$emit("astyle",25,"red")'>点击</button>
</div> `,
})
new Vue({
el: '#app',
data: {
size: 12,
color: 'blue'
},
methods: {
change: function(astyle) {
this.size = astyle[0]
this.color = astyle[1]
}
}
})
</script>
注:
1、传递单个参数时,父组件中的形参必须是$event;传递多个形参时,父组件的形参是arguments。不能省略,不要写错
2、传递多个形参时,值以数组的形式保存。按照参数的顺序依次存储在数组中,访问时也要以数组的形式访问
兄弟组件之间传参
1、定义单独的事件中心,管理组件间的通信
var eventHub=new Vue();
2、监听事件与销毁事件
eventHub.$on(事件名,处理函数)
eventHub.$of(事件名)
3、触发事件
eventHub.$emit(事件,参数)
实例:点击Tom组件中的按钮Jon组件中的数字加1,点击Jon组件中的按钮,Tom组件中的数字加2
<body>
<div id="app" style="width: 180px;height: 180px;border: 1px solid;padding: 20px;">
<p>父组件</p>
<tom-event style="width: 100px;height: 50px;border: 2px solid red;"></tom-event>
<br />
<jon-event style="width: 100px;height: 50px;border: 2px solid red;"></jon-event>
</div>
<script type="text/javascript">
//Tom组件
Vue.component('tom-event', {
data: function() {
return {
msg: 0
}
},
methods: {
add() {
//触发Jon-event事件,向Jon组件传值
eventHub.$emit('Jon-event', 1)
}
},
//监听Tom事件
mounted: function() {
eventHub.$on('Tom-event', (val) => {
this.msg += val
})
},
template: `
<div>
Tom: {{msg}}<br/>
<button @click="add">点击</button>
</div> `
})
//Jon组件
Vue.component('jon-event', {
data: function() {
return {
msg: 0
}
},
methods: {
add() {
//触发tom-event事件,向Tom组件传值
eventHub.$emit('Tom-event', 2)
}
},
//监听Jon事件
mounted: function() {
eventHub.$on('Jon-event', (val) => {
this.msg += val
})
},
template: `
<div>
Jon: {{msg}}<br/>
<button @click="add">点击</button>
</div> `
})
//定义事件中心
var eventHub = new Vue();
//定义父组件
new Vue({
el: '#app',
data: {
size: 12
},
methods: {
addSize: function($event) {
this.size += $event;
}
}
})
</script>
</body>
mounted:生命周期函数之一