什么是组件化开发?
组件化开发是近两年流行起来的一个开发模式,把日常项目开发中一些常用的代码块封装起来,封装成一个一个的功能块,这个功能块里面包含了 结构、样式、行为、数据(state)、生命周期等。然后在做项目开发时候,项目的那些页面就由这些小的组件然后进行构成,类似乐高积木。
网站:(网页—>组件—>封装代码块)
常见的可以复用的代码:
组件其实就是开发者自己封装好的 HTML标签。因为原生的html标签非常的有限。
为什么要引入组件化开发?
就是为了代码的复用,后期的维护方便。同时为了后期的扩展功能也是非常方便,同时后期别人接受也是很好接受。
vuejs如何进行组件化开发?
Vue.component()
vuejs 常见的第三方的组件库有哪些?
ElementUI (pc端项目) (饿了么前端团队)
MintUI (移动端项目) (饿了么前端团队)
iview (个人)
uview (一般配合 uniapp 做小程序和其他的移动端使用)
vantUI(移动端UI)(有赞团队)
…
先学习自己自定义组件尝试一下.
vuejs 组件: 1. 全局组件 2. 局部组件 定义组件,必须写在实例化之前。
参数1(string): 组件的名称,
1.1 一般使用烤串法进行命名(abc-def-ghi)每个单词使用小写,中间使用中线串起来。
1.2 同时也可以使用小驼峰的方式,但是如果是以小驼峰的方式命名的话,则在调用的时候,要使用烤串法调用。 参数2(object):组件的描述对象(1. 结构 html代码 2. 样式 Css 3. 行为 js事件 4. data 5.
生命周期函数)
Vue.component('mycompoent1', { /* tempalate 必须的,同时在写的过程中,这个模板文件有且仅有一个根节点*/ template: ` <div> <h2>组件的HTML结构</h2> <h2>组件的HTML结构</h2> </div> ` });
//html页面里之间引用定义好的组件名 <mycompoent1></mycompoent1>
烤串法和小驼峰命名
Vue.component('my-compoent2', { template: ` <div> <h2>组件的HTML结构</h2> <h2>组件的HTML结构</h2> </div> ` }); /*小驼峰命名法*/ /* 调用:myCompoent3--->my-component3*/ Vue.component('myCompoent3', { template: ` <div> <h2>组件的HTML结构</h2> <h2>组件的HTML结构</h2> </div> ` });
<my-compoent2></my-compoent2> <hr> <my-compoent3></my-compoent3>
总结: 在用户自定义组件的时候,组件的名称建议使用 烤串法命名,这样的定义的时候不出错,调用时候自然不会出错!
Vue.component('mycompoent1', { created() { console.log('组件 mycomponent1产生了'); // 一般会发生网络请求 this.getCommentList(); }, /*属于组件自己的数据要使用一个 data函数来定义,该函数的返回值是一个对象,该对象里面的数据我们一般称之为 模型数据,模型数据里面的属性称之为模型变量,模型变量可以在template里面使用*/ data() { return { title: 'hi component!', counter: 0, result: [], page: 1, limit: 5, } }, /*组件也是可以存在 methods 的这个里面就写我们事件的回调函数*/ methods: { async getCommentList() { // axios 发生网络请求 let url = `http://localhost:3000/api/v1/comment/list?page=${this.page}&limit=${this.limit}`; try { // 请求完成 this.isLoading = false; const res = await axios.get(url); // res.data 响应体 this.result = res.data.data.result; console.log('this.result ', this.result); } catch (e) { this.result = []; alert('获取信息失败!'); return; } }, clickHandler() { this.counter++; console.log('clickHandler'); } }, template: ` <div style="color:red;"> <h2>我的第一个组件</h2> <p>行为:事件</p> <h3>{{ title }}</h3> <p>counter: {{ counter }}</p> <button @click="clickHandler()">点击我</button> <hr> <hr> <ul v-for="ele in result"> <li>序号:{{ ele._id }}</li> <li>用户名:{{ele.username}}</li> <li>评论日期:{{ele.addTime}}</li> <li>评论内容:{{ele.content}}</li> </ul> </div> ` });
<mycompoent1></mycompoent1> <mycompoent1></mycompoent1> <mycompoent1></mycompoent1>
组件是可以高度复用的,想用多少次就用多少次
要先定义
new Vue({ el: '#app', data: {}, /*定义局部组件的位置*/ components: { /*key:组件名称 烤串法; value:组件描述对象*/ 'my-component2': myComponent1, 'my-component1': myComponent2, } });
将组件描述对象提取出来了,可以不提取,但是提取了会更精简一些。
const myComponent1 = { //支持生命周期函数 created() { console.log('created'); }, data() { return { counter: 0, } }, methods: { clickHandler() { this.counter++; console.log('clickHandler'); } }, template: ` <div style="color: blue;"> <h1>我是第二个局部组件!</h1> <p>counter:{{ counter }}</p> <button @click="clickHandler">点击我</button> </div> ` }; const myComponent2 = { created() { console.log('created'); }, data() { return { counter: 0, } }, methods: { clickHandler() { this.counter++; console.log('clickHandler'); } }, template: ` <div style="color: blue;"> <h1>我是第一个局部组件!</h1> <p>counter:{{ counter }}</p> <button @click="clickHandler">点击我</button> </div> ` };
组件调用:1. 双标签 2. 单标签 自闭合
建议:双标签调用;如果是一单一双,有一个出不来
<!--<my-component1/>--> <my-component1></my-component1> <hr> <my-component2></my-component2>
官方提供:
component 特点:该组件显示什么内容,取决于我们给该组件的is属性对应的属性是哪个组件,就显示哪个组件的内容
<component :is="my-component1"></component>
Vue.component('my-compoent1', { template: ` <div> <h2>组件的HTML结构</h2> <h2>组件的HTML结构</h2> </div> ` });
一般可以去做一个选项卡
<!DOCTYPE html> <html lang="zh_CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title</title> <style> * { margin: 0; padding: 0; } .list { width: 200px; height: 50px; display: flex; } .list li { border: 1px solid #000; width: 80px; height: 50px; line-height: 50px; text-align: center; list-style: none; cursor: pointer; } .list li.active { background-color: gold; } </style> </head> <body> <div id="app"> <ul class="list"> <li :class="{'active': currentComponent == 'my-component1'}" @click="selectComponent('my-component1')">正在热映... </li> <li :class="{'active': currentComponent == 'my-component2'}" @click="selectComponent('my-component2')">即将上映... </li> </ul> <!--keep-alive 也是官方提供的,可以直接使用,该组件的作用可以保存组件的状态,不会让组件重新的生成和销毁--> <keep-alive> <component :is="currentComponent"></component> </keep-alive> </div> </body> <script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> Vue.component('my-component1', { template: ` <div> <h2>我是第一个组件!</h2> <p>正在热映...</p> <hr> </div> ` }); Vue.component('my-component2', { template: ` <div> <h2>我是第二个组件!</h2> <p>即将上映...</p> <hr> </div> ` }); new Vue({ el: '#app', data: { currentComponent: 'my-component1', }, methods: { selectComponent(item) { console.log('item', item); this.currentComponent = item; } } }); </script> </html>
(vuejs面试必问)
什么是组件间的通信问题?
由于页面是由组件构成的,那么组件间存在关系。
常见的关系如下:
有了这种关系后,组件是需要进行数据的传递,这个时候就称之为 组件间的通信问题。
常见的通信:
上面的这些通信方式全部可以使用一个叫做 vuex 方案进行解决。
Vue.component('father-component', { template: ` <div> <h2>父组件</h2> <p>父亲的钱:{{ money }}</p> <hr> //直接在父组件里用子组件 <son-component></son-component> </div> ` }); Vue.component('son-component', { template: ` <div> <h3>子组件</h3> <hr> </div> ` });
<father-component></father-component>
如果父组件要往子组件传东西,父亲定义一个data放东西,子组件定义prpos拿东西
Vue.component('father-component', { data() { return { money: 1000, title: '我是父组件的内容!' } }, template: ` <div> <h2>父组件</h2> <p>父亲的钱:{{ money }}</p> <hr> <son-component :qian="money" :title="title"></son-component> </div> ` }); Vue.component('son-component', { props: ['qian', 'title'], template: ` <div> <h3>子组件</h3> <p>来自父亲的钱:{{ qian }}</p> <hr> <p>{{ title }}</p> <hr> </div> ` });
1.需要在父组件自定义一个事件(事件的名称用户自定义),然后在 methods 定义好自定义事件的回调函数
<son-component @giveMoney="callback" :qian="money" :title="title"></son-component>
定义方法
methods: { callback(data) { console.log('来自儿子的问候:', data); // data 儿子传递过来的信息(儿子:子组件) } },
<button @click="giveMeSameMoney">老爸,给我点生活费</button>
定义方法
methods: { giveMeSameMoney() { console.log('giveMeSameMoney'); /*第一个参数,父组件里面定义的自定义事件,第二个参数传递该事件回调函数的参数*/ /*第二个参数:一般叫做 payload 载荷*/ this.$emit('giveMoney', {money: 2000}); // this.$emit 是 vuejs 提供的 } },
3.父亲接收
方法接收
this.message = data.money;
<p>来自儿子的问候:{{ message }}</p>
整个代码
Vue.component('father-component', { data() { return { money: 1000, title: '我是父组件的内容!', message: '', } }, methods: { callback(data) { console.log('来自儿子的问候:', data); // data 儿子传递过来的信息(儿子:子组件) this.message = data.money; } }, /* 子父通信:1.需要在父组件自定义一个事件(事件的名称用户自定义),然后在 methods 定义好自定义事件的回调函数*/ template: ` <div> <h2>父组件</h2> <p>父亲的钱:{{ money }}</p> <p>来自儿子的问候:{{ message }}</p> <hr> <son-component @giveMoney="callback" :qian="money" :title="title"></son-component> </div> ` }); Vue.component('son-component', { props: ['qian', 'title'], methods: { giveMeSameMoney() { console.log('giveMeSameMoney'); /*第一个参数,父组件里面定义的自定义事件,第二个参数传递该事件回调函数的参数*/ /*第二个参数:一般叫做 payload 载荷*/ this.$emit('giveMoney', {money: 2000}); // this.$emit 是 vuejs 提供的 } }, /*子父通信:2. 在子组件里面触发父组件里面自定义的事件*/ template: ` <div> <h3>子组件</h3> <p>来自父亲的钱:{{ qian }}</p> <p>需求:儿子觉得父亲给的钱不够,那么希望父亲给多一点?(回调函数实现?)</p> <button @click="giveMeSameMoney">老爸,给我点生活费</button> <hr> <p>{{ title }}</p> <hr> </div> ` }); new Vue({ el: '#app', data: {} });
<div id="app"> <father-component></father-component> </div>
例子:熊大要发送一个信息给熊二,告知熊二,今天下午五点一起去揍光头强;熊二回复熊大,信息已收到,没有问题。
<xiong-da-component></xiong-da-component> <hr> <xiong-er-component></xiong-er-component>
Vue.component('xiong-da-component', { template: ` <div> <h2>熊大-组件</h2> </div> ` }); Vue.component('xiong-er-component', {template: ` <div> <h3>熊二二-组件</h3> </div> ` });
公共的父组件 1. 熊大信息给父组件(回调函数)2. 父组件信息给熊二(属性传递)
EventBus 事件车 计算机网络里的三大总线 1. 地址总线 2. 控制总线 3. 寻址总线 2^64
const EventBus = new Vue();
一开始熊二是被动方,在熊二组件的生命周期函数里用到事件车,通过.$on设置监听函数(函数用户自定义)
created() { /*被动方:onClick*/ EventBus.$on('waitForMyBigBrotherGiveMeCall', (data) => { console.log('来自大哥的电话:', data); }); },
熊大作为主动方来触发这件事情,在熊大组件里button创建一个点击事件
<button @click="callMyLitterBrother">打电话告知熊二</button>
data() { return { message: '今天下午五点一起去揍光头强', } }, methods: { /*主动方:触发监听事件*/ callMyLitterBrother() { EventBus.$emit('waitForMyBigBrotherGiveMeCall', {message: this.message}); } },
熊二接收到信息之后
data() { return { myMessage: '', } }, created() { /*被动方:onClick*/ EventBus.$on('waitForMyBigBrotherGiveMeCall', (data) => { console.log('来自大哥的电话:', data); this.myMessage = data.message; }); },
<p>来自大哥的电话信息:{{ myMessage }}</p>
熊二收到信息后要给熊大回信息,此时熊二为主动方,熊大为被动方。
此时熊大做事件监听:
created() { /*被动方:熊大等待熊二传递信息*/ EventBus.$on('waitForMyLitterBrotherGiveMeCall', (data) => { console.log('来自小弟熊二的问候', data); }) },
熊二回消息:
<button @click="giveMeMyBigBrotherCall">回个电话给熊大</button>
data() { return { myMessage: '', message: '信息已收到,没有问题!!!', } }, methods: { giveMeMyBigBrotherCall(){ /*熊二 主动方*/ EventBus.$emit('waitForMyLitterBrotherGiveMeCall', {message: this.message}); } },
熊大接收到信息之后拿出来:
data() { return { message: '今天下午五点一起去揍光头强', myMessage: '', } }, created() { /*被动方:熊大等待熊二传递信息*/ EventBus.$on('waitForMyLitterBrotherGiveMeCall', (data) => { console.log('来自小弟熊二的问候', data); this.myMessage = data.message; }) },
<p>来自熊二的回复:{{ myMessage }}</p>
整个代码:
const EventBus = new Vue(); Vue.component('xiong-da-component', { created() { /*被动方:熊大等待熊二传递信息*/ EventBus.$on('waitForMyLitterBrotherGiveMeCall', (data) => { console.log('来自小弟熊二的问候', data); this.myMessage = data.message; }) }, data() { return { message: '今天下午五点一起去揍光头强', myMessage: '', } }, methods: { /*主动方:触发*/ callMyLitterBrother() { EventBus.$emit('waitForMyBigBrotherGiveMeCall', {message: this.message}); } }, template: ` <div> <h2>熊大-组件</h2> <button @click="callMyLitterBrother">打电话告知熊二</button> <p>来自熊二的回复:{{ myMessage }}</p> </div> ` }); Vue.component('xiong-er-component', { data() { return { myMessage: '', message: '信息已收到,没有问题!!!', } }, created() { /*被动方:onClick*/ EventBus.$on('waitForMyBigBrotherGiveMeCall', (data) => { console.log('来自大哥的电话:', data); this.myMessage = data.message; }); }, methods: { giveMeMyBigBrotherCall(){ /*熊二 主动方*/ EventBus.$emit('waitForMyLitterBrotherGiveMeCall', {message: this.message}); } }, template: ` <div> <h3>熊二二-组件</h3> <p>来自大哥的电话信息:{{ myMessage }}</p> <button @click="giveMeMyBigBrotherCall">回个电话给熊大</button> </div> ` }); new Vue({ el: '#app', data: {} });
<xiong-da-component></xiong-da-component> <hr> <xiong-er-component></xiong-er-component>