本文最初发表于博客园,并在GitHub上持续更新前端的系列文章。欢迎在GitHub上关注我,一块儿入门和进阶前端。javascript
如下是正文。html
组件: 组件的出现,就是为了拆分Vue实例的代码量的,可以让咱们以不一样的组件,来划分不一样的功能模块,未来咱们须要什么样的功能,就能够去调用对应的组件便可。前端
模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每一个功能模块的职能单一vue
组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用java
组件Component
是 Vue.js 最强大的功能之一。组件能够扩展 HTML 元素,封装可重用的代码。git
全局组件的定义和注册有三种方式,咱们接下来说一讲。github
写法一:使用Vue.extend方法定义组件,使用 Vue.component方法注册组件。微信
代码举例:app
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- 若是要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中,便可 --> <account> </account> </div> <script> //第一步:使用 Vue.extend 定义组件 var myAccount = Vue.extend({ template: '<div><h2>登陆页面</h2> <h3>注册页面</h3></div>' // 经过 template 属性,指定了组件要展现的HTML结构。template 是 Vue 中的关键字,不能改。 }); //第二步:使用 Vue.component 注册组件 // Vue.component('组件的名称', 建立出来的组件模板对象) Vue.component('account', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象 new Vue({ el: '#app' }); </script> </body> </html>
上方代码中,在注册组件时,第一个参数是标签名,第二个参数是组件的定义。模块化
运行结果以下:
代码截图以下:
上图中,注意两点:
注意1、红框部分,要保证两者的名字是一致的。若是在注册时,组件的名称是驼峰命名,好比:
Vue.component('myComponent', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象
那么,在标签中使用组件时,须要把大写的驼峰改成小写的字母,同时两个单词之间使用-
进行链接:
<my-component> </my-component>
Vue.component('my')
注意2、绿框部分,必定要用一个大的根元素(例如<div>
)包裹起来。若是我写成下面这样,就没有预期的效果:
template: '<h2>登陆页面</h2> <h3>注册页面</h3>'
结果以下:(并不是预期的效果)
写法二:Vue.component方法定义、注册组件(一步到位)。
代码以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <account> </account> </div> <script> //定义、注册组件:第一个参数是组件的名称(标签名),第二个参数是组件的定义 Vue.component('account', { template: '<div><h2>登陆页面</h2> <h3>注册页面</h3></div>' // template 是 Vue 中的关键字,不能改。 }); new Vue({ el: '#app' }); </script> </body> </html>
代码截图以下:
上图中,一样注意两点:
一、红框部分,要保证两者的名字是一致的。
二、绿框部分,必定要用一个大的根元素(例如<div>
)包裹起来。若是我写成下面这样,就没有预期的效果:
template: '<h2>登陆页面</h2> <h3>注册页面</h3>'
结果以下:(并不是预期的效果)
上面的写法1、写法二并非很智能,由于在定义模板的时候,没有智能提示和高亮,容易出错。咱们不妨来看看写法三。
写法三:将组件内容定义到template标签中去。
代码以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <!-- 定义模板 --> <template id="myAccount"> <div> <h2>登陆页面</h2> <h3>注册页面</h3> </div> </template> <div id="app"> <!-- 使用组件 --> <account> </account> </div> <script> //定义、注册组件 Vue.component('account', { template: '#myAccount' // template 是 Vue 中的关键字,不能改。 }); new Vue({ el: '#app' }); </script> </body> </html>
代码截图以下:
写法三其实和方法二差很少,无非是把绿框部分的内容,单独放在了<template>
标签中而已,这样有利于 html 标签的书写。
咱们在上一段中定义的是全局组件,这样作的时候,多个Vue实例均可以使用这个组件。
咱们还能够在一个Vue实例的内部定义私有组件,这样作的时候,只有当前这个Vue实例才可使用这个组件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- 使用Vue实例内部的私有组件 --> <my-login></my-login> </div> <script> new Vue({ el: '#app', data: {}, components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: '<h3>这是私有的login组件</h3>' } } }); </script> </body> </html>
运行效果:
固然,咱们还能够把模板的定义存放在<template>
标签中,这样的话,模板里的html标签就能够出现智能提示和高亮,避免出错。以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <!-- 定义模板 --> <template id="loginTmp"> <h3>这是私有的login组件</h3> </template> <div id="app"> <!-- 调用Vue实例内部的私有组件 --> <my-login></my-login> </div> <script> new Vue({ el: '#app', data: {}, components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: '#loginTmp' } } }); </script> </body> </html>
运行效果不变。
既然组件是一个页面,那么,页面中可能会有一些功能要动态展现。所以,咱们有必要为组件添加 data 和 methods。
代码举例以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <!-- 定义组件的模板 --> <template id="myAccount"> <div> <!-- 在组件的模板中,调用本组件中的data --> {{myData}} <a href="#" v-on:click="login">登陆1</a> <h2>登陆页面</h2> <h3>注册页面</h3> </div> </template> <div id="app"> <!-- 第一次调用组件 --> <account> </account> <!-- 第二次调用组件 --> <account> </account> </div> <script> //定义、注册组件 Vue.component('account', { template: '#myAccount', //组件中的 data //【注意】组件中的data,再也不是对象,而是一个方法(不然报错);并且这个方法内部,还必须返回一个对象才行 // 组件中 的data 数据,使用方式,和实例中的 data 使用方式彻底同样!!! data: function () { return { myData: 'smyhvae' } }, //组件中的 method methods: { login: function () { alert('login操做'); } } }); new Vue({ el: '#app' }); </script> </body> </html>
上方代码所示,咱们在account
组件中添加的data 和 methods,其做用域只限于account
组件里,保证独立性。
注意,在为组件添加数据时,data再也不是对象了,而是function,并且要经过 return的形式进行返回;不然,页面上是没法看到效果的。经过 function返回对象的形式来定义data,做用是:
上方代码中,组件<account>
被调用了两次(不像根组件那样只能调用一次),可是每一个组件里的数据 myData是各自独立的,不产生冲突。
换而言之,经过函数返回对象的目的,是为了让每一个组件都有本身独立的数据存储,而不该该共享一套数据。
咱们先来看下面这样的例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- 第一次调用组件 --> <counter></counter> <hr> <!-- 第二次调用组件 --> <counter></counter> </div> <!-- 定义模板 --> <template id="tmpl"> <div> <input type="button" value="让count加1" @click="increment"> <h3>{{count}}</h3> </div> </template> <script> var dataObj = { count: 0 } // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1 Vue.component('counter', { template: '#tmpl', data: function () { return dataObj //当咱们return全局的dataObj的时候,子组件们会共享这个dataObj }, methods: { increment() { this.count++ } } }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body> </html>
运行效果以下:
上面的例子中,将组件<counter>
调用了两次,因为dataObj
是全局对象,致使两个组件实例均可以共享这个dataObj
数据。因而,咱们点击任何一个组件实例的按钮,均可以让count
数据加1。
如今问题来了,若是咱们想让组件<counter>
的两个实例去单独操做count
数据,应该怎么作呢?咱们应该修改 data中 return出去的内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <counter></counter> <hr> <counter></counter> <hr> <counter></counter> </div> <template id="tmpl"> <div> <input type="button" value="让count加1" @click="increment"> <h3>{{count}}</h3> </div> </template> <script> var dataObj = { count: 0 } // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1 Vue.component('counter', { template: '#tmpl', data: function () { // return dataObj //当咱们return全局的dataObj的时候,这个dataObj是共享的 return { count: 0 } // 【重要】return一个**新开辟**的对象数据 }, methods: { increment() { this.count++ } } }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body> </html>
运行效果:
如上图所示,每当咱们建立一个新的组件实例时,就会调用data函数,data函数里会return一个新开辟的对象数据。这样作,就能够保证每一个组件实例有独立的数据存储。
代码举例:(登陆组件/注册组件,二选一)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- 舒适提示:`.prevent`能够阻止超连接的默认事件 --> <a href="" @click.prevent="flag=true">登陆</a> <a href="" @click.prevent="flag=false">注册</a> <!-- 登陆组件/注册组件,同时只显示一个 --> <login v-if="flag"></login> <register v-else="flag"></register> </div> <script> Vue.component('login', { template: '<h3>登陆组件</h3>' }) Vue.component('register', { template: '<h3>注册组件</h3>' }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body> </html>
运行效果以下:
<component>
标签实现组件切换上面的例子中,咱们是经过flag的值来进行组件的切换。可是,flag的值只可能有两种状况,也就是说,v-if和v-else只能进行两个组件之间的切换。
那如何实现三个甚至三个以上的组件切换呢?这里,咱们能够用到Vue提供的<component>
标签。
咱们先来看一下<component>
标签的用法。
基于上面的代码,若是我想让login组件显示出来,借助<component>
标签能够这样作:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="Vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- Vue提供了 component ,来展现对应名称的组件 --> <!-- 【重要】component 是一个占位符, `:is` 属性,能够用来指定要展现的组件名称。这里,咱们让 login 组件显示出来 --> <component :is="'login'"></component> </div> <script> // 组件名称是 字符串 Vue.component('login', { template: '<h3>登陆组件</h3>' }) Vue.component('register', { template: '<h3>注册组件</h3>' }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); </script> </body> </html>
上方代码中,提取关键代码以下:
<component :is="'login'"></component>
若是我想让register组件显示出来,借助<component>
标签能够这样作:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="Vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- Vue提供了 component ,来展现对应名称的组件 --> <!-- 【重要】component 是一个占位符, `:is` 属性,能够用来指定要展现的组件名称 --> <component :is="'register'"></component> </div> <script> // 组件名称是 字符串 Vue.component('login', { template: '<h3>登陆组件</h3>' }) Vue.component('register', { template: '<h3>注册组件</h3>' }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); </script> </body> </html>
上方代码中,提取关键代码以下:
<component :is="'register'"></component>
所以,若是要实现组件之间的切换,咱们能够给<component>
标签里的is属性值设置为变量便可,来看看代码实现。
实现组件切换的完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="vue2.5.16.js"></script> </head> <body> <div id="app"> <!-- 点击按钮后,设置变量`comName`为不一样的值,表明着后面的component里显示不一样的组件 --> <a href="" @click.prevent="comName='login'">登陆</a> <a href="" @click.prevent="comName='register'">注册</a> <!-- Vue提供了 component ,来展现对应名称的组件 --> <!-- component 是一个占位符, :is 属性,能够用来指定要展现的组件的名称 --> <!-- 此处的`comName`是变量,变量值为组件名称 --> <component :is="comName"></component> </div> <script> // 组件名称是 字符串 Vue.component('login', { template: '<h3>登陆组件</h3>' }) Vue.component('register', { template: '<h3>注册组件</h3>' }) // 建立 Vue 实例,获得 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' // 当前 component 中的 :is 绑定的组件的名称 }, methods: {} }); </script> </body> </html>
效果:
想学习代码以外的软技能?不妨关注个人微信公众号:生命团队(id:vitateam
)。
扫一扫,你将发现另外一个全新的世界,而这将是一场美丽的意外: