vuejs组件化开发

vuejs 组件化

什么是组件化开发?

组件化开发是近两年流行起来的一个开发模式,把日常项目开发中一些常用的代码块封装起来,封装成一个一个的功能块,这个功能块里面包含了 结构、样式、行为、数据(state)、生命周期等。然后在做项目开发时候,项目的那些页面就由这些小的组件然后进行构成,类似乐高积木。

网站:(网页—>组件—>封装代码块)

常见的可以复用的代码:

  • 按钮
  • 弹出框
  • 模态框
  • badge 徽章
  • Icon

vuejs组件化开发
组件其实就是开发者自己封装好的 HTML标签。因为原生的html标签非常的有限。

为什么要引入组件化开发?

就是为了代码的复用,后期的维护方便。同时为了后期的扩展功能也是非常方便,同时后期别人接受也是很好接受。

vuejs如何进行组件化开发?

Vue.component()

vuejs 常见的第三方的组件库有哪些?

  • ElementUI (pc端项目) (饿了么前端团队)

    • https://element.eleme.cn/#/zh-CN/component/drawer
  • MintUI (移动端项目) (饿了么前端团队)

    • http://mint-ui.github.io/docs/#/
  • iview (个人)

    • https://weapp.iviewui.com/components/switch
  • uview (一般配合 uniapp 做小程序和其他的移动端使用)

    • https://www.uviewui.com/components/button.html
  • vantUI(移动端UI)(有赞团队)

    • https://vant-contrib.gitee.io/vant/#/zh-CN/goods-action

组件

全局组件的基本用法

先学习自己自定义组件尝试一下.
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>

vuejs组件化开发
烤串法和小驼峰命名

	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>

vuejs组件化开发
总结: 在用户自定义组件的时候,组件的名称建议使用 烤串法命名,这样的定义的时候不出错,调用时候自然不会出错!

全局组件的样式和行为

		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>
        `
    });

vuejs组件化开发

	<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>

vuejs组件化开发

动态组件

官方提供:
component 特点:该组件显示什么内容,取决于我们给该组件的is属性对应的属性是哪个组件,就显示哪个组件的内容

 <component :is="my-component1"></component>
	Vue.component('my-compoent1', {
        template: `
          <div>
            <h2>组件的HTML结构</h2>
            <h2>组件的HTML结构</h2>
          </div>
        `
    });

vuejs组件化开发
一般可以去做一个选项卡

<!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组件化开发
vuejs组件化开发

组件间的通信问题

(vuejs面试必问)

什么是组件间的通信问题?

由于页面是由组件构成的,那么组件间存在关系。

常见的关系如下:

  • 嵌套关系
    • 父子嵌套(父组件,子组件)
    • 爷孙嵌套
  • 平级
    • 兄弟组件

有了这种关系后,组件是需要进行数据的传递,这个时候就称之为 组件间的通信问题。
常见的通信:

  • 父子通信(属性传递)
  • 子父通信(回调函数)
  • 兄弟通信(1. 公共的父组件 2. EventBus 事件车)

上面的这些通信方式全部可以使用一个叫做 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>

vuejs组件化开发
如果父组件要往子组件传东西,父亲定义一个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>
        `
    });

vuejs组件化开发

子父通信(回调函数)

1.需要在父组件自定义一个事件(事件的名称用户自定义),然后在 methods 定义好自定义事件的回调函数

<son-component @giveMoney="callback" :qian="money" :title="title"></son-component>

定义方法

		methods: {
            callback(data) {
                console.log('来自儿子的问候:', data); // data 儿子传递过来的信息(儿子:子组件)
            }
        },
  1. 在子组件里面触发父组件里面自定义的事件
<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>

vuejs组件化开发

兄弟通信

例子:熊大要发送一个信息给熊二,告知熊二,今天下午五点一起去揍光头强;熊二回复熊大,信息已收到,没有问题。

	<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

  • 事件车:1. 实例化一个事件车
 const EventBus = new Vue();
  • 通信:存在一个主动方(信息是谁发起的),被动方(信息的接受者)
  • 事件车:2. 需要在被动方的 created 生命周期函数里面设置监听事件(用户自定义)
  • 事件车:3. 需要在主动方的业务代码去触发第二步里面的监听事件

一开始熊二是被动方,在熊二组件的生命周期函数里用到事件车,通过.$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>

vuejs组件化开发
熊二收到信息后要给熊大回信息,此时熊二为主动方,熊大为被动方。
此时熊大做事件监听:

		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>

vuejs组件化开发

上一篇:Vue脚手架 Vue Cli (安装 | Vue CLI (vuejs.org))


下一篇:Vue全家桶系列(vue3中更新中。。。)