前言
什么是组件
组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。
模块化和组件化的区别
全局组件的定义和注册
组件Component
是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。
全局组件的定义和注册有三种方式,我们接下来讲一讲。
写法一
写法一:使用Vue.extend方法定义组件,使用 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> var myAccount = Vue.extend({ template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>' }); Vue.component('account', myAccount);
new Vue({ el: '#app' }); </script> </body>
</html>
|
上方代码中,在注册组件时,第一个参数是标签名,第二个参数是组件的定义。
运行结果如下:
代码截图如下:
上图中,注意两点:
注意1、红框部分,要保证二者的名字是一致的。如果在注册时,组件的名称是驼峰命名,比如:
Vue.component('myComponent', myAccount);
|
那么,在标签中使用组件时,需要把大写的驼峰改为小写的字母,同时两个单词之间使用-
进行连接:
<my-component> </my-component>
|
所以,为了避免名字不一致的问题,我们注册组件时,组件的名称可以直接写成my-component
。比如:(避免驼峰不一致的建议写法)
Vue.component('my-component', myAccount);
|
注意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>' });
new Vue({ el: '#app' }); </script> </body>
</html>
|
代码截图如下:
上图中,同样注意两点:
1、红框部分,要保证二者的名字是一致的。
2、绿框部分,一定要用一个大的根元素(例如<div>
)包裹起来。如果我写成下面这样,就没有预期的效果:
template: '<h2>登录页面</h2> <h3>注册页面</h3>'
|
结果如下:(并非预期的效果)
写法三【荐】
上面的写法一、写法二并不是很智能,因为在定义模板的时候,没有智能提示和高亮,容易出错。我们不妨来看看写法三。
写法三:将组件内容定义到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' });
new Vue({ el: '#app' }); </script> </body>
</html>
|
代码截图如下:
写法三其实和方法二差不多,无非是把绿框部分的内容,单独放在了<template>
标签中而已,这样有利于 html 标签的书写。
使用components定义私有组件
我们在上一段中定义的是全局组件,这样做的时候,多个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"> <my-login></my-login> </div>
<script>
new Vue({ el: '#app', data: {}, components: { 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"> <my-login></my-login> </div>
<script> new Vue({ el: '#app', data: {}, components: { myLogin: { template: '#loginTmp' } } }); </script> </body>
</html>
|
运行效果不变。
上方代码中,如果在注册私有组件时,组件的名称是驼峰命名,比如:
components: { myLogin: { template: '#loginTmp' } }
|
那么,在标签中使用组件时,需要把大写的驼峰改为小写的字母,同时两个单词之间使用-
进行连接:
所以,为了避免名字不一致的问题,我们注册组件时,组件的名称可以直接写成my-login
。比如:(避免驼峰不一致的建议写法)
components: { `my-login`: { template: '#loginTmp' } }
|
为组件添加 data 和 methods
既然组件是一个页面,那么,页面中可能会有一些功能要动态展示。因此,我们有必要为组件添加 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> {{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: function () { return { myData: 'smyhvae' } }, methods: { login: function () { alert('login操作'); } } });
new Vue({ el: '#app' }); </script> </body>
</html>
|
上方代码所示,我们在account
组件中添加的data 和 methods,其作用域只限于account
组件里,保证独立性。
注意,在为组件添加数据时,data不再是对象了,而是function,而且要通过 return的形式进行返回;否则,页面上是无法看到效果的。通过 function返回对象的形式来定义data,作用是:
为什么组件的data必须是一个function
我们先来看下面这样的例子:
<!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 }
Vue.component('counter', { template: '#tmpl', data: function () { return dataObj }, methods: { increment() { this.count++ } } })
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 }
Vue.component('counter', { template: '#tmpl', data: function () { return { count: 0 } }, methods: { increment() { this.count++ } } })
var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body>
</html>
|
运行效果:
如上图所示,每当我们创建一个新的组件实例时,就会调用data函数,data函数里会return一个新开辟的对象数据。这样做,就可以保证每个组件实例有独立的数据存储。
组件的切换
使用v-if和v-else结合flag进行切换
代码举例:(登录组件/注册组件,二选一)
<!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"> <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>' })
var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body>
</html>
|
运行效果如下:
使用Vue提供的<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">
<component :is="'login'"></component>
</div>
<script> Vue.component('login', { template: '<h3>登录组件</h3>' })
Vue.component('register', { template: '<h3>注册组件</h3>' })
var vm = new Vue({ el: '#app', data: { comName: 'login' }, 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">
<component :is="'register'"></component>
</div>
<script> Vue.component('login', { template: '<h3>登录组件</h3>' })
Vue.component('register', { template: '<h3>注册组件</h3>' })
var vm = new Vue({ el: '#app', data: { comName: 'login' }, 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"> <a href="" @click.prevent="comName='login'">登录</a> <a href="" @click.prevent="comName='register'">注册</a>
<component :is="comName"></component>
</div>
<script> Vue.component('login', { template: '<h3>登录组件</h3>' })
Vue.component('register', { template: '<h3>注册组件</h3>' })
var vm = new Vue({ el: '#app', data: { comName: 'login' }, methods: {} }); </script> </body>
</html>
|
效果:
多个组件切换时,通过mode属性添加过渡的动画
<!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> <style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); }
.v-enter-active, .v-leave-active { transition: all 0.5s ease; } </style> </head>
<body> <div id="app"> <a href="" @click.prevent="comName='login'">登录</a> <a href="" @click.prevent="comName='register'">注册</a>
<transition mode="out-in"> <component :is="comName"></component> </transition>
</div>
<script> Vue.component('login', { template: '<h3>登录组件</h3>' })
Vue.component('register', { template: '<h3>注册组件</h3>' })
var vm = new Vue({ el: '#app', data: { comName: 'login' }, methods: {} }); </script> </body>
</html>
|
运行效果:
如上方代码所示,多个组件切换时,如果要设置动画,可以用<transition>
把组件包裹起来。需要注意的是,我给<transition>
标签里添加了mode="out-in"
这种模式,它表示第一个组件消失之后,第二个组件才会出现。如果没有这个mode属性,效果如下:(第一个组件准备消失的时候,第二个组件马上就准备出现,这不是我们想要的效果)
我的公众号
想学习更多技能?不妨关注我的微信公众号:千古壹号(id:qianguyihao
)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外: