在这一节里,咱们将会了解到Vue的组件,理解组件是如何工做的,并利用一系列
的例子证实,用组件化的思想开发项目,会给你带来不同感觉。若是咱们理解了Vue的组件化思想,咱们就能够利用这个思想构造一个简化的评论投票系统,一个用户能够发布评论,其余用户能够在任意的评论上面投“同意票”或者投“反对票”。css
若是你是第一次接触Vue的话,你能够看看我以前的文章,《从零开始学Vue》,了解Vue的基本语法。html
利用组件可以很好的把一个你正在构建的具备复杂接口的应用拆分开来,同时,组件也具备很高的复用性,即便是在你正在开发的是不一样的项目也能封装复用。vue
先建立一个简单的html页面,并将Vue实例化后挂载在咱们的DOM元素上。git
<!DOCTYPE html> <html> <head> <title>揭开Vue组件的神秘面纱</title> </head> <body> //这中间就是实例挂载点的实例边界 <div id="vueInstance"></div> //Vue的CDN,以后会省略不写 <script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script> <script> // 建立一个新的Vue实例,并设置挂载点 var V = new Vue({ el : '#vueInstance' }); </script> </body> </html>
如今咱们已经把在《从零开始学Vue》的基础都准备好了,而后咱们将建立咱们的第一个简单的,可复用的组件。在Vue中你,可使用Vue.component()来建立和注册你的组件,这个构造器有两个参数:github
组件的名字ajax
包含组件参数的对象数据库
这个对象有点像Vue()构造器里的对象,它也有相似于Vue()里的el属性和data属性,可是又有点不同。segmentfault
Vue()构造器的el和data能够是对象。
Vue.component()构造器的el和data只能是函数。数组
如今来看看第一个组件是如何运做的。我想要注册一个组件,用p标签输出一行个人自我介绍。因此我建立了一个组件,并填入两个参数:ide
组件的名字:'mine'
包含组件参数的对象:这个对象包含一个属性'template'
Vue.component('mine',{ template : '<p>My name is Appian.</p>' })
如今你已经有了本身的一个组件了,你能够在你的应用的任何地方使用它。只要你调用它的惟一标识(就是组件名字),并用普通html标签的格式来书写,好比<mine></mine>,组件上注册的内容就会在你的自定义标签的地方插入。
<div id="vueInstance"> <mine></mine> //标识注册的内容会在这里插入 <mine></mine> <mine></mine> //重复插入注册内容 </div> <script> Vue.component('mine',{ //这里就是注册的内容 template : '<p>My name is Appian.</p>' }); var V = new Vue({ el : '#vueInstance' }); </script>
Vue使用模板Template来代替组件,并使自定义的惟一标识用html标签插入到DOM结构中去,使得html更加简洁、整齐和直观。
如今你可能会想,我写的组件怎么可能只有一行p标签?一行p标签还有必要组件这么麻烦吗?是的,组件是为了更复杂的封装复用而生的。因此,若是你只会Vue.component()构造器中的template属性定义html代码,利用字符串拼接拼出全部的代码,这样只会让你比用jq更加疲惫不堪。
为了不上面的这种状况,因此咱们能够用template标签(注意属性和标签是不同的)来达到咱们的目的。咱们能够在页面的任何地方,定义template标签,并在template标签内,写好咱们的模板。由于template标签在页面加载的时候不会渲染出来,只有在咱们须要它的时候,这个标签内的内容才会被渲染出来。因此,你能够把template标签放在任何地方,并给它一个id,以便在组件注册的时候可以找到模板。
<div id="vueInstance"> <mine></mine> //标识注册的内容会在这里插入 </div> <template id="mineTpl"> <p>My name is Appian.</p> <button>点击没有任何事件</button> </template> <script> Vue.component('mine',{ //这里就是注册的内容 template : '#mineTpl' }); var V = new Vue({ el : '#vueInstance' }); </script>
咱们如今已经能够利用这样的方法建立一个复杂的组件了。这样咱们可能将复杂的代码进行功能分区以后组件化,用组件的思想避免代码一坨一坨的。组件化可以帮你更清晰的组织好你的模块,使你的组件更加vue化。
每次建立组件实例的时候,这个实例都划分了本身的组件范围,这个范围致使了在这个组件区域内没法得到其父组件的数据。因此,Vue是如何处理父组件向子组件中传递数据的呢?答案是,经过props。
先看一个最简单,从父组件向子组件中传递data的例子。注册的mine组件是子组件,他但愿从父组件那里获得‘city’这个数据的信息,因此在mine的构造器里增长了一个参数props,用来接收父组件传递过来的city的值。
Vue.component('mine',{ template : '<p>Appian is from {{ city }}.</p>', props : ['city'] });
上面的例子中,咱们定义了props做为一个数组,因此props能够用来接收多个字段,而这些字段就是子组件指望从父组件那里获得的。
props不必定要是数组,也能够是对象。能够在对象中详细的定义不少props的限制条件。
Vue.component('mine',{ template : '<p>Appian is from {{ city }}.</p>', props : { city : { type : String,//定义字符串类型 required : true,//该字段是必须的 default : 'China'//设置默认值 } } });
咱们不须要每次都将props的限制条件都写出来,由于在这个例子中的数据是一个很简单的字段,上例中只是为了完整展现props的对象表示方法,因此才展开来写的。
那父组件那里又是怎么指派字段给子组件的呢?
<mine city="FuJian-YongAn"></mine>
这样直接在mine标签里面定义‘city’字段,就是父组件指派字段的方式之一。可是这样直接指派是很瞎的,咱们须要的是动态变化的city,这个一会咱们会说到的。
先简单介绍一下咱们接下来要作的事。咱们要伪装咱们正在搭一个博客,博客须要展现做者的基本信息,此时,咱们可能会须要一些数据对象,多是从数据库得到的,或者ajax请求到的,总之就是请求到了以后,将这个数据对象定义在父级的data中。并在html的template标签中准备渲染。
<div id="vueInstance"> <mine></mine> //标识注册的内容会在这里插入,以后也要展开来讲!!! </div> <template id="mineTpl"> <h1>{{ name }}</h1> <h2>{{ title }}</h2> <h3>{{ city }}</h3> <p>{{ content }}</p> </template> <script> //Vue.component()的构造在下文中展开来讲!!! var V = new Vue({ el : '#vueInstance', data : { name : 'Appian', title : 'This is a title', city : 'FuJian-XiaMen', content : 'There are some desc about Appians Blog' } }); </script>
准备好模板渲染以后,固然也要注册mine的构造器Vue.component()。除了基本的绑定模板id(#mineTpl)以外,还须要指定这个子组件想要的数据的字段名,并把指望获得的4个字段写在props中。
Vue.component('mine',{ template : '#mineTpl', props : ['name','title','city','content'] });
这样咱们就能告诉父级,子组件须要的字段是哪些。接下来父级就能够指派字段的值给子组件了。前面的city字段是写死的,如今这里绑定的字段就是动态绑定的。
<mine :name='name' :title='title' :city='city' :content='content' ></mine>
等号左右两边的字段名称能够不同。
等号左边的字段名,是指在子组件的props中声明的名字。在html写成肉串式,可是在props中写成驼峰式。
等号右边的字段名,是指在父级里定义的字段的名字。‘:’是‘v-bind’的缩写
这样就能把父组件的4个字段绑定到子组件上。如今,只要父组件指派的字段的值一发生改变,子组件的值也会发生相应的改变。
如今就能够利用前面学到的内容,搭建一个简易的评论社区系统,样式什么的先无论,只讲究js的具体实现。
建立一个新的Vue实例
给实例挂载一个div(#vueInstance)
定义数据,而后渲染。
<div id="vueInstance"> <div class="container"> <ul> //这里即将渲染出评论的投票列表 </ul> </div> </div> <template id="postTpl"> <li> <i class="up">我支持</i> <span>票数: {{ post.votes }}</span> <i class="down">我反对</i> <a>话题: {{ post.title }}</a> </li> </template> <script> //Vue.component()的构造在下文中展开来讲!!! var V = new Vue({ el : '#vueInstance', data : { posts: [{ title: '请大大多多为我投票,我给你们发红包', votes: 15 },{ title: '投我准没错', votes: 53 },{ title: '不要投给我楼上的', votes: 10 }] } }); </script>
如今先构造好数据,有投票的话题和投票人数。而后再构造好模板(template标签),这个模板值用来渲染单个话题。模板里有除了渲染话题和投票人数,还有两个按钮,用来投同意票或者反对票。以后咱们只须要在html循环模板,而后就能屡次插入模板,渲染成列表。固然也能够在模板里渲染好列表再一次插入。咱们先用前一种方法。
无论css的样式问题,如今就能够开始注册Vue.component()构造器了,以便咱们渲染页面。咱们在注册的时候要明确,我注册的子组件须要的props是父级的posts数组中的一个元素对象post。因此咱们应该这样注册:
Vue.component('post',{ template : '#postTpl', props : ['post'] });
而后咱们使用自定义的<post>标签插入在html中去。
<div id="vueInstance"> <div class="container"> <ul> <post v-for="post in posts" :post="post"></post> </ul> </div> </div>
这样咱们就已经完成了循环输出posts数组了。由于咱们把数组的元素指派给了子组件,因此子组件就能够渲染title和vote。接下来要作的就是增长“同意”和“反对”按钮的逻辑代码,并咱们须要对投票状态进行锁定,就是若是咱们投了某个话题的同意票就不能再投该话题的反对票,反之亦然。
因此让咱们开始在模板里面定义点击事件吧,投同意票的事件叫作“upvote”,投反对票的事件叫作“downvote”。
<template id="postTpl"> <li> <i class="up" @click="upvote">我支持</i> <span>票数: {{ post.votes }}</span> <i class="down" @click="downvote">我反对</i> <a>话题: {{ post.title }}</a> </li> </template>
Vue.component('post',{ template : '#postTpl', props : ['post'], data : function (){ return { //data必须为function,定义投票状态 upvoted: false, downvoted: false } }, methods : { upvote : function() { //点击同意的事件 this.upvoted = !this.upvoted; this.downvoted = false; }, downvote: function() { //点击反对的事件 this.downvoted = !this.downvoted; this.upvoted = false; } } });
注意,data里面的两个布尔值的定义是做为一个函数的返回值定义的。那是由于咱们想要给每个组件都设置一个是否投票的状态。
(还记得以前我说过,此次的列表渲染是循环渲染多个模板,每一个模板都只是一个话题的相关信息,而如今在组件中定义的data:upvoted和downvoted,也是专属于某个模板的。)
这样咱们若是投了某个话题的同意票,并不会影响剩下话题的投票状况。
接下来已经完成了点击事件的状态控制,那么点击“同意”和“反对”会致使话题的票数发生变化。这个时候咱们能够利用以前的教程中学过的computed属性进行计算。
组件也有computed属性哦~
Vue.component('post',{ template : '#postTpl', props : ['post'], data : function (){ //同上,略 }, methods : { //同上,略 }, computed: { //重点部分 votes: function () { if (this.upvoted) { return this.post.votes + 1; } else if (this.downvoted) { return this.post.votes - 1; } else { return this.post.votes; } } } });
到此为止,应该组件中的逻辑处理差很少完成了,如今要作的就是让咱们在组件中修改的投票人数,可以在模板中渲染出来。由于咱们如今的votes的值是在子组件中修改的,而一开始渲染的时候,咱们的votes只是一味的接受父级传过来的值,因此,如今要把修改的值显示在模板上。
因此模板变成了这样:
<template id="postTpl"> <li> <i class="up" @click="upvote">我支持</i> <span>票数: {{ votes }}</span> <i class="down" @click="downvote">我反对</i> <a>话题: {{ post.title }}</a> </li> </template>
如今咱们的投票系统已经基本完成了。咱们可能会但愿咱们的投票系统好看一点,直观一点。因此咱们能够在按钮上绑定一些样式。好比当用户已经投了某个话题的同意票或者反对票,就让这个按钮变成橙色。
.disabled { color : orange; }
Vue是利用v-bind:class来进行样式绑定的,能够简写成一个‘:’。其绑定的内容是一个对象,对象里面是class的名字和class对应的状态。
了解更多样式绑定的信息点这里
<template id="postTpl"> <li> <i class="up" @click="upvote" :class="{disabled: upvoted}">我支持</i> <span>票数: {{ votes }}</span> <i class="down" @click="downvote" :class="{disabled: downvoted}">我反对</i> <a>话题: {{ post.title }}</a> </li> </template>
若是咱们点击了某个话题的同意按钮,则它的upvoted就会变成true,则disabled的样式就绑定到同意按钮上去。若是点了该话题的反对按钮,则它的upvoted就会变成false,则disabled就不会绑定到同意按钮上。以上就是模板最终的样子。
咱们已经利用了咱们对Vue的基本语法还有一些组件的基本操做,创建起了一个基本的话题投票系统。在教程的最后一部分,咱们将看看,咱们应该如何将这个投票系统组件进行复用。
复用的关键在于组件的命名,让你的命名可以复用。至少你在构建你的组件的时候,你要问本身,“是否其余地方也能用到这个组件?”
好比,在上面的例子中,posts的意思是,这个数据是从ajax的post请求过来的数据,为了便于理解,才取名为posts,为了让本身的组件名字一看就知道关联,因此把模板的id定义为#postTpl,tpl是template的简写,自定义标签的命名也是post。总之,就是这样的细节,不只方便本身阅读,也方便其余人阅读你的代码。
如今咱们的评论系统须要增长一个功能,就是增长一个发布评论的功能。就是增长了一个发布评论的区域(#commentBox)。
<div id="vueInstance"> <div class="container"> <ul> <post v-for="post in posts" :post="post"></post> </ul> <div id="commentBox"> 请输入评论内容并提交: <input type="text" v-model="comment" @keyup.enter="postComment"> <button @click="postComment">提交评论</button> </div> </div> </div> //模板渲染不变 <script> //Vue.component()的注册不变。 var V = new Vue({ el : '#vueInstance', data : { posts: [{ title: '请大大多多为我投票,我给你们发红包', votes: 15 },{ title: '投我准没错', votes: 53 },{ title: '不要投给我楼上的', votes: 10 }], comment: '' }, methods: { postComment: function() { this.posts.push({ title: this.comment, votes: 0 }) this.comment = ''; } } }); </script>
输入框用v-model绑定了comment字段,为了不管用户输入什么,在提交的时候都能得到他输入的值。当用户按回车或者点击提交按钮的时候都会触发postComment方法。这里的事件绑定一个是用的回车事件 @keyup.enter,还有一个点击事件@click。postComment方法就是把话题和投票为0的对象push进posts数组中去,Vue会将新的模板自动渲染出来。
这样一个可复用的组件就构造完成了,组件化会节省开发者的不少时间。组件是否复用,也要结合开发的实际需求而定。
到此为止,你就已经可以掌握了Vue的组件的基本使用,组件经过props向下传递数据,经过使用<template>标签来构造模板。咱们在上文中利用构建了一个评论发布投票系统来讲明了组件的用法,而且简单介绍了如何复用。
利用 props,子组件能够定义须要父级传递的字段
利用 'v-bind:' 或 ':' 在自定义标签的地方绑定父级指派的字段
组件的 data 和 el 必须定义为function
不要忘记,仍是须要将Vue实例化,才能使用组件。
github地址
https://github.com/AppianZ/Close2Vue
推荐一个Vue交流群:364912432