zoukankan      html  css  js  c++  java
  • Vue组件通信应知必知

    前言

    本章我们来学习Vue组件通信中的可以算是所有内容,在此之前,您最好掌握Vue的基础语法、指令等内容,同时也建议您查看我其他的文章进行补充。

    组件通信

    父子组件关系

    file
    通过上图顺带给大家说明了父子组件的实现原理,以及组件间传值传DOM的实现思路,那么我们看看Vue的代码来感受一下

    父向子传值

    模板部分(此处传值也能使用组件内的变量)

    <div id="app">
        	<!-- 传递一个字符串常量haha -->
             <son v-bind:text="'haha'"/>
    </div>
    

    js部分

            // 子组件
            var Son = {
                // 要接收的字段名称
                props:['text'], 
                template:`
                    <div>
                        {{ text }}
                    </div>`
            };
            Vue.component('son',Son);
            // 父组件
            new Vue({
                el:'#app'
            });
    

    显示结果很显然是子组件的haha

    子向父通信

    试想一种情况,由父组件控制子组件的显示,而从子组件中点击X来实现子组件的隐藏,那么实际的控制权确实在父组件

    file

    要处理这个问题,大家第一反应应该就是相当通过子组件的点击事件,拿到父组件内控制显示与隐藏的变量并更改就可以了

    代码如下

    // 隐藏按钮点击函数
    methods:{
    	clickChild(){
            this.$parent.isShow = false;
        }
    }
    

    实现是对的,不过file

    在框架中,我们最好抛开以前的DOM思想,否则我们会无法体会到框架带给我们的思想,而永远沉寂在面向过程中。。。

    事件通信机制

    在Vue中我们用@xxx来给原生DOM元素绑定事件,比如:click、input等。。

    那么同时,我们也可以给子组件绑定自定义事件,不论他叫什么名字。举例:

    <!-- 父组件 -->
    <son v-show="isShow" @callme="callmeFn"/>
    
    // 父组件js
    methods:{
    	callmeFn(params){
    		this.isShow = false;
        }
    }
    

    接下来子组件只用触发这个事件就好了,从低耦合的角度来说,是不是父子各玩各的呢?

    // 子组件点击函数中,触发父组件为其绑定的事件
    this.$emit('callme','还可以传递参数')
    

    子向父值同步扩展

    对于刚才的例子,我们实际上无需父组件和子组件函数的执行,只需要在子组件点击时同步父组件的isShow的值即可,那么可以这样写

    <!-- 父组件内 -->
    <son v-show="isShow" :isShow.sync="isShow"/>
    

    从子组件中的代码你可以看出原理还是基于事件

    // 子组件内
    this.$emit('update:isShow','value')
    

    通过Vue提供的事件对象来实现多层级别的组件通信

    要做的只有类似这样3步

    • 创建一个共同通信的对象
    let connector = new Vue();
    
    • 在要触发事件的函数中注册事件
    connector.$on('事件名',function(params){ });
    
    • 在目标事件中触发以上事件
    connector.$emit('事件名','value');
    

    事件原理实现

    大家对于on,emit可能已经看得比较痛苦了,有懵逼的吧?那话不多说,直接上源码实现,相信会让你感觉好一点

    	var store = {
    			once:{},
    			fns:{},
    			on(key,fn,isOnce){
    				this.fns[key]?this.fns[key].push(fn):this.fns[key] = [fn];
    			},
    			emit(key,value){
    				let t = this.fns[key];
    				let o = this.once[key];
    				if (!t)return;
    				t.forEach(fn=>{
    					fn(value);
    				});
    				if (o)	this.off(key);
    			},
    			off(key) {
    					delete this.fns[key];
    			},
    			once(key,fn){
    				this.once[key] = true;
    				this.on(key,fn);
    			}
    		}
    

    原理其实就是一个对象用key存储着事件名,用value存储着函数!

    传递DOM元素

    看下面的功能,9宫格的6个,看看这些组件样子一样却又各不相同,因此,我们可以尝试由父组件给他们不同的DOM来体现他们的不同,子组件只需要做一些对他们公共特点的编写即可

    file

    如果子元素的大部分所有内容由父元素来定制,子组件内尽量单一、简单,该组件就算是低耦合、高内聚了。

    那么子组件中给父组件留下的内容区域如何来实现呢? 答案是:slot(插槽)

    slot实现步骤

    1. 在子组件中留坑
    <!-- 子组件 -->
    <div>
        <!--一个默认的坑-->
        <slot></slot>
    </div>
    
    1. 在父组件中传入DOM
    <!-- 父组件 -->
    <!-- 使用子组件 -->
    <son>
    	<!--传递的DOM-->
        <template v-slot:default>
            <button>给子的按钮</button>
        </template>
    </son>
    
    1. 当然也可以具名传递
    <!-- 子组件 -->
    <div>
        <!-- 定制上半部分 -->
        <slot name="head"></slot>
        <!-- 定制下半部分 -->
        <slot name="foot"></slot>
    </div>
    
    1. 父组件也需要说清楚名字
    <!-- 父组件 -->
    <!-- 使用子组件 -->
    <son>
    	<!--传递的DOM-->
        <template v-slot:head>
            <button>给头的按钮</button>
        </template>
         <template v-slot:foot>
            <button>给底部的按钮</button>
        </template>
    </son>
    

    最后说说一般人说不清楚的内容

    file

    思路整理: 这一组ul+li我们把他想象成一个组件,他接收一个数组,通过v-for帮我们渲染,数据如下

    // 父组件数据
    todos: [
        	{
                id: 0,
                text: 'ziwei0',
                isComplete: true
            },
            {
                text: 'ziwei1',
                id: 1,
                isComplete: true
            },
            {
                text: 'ziwei2',
                id: 2,
                isComplete: false
            },
            {
                text: 'ziwei3',
                id: 3,
                isComplete: false
            }
    ];
    

    父组件把该对象传递给子组件

    <son :todos="todos"></son>
    

    剩下的就交给子组件,让它来处理具体的业务吧! 对吗?

    file

    不是说好了,让子组件功能尽量单一,高内聚、低耦合的么,它都处理业务了,还谈啥公共组件呢,复用性不高,pass!

    因此我们将业务判断功能留给父组,子组件这么写

     <!--子组件-->
      <ul>
        <li v-for="todo in todos" :key="todo.id">
          <slot>
          </slot>
        </li>
      </ul>
    

    那么问题来了,父组件是不是要传递DOM作为slot的值呢?

    	<!--父组件-->
    	<son :todos="todos">
            <template v-slot:default>
                <span>✓</span>
                <span>内容</span>
            </template>
    	</son>
    

    糟糕,父组件把todos都传递进去了,可现在要通过每一个todo来做业务处理啊,看张图

    file

    因此,我们使用2.6的新功能slotProps,看slot 传值

     <!--子组件-->
      <ul>
        <li v-for="todo in todos" :key="todo.id">
          <slot :todo="todo">
          </slot>
        </li>
      </ul>
    

    看父组件如何接收,看template那里(固定写法) slotProps相当于内置变量

    <!--父组件-->
    	<son :todos="todos">
    				<template v-slot:default="slotProps">
                        <span v-if="slotProps.todo.isComplete">✓</span>
                    	<span>{{slotProps.todo.text}}</span>
               	    </template>
    			</son>
    

    搞定!如果你喜欢我的文章,可以关注我,如果忍不住想天天看到我,可以联系我加入我们的前端讨论群

  • 相关阅读:
    kafka window环境搭建
    oracle 日期格式化和数据去重
    angular $http服务详解
    Spring框架之beans源码完全解析
    计算机经典书籍100本分享
    Thinking in Java 4th(Java编程思想第四版)文档、源码、习题答案
    Spring框架之事务源码完全解析
    TCP/IP网络协议层对应的RFC文档
    Spring源码深度解析之事务
    Spring框架之websocket源码完全解析
  • 原文地址:https://www.cnblogs.com/qidaoxueyuan/p/12378631.html
Copyright © 2011-2022 走看看