vue的核心基础就是组件的使用,玩好了组件才能将前面学的基础更好的运用起来。组件的使用更使咱们的项目解耦合。更加符合vue的设计思想MVVM。javascript
// 定义一个名为 button-counter 的新组件 Vue.component('button-counter', { data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' })
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>
。咱们能够在一个经过 new Vue
建立的 Vue 根实例中,把这个组件做为自定义元素来使用:css
<div id="components-demo"> <button-counter></button-counter> </div> new Vue({ el: '#components-demo' })
由于组件是可复用的 Vue 实例,因此它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。html
能够将组件进行任意次数的复用:vue
<div id="components-demo"> <button-counter></button-counter> <button-counter></button-counter> <button-counter></button-counter> </div>
点击按钮时,每一个组件都会各自独立维护它的count。由于你每用一次组件,都会有它的新实例被建立。html5
定义这个 <button-counter>
组件时,你可能会发现它的 data
并非像这样直接提供一个对象:java
data: { count: 0 }
取而代之的是,一个组件的 data
选项必须是一个函数,所以每一个实例能够维护一份被返回对象的独立的拷贝:node
data: function () { return { count: 0 } }
若是 Vue 没有这条规则,点击一个按钮就可能会影响到其它全部实例。app
一般一个应用会以一棵嵌套的组件树的形式来组织:ide
例如,你可能会有页头、侧边栏、内容区等组件,每一个组件又包含了其它的像导航连接、博文之类的组件。函数
为了能在模板中使用,这些组件必须先注册以便 Vue 可以识别。这里有两种组件的注册类型:全局注册和局部注册。
经过 Vue.component
全局注册:
Vue.component('my-component-name', { // ... options ... })
全局注册的组件能够用在其被注册以后的任何 (经过 new Vue
) 新建立的 Vue 根实例,也包括其组件树中的全部子组件的模板中。
<body> <div id="app"></div> <script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 声明头部组件 var Vheader = { template: ` <header class="head"> 我是头部 </header> ` }; // 1.声明入口组件 /* 1.头部组件 2.侧边栏 3.内容组件 4.脚本组件 */ var Vmain = { template: ` <div class="main"> 我是入口 <Vheader></Vheader> </div> `, components:{ // 挂载子组件 Vheader, // 等价于Vheader:Vheader } }; new Vue({ el: '#app', // 3.使用子组件 template: `<Vmain/>`, // 单闭合 data: { }, components: { // 2.声明变量,挂载子组件 Vmain: Vmain } }); </script> </body>
显示效果以下所示:
注意:先声明子组件、再挂载子组件、最后使用子组件。
<head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> * { padding: 0; margin: 0; } .main { width: 100%; } body { color: #fff; } .head { width: 100%; height: 70px; background-color: purple; text-align: center; font-size: 20px; line-height: 70px; } .wrap { width: 100%; height: 1200px; } .wrap .aside { width: 30%; height: 1200px; background-color:green; float: left; /*侧边栏浮动*/ } .wrap .content { width: 70%; height: 1200px; background-color: saddlebrown; float: left; /*内容区浮动*/ } </style> </head> <body> <div id="app"> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> // 打油诗:先声子再挂子再用子 var Vheader = { // 先声明头部组件 template:` <header class="head"> 我是头部 </header> ` }; var Vaside = { // 声明侧边栏组件 template:` <div class="aside"> 我是侧边栏 </div> ` }; var Vcontent = { // 声明内容区组件 template:` <div class="content"> 我是内容区域 </div> ` }; // 第一步.声明入口组件 /* 1.头部组件 2.侧边栏 3.内容组件 4.脚步组件 以上组件分别挂载到入口组件里面去。 */ var Vmain = { // 局部组件 template:` <div class='main'> <Vheader></Vheader> <div class="wrap"> <Vaside/> <Vcontent/> </div> </div> `, components:{ // 等价于Vheader:Vheader,当两个词如出一辙时能够这样简写: Vheader, // 挂载子组件:头部组件 Vaside, // 挂载子组件:侧边栏组件 Vcontent } }; new Vue({ el:"#app", // 注意一个vue里面只有一个el //第三步.使用子组件 template:"<Vmain></Vmain>", data: { }, components:{ //第二步.声明变量,挂载子组件 key表示组件名 value表示组件对象 Vmain:Vmain } }); </script> </body>
组件是可复用的Vue实例,而且带有一个名字:在这个例子中是 <Vheader>
。咱们能够在一个经过 new Vue
建立的 Vue 根实例中,把这个组件做为自定义元素来使用。
显示效果以下:
组件使用打油诗:1.声子 2.挂子 3.用子。
<!-- 1.声子 --> var App = { template:` <div class='app'></div> ` }; <!-- 2.挂子 --> new Vue({ el:"#app", template:"<App/>" components:{ App } })
Prop 是你能够在子组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。那么就能够像访问data中的值同样来访问。
为了给博文组件传递一个标题,咱们能够用一个 props
选项将其包含在该组件可接受的 prop 列表中:
// 全局组件 Vue.component('blog-post', { props: ['title'], template: '<h3>{{ title }}</h3>' })
一个组件默承认以拥有任意数量的 prop,任何值均可以传递给任何 prop。在上述模板中,你会发现咱们可以在组件实例中访问这个值,就像访问 data
中的值同样。
一个 prop 被注册以后,你就能够像这样把数据做为一个自定义特性传递进来:
<blog-post title="My journey with Vue"></blog-post> <blog-post title="Blogging with Vue"></blog-post> <blog-post title="Why Vue is so fun"></blog-post>
<script type="text/javascript"> var Vheader = { // 先声明头部组件 template:` <header class="head"> <h3>{{title}}</h3> // 模板语法渲染title <span>{{count}}</span> <button @click = 'count+=1'>点击</button> </header> `, data(){ return { count: 0 } }, props:['title'], // props接收title methods:{ } }; var Vmain = { // 局部组件 template:` <div class='main'> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent/> </div> </div> `, components:{ // 等价于Vheader:Vheader,当两个词如出一辙时能够这样简写: Vheader, // 挂载子组件:头部组件 Vaside, // 挂载子组件:侧边栏组件 Vcontent }, props:['title'] // 自定义的属性 }; new Vue({ el:"#app", // 注意一个vue里面只有一个el //第三步.使用子组件 template:"<Vmain v-bind:title='text'/>", // title是属性名,'text'是数据属性的名字 data: { text:"alex是SB" // 在data中设置text,这是数据 }, components:{ //第二步.挂载子组件 key表示组件名 value表示组件对象 Vmain:Vmain } }); </script>
显示效果以下所示:
props:['自定义的属性']
当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性,能够像访问data中的值同样。
须要绑定自定义的属性<Vheader :title = '父组件中data声明的数据属性'/>
一个组件默承认以拥有任意数量的prop,任何值均可以传递任何prop。
在上述模板中,会发现咱们可以在组件实例中访问这个值,就像访问data中的值同样。
<script type="text/javascript"> var Vcontent = { // 声明内容区组件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 对应id <h3>个人博客标题:{{post.title}}</h3> <p>个人博客内容:{{post.content}}</p> </li> </ul> </div> `, props:['posts'] }; var Vmain = { // 局部组件 template:` <div class='main'> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' /> </div> </div> `, components:{ // 等价于Vheader:Vheader,当两个词如出一辙时能够这样简写: Vheader, // 挂载子组件:头部组件 Vaside, // 挂载子组件:侧边栏组件 Vcontent }, props:['title', 'appPosts'] }; new Vue({ el:"#app", // 注意一个vue里面只有一个el //第三步.使用子组件 template:"<Vmain v-bind:title='text' :appPosts = 'posts'/>", // title对应属性名 data: { text:"alex是SB", posts:[ {id:1, title:"组件中传值1", content:"经过prop传递数据1"}, {id:2, title:"组件中传值2", content:"经过prop传递数据22"}, {id:3, title:"组件中传值3", content:"经过prop传递数据333"} ] }, components:{ //第二步.挂载子组件 key表示组件名 value表示组件对象 Vmain:Vmain } }); </script>
显示效果:
开发 <blog-post>
组件时,它的一些功能可能要求咱们和父级组件进行沟通。例如咱们可能会引入一个可访问性的功能来放大博文的字号,同时让页面的其它部分保持默认的字号。
在其父组件中,咱们能够经过添加一个 postFontSize
数据属性来支持这个功能:
new Vue({ el: '#blog-posts-events-demo', data: { posts: [/* ... */], postFontSize: 1 } })
它能够在模板中用来控制全部博文的字号:
<div id="blog-posts-events-demo"> <div :style="{ fontSize: postFontSize + 'em' }"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" ></blog-post> </div> </div>
在每篇文章正文前添加一个按钮来放大字号。
当点击这个按钮时,咱们须要告诉父级组件放大全部博文的文本。幸亏 Vue 实例提供了一个自定义事件的系统来解决这个问题。咱们能够调用内建的 $emit
方法并传入事件的名字,来向父级组件触发一个事件:
Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> /*<button> Enlarge text </button>*/ <button v-on:click="$emit('enlarge-text')"> Enlarge text </button> <div v-html="post.content"></div> </div> ` })
<script type="text/javascript"> var Vcontent = { // 声明内容区组件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 对应id <h3>个人博客标题:{{post.title}}</h3> <p>个人博客内容:{{post.content}}</p> </li> </ul> <button @click="changeSize">改变字体大小</button> </div> `, props:['posts'], methods:{ // 声明方法 changeSize(){ // 经过$emit()方法传入事件名字,来触发自定义的事件 this.$emit('postChangeSize') } } }; var Vmain = { // 局部组件 template:` <div class='main' :style="{fontSize:fontsize+'px'}"> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' @postChangeSize="fontsize+=1" /> // 绑定自定义属性和自定义事件 </div> </div> `, data(){ return { fontsize:14 // 默认字体大小为14 } }, components:{ // 等价于Vheader:Vheader,当两个词如出一辙时能够这样简写: Vheader, // 挂载子组件:头部组件 Vaside, // 挂载子组件:侧边栏组件 Vcontent }, props:['title', 'appPosts'] }; new Vue({...)}; </script>
经过点击按钮能够不断修改字体大小,具体驱动流程以下所示:
页面显示效果以下所示:
$emit第一个参数是自定义的事件名字,第二个参数就是传递的值。
var Vcontent = { // 声明内容区组件 template:` <div class="content"> <ul> <li v-for="post in posts" :key="post.id"> // 对应id <h3>个人博客标题:{{post.title}}</h3> <p>个人博客内容:{{post.content}}</p> </li> </ul> <button @click="changeSize">改变字体大小</button> </div> `, props:['posts'], methods:{ // 声明方法 changeSize(){ // 经过$emit()方法来触发自定义的事件 // 第一个参数是自定义的事件名字;第二个参数就是传递的值。
// this指的是vue实例化对象的子类 this.$emit('postChangeSize', 1) } } }; var Vmain = { // 局部组件 template:` <div class='main' :style="{fontSize:fontsize+'px'}"> <a href="#">{{title}}</a> <Vheader v-bind:title = 'title'></Vheader> <div class="wrap"> <Vaside/> <Vcontent v-bind:posts = 'appPosts' @postChangeSize="clickHandler" /> // 绑定自定义属性和自定义事件 </div> </div> `, methods:{ clickHandler(value){ this.fontsize += this.fontsize+1; } }, data(){ return { fontsize:14 // 默认字体大小为14 } }, components:{ // 等价于Vheader:Vheader,当两个词如出一辙时能够这样简写: Vheader, // 挂载子组件:头部组件 Vaside, // 挂载子组件:侧边栏组件 Vcontent }, props:['title', 'appPosts'] };
组件传值是vue中最重要的知识点。
(1)给子组件中的某个按钮绑定原生事件,能够调用内建方法this.$emit('自定义事件名','传递的数据'),来向父级组件触发一个自定义的事件。
(2)在父组件中的子组件标签中要绑定自定义的事件。
全局注册的组件能够用在其被注册以后的任何(经过 new Vue
)新建立的 Vue 根实例,也包括其组件树中的全部子组件的模板中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
padding:0;
margin:0;
}
#head {
width: 100%;
height: 80px;
background-color: purple;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
// 建立公共组件
// 第一个参数是公共组件的名字;第二个参数options(与局部组件相同)
Vue.component('Vbtn', {
template:`<button>登陆</button>`
});
var Vheader = { // 这里使用Vheader的缘故是,html5中有header标签
template:`<div id="header">
<Vbtn></Vbtn>
<Vbtn></Vbtn>
<Vbtn></Vbtn>
</div>`
};
// 局部组件的使用
var App = {
template:`<div>
<Vheader></Vheader>
</div>`,
components: {
Vheader
}
};
new Vue({
el: '#app',
data(){ // 组件中必定是函数
},
template:'<App/>', // 注意必定是闭合标签
components: {
App // App组件
}
})
</script>
</body>
</html>
页面显示效果以下:
全局组件的使用: Vue.component('全局组件的名称', { 跟new.Vue()实例化对象中的options是同样的,可是要注意是: 不论是公共组件仍是局部组件,data必须是一个函数,函数必定要有返回值(哪怕是一个空对象{}) })
Vue 实现了一套内容分发的 API,这套 API 基于当前的 Web Components 规范草案,将 <slot>
元素做为承载分发内容的出口。
<head>代码省略</head> <body> <div id="app"></div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> // 建立公共组件 // 第一个参数是公共组件的名字;第二个参数options Vue.component('Vbtn', { template:`<button> <slot></slot> </button>` }); var Vheader = { // 这里使用Vheader的缘故是,html5中有header标签 template:`<div id="header"> <Vbtn>登陆</Vbtn> <Vbtn>注册</Vbtn> <Vbtn>提交</Vbtn> </div>` }; """代码省略""" </script> </body> </html>
若是不使用slot,像上面这么在模板中添加不一样的信息是不显示的。使用vue内置组件slot后显示效果以下:
<script type="text/javascript"> // 建立公共组件 // 第一个参数是公共组件的名字;第二个参数options Vue.component('Vbtn', { template: `<button class="default" :class="type"> <slot></slot> </button>`, props: ['type'] }); var Vheader = { // 这里使用Vheader的缘故是,html5中有header标签 template: `<div id="header"> <Vbtn>登陆</Vbtn> <Vbtn>注册</Vbtn> <Vbtn>提交</Vbtn> <Vbtn>默认按钮</Vbtn> <Vbtn type="primary">主要按钮</Vbtn> <Vbtn type="success">成功按钮</Vbtn> </div>` }; """代码省略""" </script>
这里应用了vue的v-bind:class来给每一个标签元素添加class。
props:一个 prop 被注册以后,能够把数据做为一个自定义特性传递进来。
所以在“<Vbtn type="success">成功按钮</Vbtn> ”,中给type定义了一个属性,经过props组件传值传递到公共组件中,由此就能够对网页中全部的按钮进行一个修饰。
Element - 网站快速成型工具:http://element-cn.eleme.io/#/zh-CN
添加css代码以下所示:
<style> * { padding: 0; margin: 0; } #head { width: 100%; height: 80px; background-color: purple; } button { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; border-top-color: rgb(220, 223, 230); border-right-color: rgb(220, 223, 230); border-bottom-color: rgb(220, 223, 230); border-left-color: rgb(220, 223, 230); border-color: #dcdfe6; color: #606266; text-align: center; box-sizing: border-box; outline: none; margin: 0; transition: .1s; font-weight: 500; padding: 12px 20px; font-size: 14px; border-radius: 4px; } .primary { color: #fff; background-color: #409eff; border-color: #409eff; } .success { color: #fff; background-color: #67c23a; border-color: #67c23a; } </style>