你们好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新......javascript
- github:https://github.com/Daotin/Web
- 微信公众号:Web前端之巅
- 博客园:http://www.cnblogs.com/lvonve/
- CSDN:https://blog.csdn.net/lvonve/
在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。如今就让咱们一块儿进入 Web 前端学习的冒险之旅吧!css
什么是组件: 组件的出现,就是为了拆分 Vue 实例的代码量的,可以让咱们以不一样的组件,来划分不一样的功能模块,未来咱们须要什么样的功能,就能够去调用对应的组件便可;html
组件化和模块化的不一样:前端
定义全局组件有三种方式:vue
一、使用 Vue.extend
配合 Vue.component
方法:java
// 1.使用 Vue.extend 来建立全局的Vue组件 var login = Vue.extend({ // 经过 template 属性,指定了组件要展现的HTML结构 template: '<h1>登陆</h1>' }); // 2.使用 Vue.component('组件的名称', 建立出来的组件模板对象) Vue.component('login', login); // 3.使用组件 <div id="app"> <!-- 若是要使用组件,直接,把组件的名称,以 HTML 标签的形式,引入到页面中便可 --> <login></login> </div>
注意:git
使用 Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名(如myLogin),则在引用组件的时候,须要把 大写的驼峰改成小写的字母,同时在两个单词以前,使用 - 连接(
<my-login></my-login>
);若是不使用驼峰,则直接拿名称来使用便可;github
固然,上面两步能够合成一个步骤完成:微信
Vue.component('login', Vue.extend({ template: '<h1>登陆</h1>' }));
二、直接使用 Vue.component 方法:app
Vue.component('login', { template: '<div><h3>注册</h3><span>123</span></div>' });
注意:不管是哪一种方式建立出来的组件,组件的 template 属性指向的模板内容,必须有且只能有惟一的一个根元素,不然会报错。
三、将模板字符串,定义到 template 标签中:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <!-- 3. 使用组件 --> <mycom></mycom> </div> <!-- 2.在 被控制的 #box 外面,使用 template 元素,定义组件的HTML模板结构 --> <template id="tmp1"> <!-- 仍是须要听从template 模板内容,必须有且只能有惟一的一个根元素 --> <div> <h3>登陆</h3> <p>p标签</p> </div> </template> <script> // 1.定义组件 Vue.component('mycom', { template: '#tmp1' }); var vm = new Vue({ el: "#box", data: {}, methods: {} }); </script> </body> </html>
注意:
一、
template: '#tmp1'
是定义模板标签的 id ,# 别忘写了。二、被控制的 #box 外面,使用 template 标签;
三、 template 标签里面,仍是听从只能有惟一的一个根元素的原则。
定义私有组件,就是再VM实例中定义组件。
以下,box中可使用,box2不可使用。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <mycom></mycom> </div> <div id="box2"> <mycom></mycom> </div> <template id="temp"> <h3>自定义私有属性</h3> </template> <script> var vm = new Vue({ el: "#box", data: {}, methods: {}, // 定义私有组件 components: { mycom: { template: '#temp' } } }); var vm2 = new Vue({ el: "#box2", data: {}, methods: {} }); </script> </body> </html>
组件中也能够有本身的data和methods属性,能够传入template中使用。
特色:
<div id="box2"> <login></login> </div> <template id="temp2"> <div> <input type="button" value="按钮" @click="myclick"> <h3>自定义私有属性</h3> <p> {{msg}} </p> </div> </template> <script> Vue.component('login', { template: '#temp2', data: function () { return { msg: '这是组件中的data' } }, methods: { myclick() { console.log("点击按钮"); } } }); </script>
咱们在登陆注册一个网站的时候,常常看到两个按钮,一个登陆,一个注册,若是你没有帐号的话,须要先注册才能登陆。咱们在点击登陆和注册的时候,网页会相应的切换,登陆页面就是登录组件,注册页面就是注册组件,那么点击登陆和注册,如何实现组件的切换呢?
使用flag
标识符结合v-if
和v-else
切换组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <!-- 给a注册点击事件,切换flag状态 --> <a href="javascript:;" @click.prevent="flag=true">登陆</a> <a href="javascript:;" @click.prevent="flag=false">注册</a> <!-- 使用v-if v-else切换组件 --> <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: "#box", data: { flag: true }, methods: {} }); </script> </body> </html>
缺陷:因为flag的值只有true和false,因此只能用于两个组件间 的切换,当大于两个组件的切换就不行了。
使用 component元素的:is
属性来切换不一样的子组件
使用 <component :is="componentId"></component>
来指定要切换的组件。
componentId:为须要显示的组件名称,为一个字符串,可使用变量指定。
componentId: 'login'
// 默认显示登陆组件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <!-- 给a注册点击事件,切换flag状态 --> <a href="javascript:;" @click.prevent="componentId='login'">登陆</a> <a href="javascript:;" @click.prevent="componentId='register'">注册</a> <component :is="componentId"></component> </div> <script> Vue.component('login', { template: '<h3>登陆组件</h3>' }); Vue.component('register', { template: '<h3>注册组件</h3>' }); var vm = new Vue({ el: "#box", data: { componentId: 'login' // 默认显示登陆 }, methods: {} }); </script> </body> </html>
为组件切换添加过渡:
很简单,只须要用 transition 将 component 包裹起来便可。
<transition> <component :is="componentId"></component> </transition>
示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <link rel="stylesheet" href="./lib/animate.css"> <style> .loginDiv { width: 200px; height: 200px; background-color: red; } .registerDiv { width: 200px; height: 200px; background-color: blue; } </style> </head> <body> <div id="box"> <!-- 给a注册点击事件,切换flag状态 --> <a href="javascript:;" @click.prevent="componentId='login'">登陆</a> <a href="javascript:;" @click.prevent="componentId='register'">注册</a> <transition mode="out-in" enter-active-class="animated bounceInRight" leave-active-class="animated bounceOutRight"> <component :is="componentId"></component> </transition> </div> <template id="login"> <div class="loginDiv"> </div> </template> <template id="register"> <div class="registerDiv"> </div> </template> <script> Vue.component('login', { template: '#login' }); Vue.component('register', { template: '#register' }); var vm = new Vue({ el: "#box", data: { componentId: 'login' }, methods: {} }); </script> </body> </html>
mode="out-in"
:能够设置切换组件的模式为先退出再进入。
咱们先经过一个例子看看子组件可不能够直接访问父组件的数据:
<body> <div id="box"> <mycom></mycom> </div> <template id="temp"> <h3>子组件 --- {{msg}}</h3> </template> <script> var vm = new Vue({ el: "#box", data: { msg: '父组件的msg' }, methods: {}, components: { mycom: { template: '#temp' } } }); </script> </body>
因为 components 定义的是私有组件,咱们直接在子组件中调用父组件的msg会报错。
那么,怎么让子组件使用父组件的数据呢?
父组件能够在引用子组件的时候, 经过 属性绑定(v-bind:) 的形式, 把须要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 。
<body> <div id="box"> <mycom v-bind:parentmsg="msg"></mycom> </div> <template id="temp"> <h3>子组件 --- 父组件:{{parentmsg}}</h3> </template> <script> var vm = new Vue({ el: "#box", data: { msg: '父组件的msg' }, methods: {}, components: { mycom: { template: "#temp", // 对传递给子组件的数据进行声明,子组件才能使用 props: ['parentmsg'] } } }); </script> </body>
注意:父组件绑定的属性名称不能有大写字母,不然不会显示,而且在命令行会有提示:
组件data数据和props数据的区别:
案例:发表评论功能
父组件为评论列表,子组件为ID,评论者,内容和按钮的集合,在输入ID,评论者等内容,而后点击添加的时候,须要首先获取子组件的list列表,而后再添加新的列表项到列表中。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <mycom :plist="list"></mycom> <ul> <li v-for="item in list" :key="item.id"> ID:{{item.id}} --- 内容:{{item.content}} --- 评论人:{{item.user}} </li> </ul> </div> <template id="tmp1"> <div> <label> ID: <input type="text" v-model="id"> </label> <br> <label> 评论者: <input type="text" v-model="user"> </label> <br> <label> 内容: <textarea v-model="content"></textarea> </label> <br> <!-- 把父组件的数据做为子组件的函数参数传入 --> <input type="button" value="添加评论" @click="addContent(plist)"> </div> </template> <script> var vm = new Vue({ el: "#box", data: { list: [{ id: Date.now(), user: 'user1', content: 'what' }, { id: Date.now(), user: 'user2', content: 'are' }] }, methods: {}, components: { mycom: { template: '#tmp1', data: function () { return { id: '', user: '', content: '', } }, methods: { addContent(plist) { plist.unshift({ id: this.id, user: this.user, content: this.content }); } }, props: ['plist'] } } }); </script> </body> </html>
把添加ID,评论人,内容做为子组件,把列表做为父组件,而后把添加的数据放到父组件列表上,因为要获取到父组件列表的数据,因此必然涉及到父组件向子组件传值的过程。这里还经过子组件方法参数来保存父组件的数据到子组件的数据中。
既然父组件能够向子组件传递数据,那么也能够向子组件传递方法。
<body> <div id="box"> <mycom v-bind:parentmsg="msg" @parentfunc="show"></mycom> </div> <template id="temp"> <div> <input type="button" value="调用父组件方法" @click="sonClick"> <h3>子组件 --- 父组件:{{parentmsg}}</h3> </div> </template> <script> var vm = new Vue({ el: "#box", data: { msg: '父组件的msg' }, methods: { show(data1, data2) { console.log("这是父组件的show方法" + data1 + data2); } }, components: { mycom: { template: "#temp", // 对传递给子组件的数据进行声明,子组件才能使用 props: ['parentmsg'], methods: { sonClick() { // 调用父组件的show方法 this.$emit("parentfunc", 111, 222); } } } } }); </script> </body>
一、
@parentfunc="show"
绑定父组件的show方法。二、
<input type="button" value="调用父组件方法" @click="sonClick">
点击按钮调用父组件的show方法三、在 子组件的 sonClick 方法中使用
this.$emit("parentfunc");
来调用父组件的show方法四、父组件的show方法也能够传参,在调用的时候,实参从 this.$emit 的第二个参数开始传入。
五、若是 this.$emit 的第二个参数传的是子组件的data数据,那么父组件的方法就能够得到子组件的数据,这也是把子组件的数据传递给父组件的方式。
咱们知道Vue不推荐直接获取DOM元素,那么在Vue里面怎么获取DOM及组件元素呢?
咱们呢能够在元素上使用 ref
属性来获取元素。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="box"> <input type="button" value="获取元素" @click="getrefs" ref="mybtn"> <h3 ref="myh3">这是H3</h3> <mycom ref="mycom"></mycom> </div> <template id="tmp1"> </template> <script> // 定义组件 Vue.component('mycom', { template: '#tmp1', data: function () { return { msg: '子组件的msg', pmsg: '' } }, methods: { show(data) { console.log('调用子组件的show'); this.pmsg = data; console.log(this.pmsg); }, } }); var vm = new Vue({ el: "#box", data: { parentmsg: '父组件的msg' }, methods: { getrefs() { console.log(this.$refs.myh3); console.log(this.$refs.mycom.msg); this.$refs.mycom.show(this.parentmsg); } } }); </script> </body> </html>
总结:
一、ref 属性不只能够获取DOM元素,也能够获取组件(不管全局仍是私有组件)元素。
二、获取到组件元素后,就能够获取组件元素的data数据和methods方法。
三、获取到组件中的方法后,能够传入VM的data数据,就能够把VM的data数据传入组件中。