前言
最近开始在学vue相关的内容。组件这章的内容比较多。看了http://www.cnblogs.com/keepfool/p/5625583.html这篇博客,博主总结的还比较全面也挺清晰,可是这篇博客的知识点跟实例都是基于vue 1.0版本的,所以参考这篇博客,我将vue2.0版本中的相关知识点做了一个总结。算是自己学习的一个笔记
什么是组件?
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。我们可以将组件看成是封装好的HTML元素。
本文的所有代码,都放在github上面https://github.com/xuxiaozhi/vue-tutorials,有需要的可以下载查看。
组件的注册和使用
全局注册
注册一个组件
要注册一个全局组件,你可以使用 Vue.component(tagName, options)
来注册。如下实例:
//1、注册一个全局的组件。要确保在初始化实例之前注册 Vue.component(‘my-component‘,{ template:"<div>这是第一个组件</div>" }) //创建跟实例 new Vue({ el:"#app" })
使用组件
组件在注册之后,便可以在父实例的模块中以自定义元素 <my-component></my-component>
的形式使用。
注意:要确保组件是在初始化实例之前注册,要不然使用的时候会报错
<div id="app"> <my-component></my-component> </div>
组件使用后在页面中,将渲染成以下结构
局部注册组件
我们不必全局注册每一个组件,根据实际情况需要,我们可以采用局部注册的方式注册组件。如下实例
new Vue({ el:"#app", components:{ ‘my-component‘:{ template:"<div>这个是局部注册的组件</div>" } } })
?注意
局部注册的组件仅在当前注册的实例或者组件内部使用。在其他地方引用将会报错,如下:
<div id="app"> <my-component></my-component> </div> <div id="app2"> <my-component></my-component> </div>
在上述实例中,我们在”#app“元素所在的实例中,注册了一个组件,然后在“#app”和“#app2”内引用,查看源代码发现,只有“#app”内的组件渲染成了html代码,而在“#app2”内只是一个无意义的标签,如下图所示:
字符串模板
在组件中,我们一般使用字符串模板,字符串模板,主要有以下三种形式
- 使用
script
标签 - 使用
template
标签 - 单文件组件
使用<script标签
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>组件相关</title> </head> <body> <div id="app"> <my-component></my-component> </div> <script type="text/x-template" id="myComponent"> <div>这是script模板</div> </script> </body> <script type="text/javascript" src="../js/vue.js" ></script> <script type="text/javascript"> //全局注册一个组件 Vue.component(‘my-component‘,{ template:"#myComponent" }) new Vue({ el:"#app" }) </script> </html>
注意点:
- 需要给script设置一个id,使用的时候,直接引用该id即可
- 使用<script>标签时,type指定为text/x-template,意在告诉浏览器这不是一段js脚本,浏览器在解析HTML文档时会忽略<script>标签内定义的内容。
使用template标签
template标签的用法跟script是一样的,区别在于template标签不需要设置type,直接设置一个id即可,一般情况下,我们建议使用这种方式来创建模板。如下所示
<template id="myComponent"> <div>这是script模板</div> </template>
单文件组件
所谓的单文件组件是指创建.vue后缀的文件,并不是我们上面所说的全局注册一个组件或者局部注册一个组件,这个知识点后面再单独说明
父子组件
组件 A 在它的模版中使用了组件 B。则A跟B就构成了父子组件的关系。在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。
子组件获取父组件的数据
默认情况下,子组件不能访问父组件的数据。子组件如果需要拿到父组件的数据,需要通过子组件的 props 选项。
子组件要拿到父组件的数据,有以下两个步骤:1、子组件要显式地用 props
选项声明它期待获得的数据。2、通过v-bind将数据绑定到子组件的模板上,
为了更好的理解,我们可以将new Vue()这个根组件看成是my-component的父组件。那么父组件向子组件传递数据,我们可以通过以下实例来说明:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>组件相关</title> <link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"/> </head> <body> <div id="app"> <!--通过v-bind将父组件的数据绑定到子组件的模板上--> <my-component :Columns="columns" :Users="users"></my-component> </div> <template id="myComponent"> <table class="table table-bordered table-striped"> <thead> <tr> <th>name</th> <th>age</th> <th>email</th> </tr> </thead> <tbody> <tr v-for="item in Users"> <td v-for="col in Columns">{{item[col]}}</td> </tr> </tbody> </table> </template> </body> <script type="text/javascript" src="../js/vue.js" ></script> <script type="text/javascript"> new Vue({ el:"#app", data:{ columns:[‘name‘,‘age‘,‘sex‘], users:[{ name: ‘Jack‘, age: 30, sex: ‘Male‘ }, { name: ‘Bill‘, age: 26, sex: ‘Male‘ }, { name: ‘Tracy‘, age: 22, sex: ‘Female‘ }, { name: ‘Chris‘, age: 36, sex: ‘Male‘ }] }, components:{ ‘my-component‘:{ template:"#myComponent", //1、props显示的申明子组件想要获取的数据 props:{ ‘Columns‘:Array, ‘Users‘:Array } } } }) </script> </html>
上述代码再页面中的运行结果如下图:
说明:
props有两种使用方式,当我们使用上述实例中的方式的时候,可以验证数据的格式,如果格式不正确会报错。我们还可以直接使用数组来申明子组件想要获取的数据,如[‘Columns‘,‘Users‘]
父组件获取子组件的数据
子组件如果需要把数据传递给父组件,那么我们就需要用到自定义的事件。这个过程主要包括两个步骤,1、使用vm.$emit(event,[...args])触发事件,2、父组件可以在使用子组件的地方直接用 v-on
来监听子组件触发的事件。在下面实例中,我们点击子组件,没点一次数据增加1,然后把这个值传递给父组件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>组件相关</title> <link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"/> </head> <body> <div id="app"> <!--通过v-bind将父组件的数据绑定到子组件的模板上--> <p>{{total}}</p> <!--在使用子组件的地方用v-on来监听子组件的事件变化--> <button-counter v-on:increment="get"></button-counter> </div> </body> <script type="text/javascript" src="../js/vue.js" ></script> <script type="text/javascript"> new Vue({ el:"#app", data:{ total:0 }, methods:{ get:function(res){ this.total=res; } }, components:{ ‘button-counter‘:{ template:‘<button v-on:click="increment">{{ counter }}</button>‘, //1、props显示的申明子组件想要获取的数据 data:function(){ return { counter:0 } }, methods:{ increment:function(){ this.counter+=1; //1、在子组件中,使用$emit来触发事件。 this.$emit(‘increment‘,this.counter) } } } } }) </script> </html>
运行效果如图:点击下面的按钮的时候,上面的数据会相应的发生改变
slot
slot是vue中用于内容分发的,通俗的说slot其实是一个内容插槽,我们也可以把它理解成一个占位符。我们可以在模板中使用这个占位符设置一些默认的内容,当我们使用这个模板时,如果我们重新设置了内容,这个占位符会替换成我们想要替换的内容,当我们不设置的时候,默认的就是显示这个占位符中的内容。下面让我们用一个实例来理解slot.
单个slot
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>组件相关</title> <link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"/> </head> <body> <div id="app"> <my-component> <h1>我是替换后的标题</h1> </my-component> <hr> <my-component></my-component> </div> <template id="myComponent"> <div> <slot><h1>我是默认标题</h1></slot> </div> </template> </body> <script type="text/javascript" src="../js/vue.js" ></script> <script type="text/javascript"> Vue.component(‘my-component‘,{ template:"#myComponent" }) new Vue({ el:"#app" }) </script> </html>
上面的代码,在页面中渲染成了以下所示:当我们没有重新设置替换内容的时候,slot中的内容会显示,当我们重新设置了 则slot中的内容不会再显示了,页面中显示的是我们设置后的内容
具名slot
<slot>
元素可以用一个特殊的属性 name
来配置如何分发内容。多个 slot 可以有不同的名字。具名 slot 将匹配内容片段中有对应 slot
特性的元素。仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的备用插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。看一下下面的实例,假设我们有一个下面一样的模板。这个模板被分成了三部分,
<template id="myComponent"> <div class="container"> <header> <slot name="header"><h1>我是默认标题</h1></slot> </header> <main> <slot name="content"> <p>我是默认内容</p> </slot> </main> <footer> <slot name="footer"> <p>我是默认底部</p> </slot> </footer> </div> </template>
这个模板被分为了三部分,每一部分都设置了一些默认的内容。这些插槽是通过name和slot对应关联的,当我们使用这个模板时,如果我们重置了header跟footer中的内容,而content中的内容我们不设置,如下:
<my-component> <h1 slot="header">我是设置后的标题</h1> <p slot="footer">我是设置后的底部</p> </my-component>
那么页面中渲染如下图: