前端面试题

CSS

盒模型

  • 模型的组成大家肯定都懂,由里向外content,padding,border,margin.

  • 盒模型是有两种标准的,一个是标准模型,一个是IE模型。

  • 盒模型的宽高只是内容(content)的宽高,而在IE模型中盒模型的宽高是内容(content)+填充
    (padding)+边框(border)的总宽高。

css如何设置两种模型
这里用到了CSS3 的属性 box-sizing

/* 标准模型 */
box-sizing:content-box;

 /*IE模型*/
box-sizing:border-box;

CSS的单位和应用场景及Rem的设置
在这里插入图片描述
rem浏览器兼容性:
IE9以上等支持CSS3的浏览器是肯定的可以支持的,如果想要兼容IE低版本,那可以考虑针对IE9以下低版本浏览器,用px来实现
1rem = 16px
1px = 2rpx

定位,回流与重绘

定位:position 属性

  • absolute 生成绝对定位的元素,相对于值不为 static 的第一个父元素进行定位。
  • fixed (老 IE 不支持) 生成绝对定位的元素,相对于浏览器窗口进行定位。
  • relative 生成相对定位的元素,相对于其正常位置进行定位。
  • static 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right z-index 声明)。
  • inherit 规定从父元素继承 position 属性的值。

Reflow,即回流
一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树
Repaint,即重绘。
意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就可以了

回流产生原因

页面渲染初始化
DOM结构改变,比如删除了某个节点
render树变化,比如减少了padding
窗口resize
最复杂的一种:获取某些属性,引发回流

CSS 选择符有哪些?哪些属性可以继承?

  • id 选择器( # myid)

  • 类选择器(.myclassname)

  • 标签选择器(div, h1, p)

  • 相邻选择器(h1 + p)

  • 子选择器(ul > li)

  • 后代选择器(li a)

  • 通配符选择器( * )

  • 属性选择器(a[rel = “external”])

  • 伪类选择器(a:hover, li:nth-child)

  • 可继承的样式: font-size font-family color, UL LI DL DD DT;

  • 不可继承的样式:border padding margin width height ;

CSS 优先级
优先级为: !important > id > class > tag important 比 内联优先级高

如何居中 div?

  • 负 margin 方法
    在父元素上position:relative;
    子元素position:absolute;left:50%;top:50%;maring-left子元素宽度的一半 margin-top子元素高度的一半

  • 位移方法
    和负 margin 方法方法一样
    子元素把margin改为

    transform:translate(-50%,-50%)

  • table-cell方法

通过将盒子转换为 table 元素,table 元素本身是可以通过属性来控制位置,div 上面 的 vertical-align: middle 是控制垂直方向上的居中的,而 text-align: center 是控制 水平方向的

 <div>
    <img src='1.png'/>
 </div>
 <style>
   div{
      width:300px;
      height:300px;
      background:#eee;
      display:table-cell;
      vertical-align:middle;
      text-align:center;
   }
   img{
     vertical-align:middle;
   }
 </style>
  • div绝对定位水平垂直居中 margin:auto实现绝对定位元素的居中

       div{
             width:200px;
             height:200px;
             background:pink;
             position:absolute;
             left:0;
             top:0;
             bottom:0;
             right:0;
             margin:auto;
          }
    
  • 弹性盒
    父元素设置

      display:flex;
      align-items:center;  控制垂直方向居中
      just-content:center;  控制水平方向居中
    

display 有哪些值?说明他们的作用。

  • block 象块类型元素一样显示。

  • none 缺省值。象行内元素类型一样显示。

  • inline-block 象行内元素一样显示,但其内容象块类型元素一样显示。

  • list-item 象块类型元素一样显示,并添加样式列表标记。

  • table 此元素会作为块级表格来显示

  • inherit 规定应该从父元素继承 display 属性的值

IFC、BFC与清除浮动
浮动元素引起的问题
(1)父元素的高度无法被撑开,影响与父元素同级的元素
(2)与浮动元素同级的非浮动元素(内联元素)会跟随其后
(3)若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示 的结构
解决方法:
使用 CSS 中的 clear:both;属性来清除元素的浮动可解决 2、3 问题,对于问题 1,添 加如下样式,给父元素添加 clearfix 样式:

  .clearfix:after{
     content: ".";
     display: block;
     height: 0;
     clear: both;
     visibility: hidden;
    }
    .clearfix{
      display: inline-block;
    }

清除浮动的几种方法:
1,额外标签法,

(缺点:不过这个办法会增加额 外的标签使 HTML 结构看起来不够简洁。)
2,使用 after 伪类 #parent:after{ content:"."; height:0; visibility:hidden; display:block; clear:both; }
3,浮动外部元素
4,设置 overflow 为 hidden 或者 auto
兼容处理
常见的浏览器内核可以分四种:
Trident、Gecko、Blink、Webkit
常见的兼容性问题:
1、不同浏览器的标签默认的外补丁( margin )和内补丁(padding)不同
解决方案: css 里增加通配符 * { margin: 0; padding: 0; }

2、IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题
解决方案:设置display:inline;

3、当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度
解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度

4、图片默认有间距
解决方案:使用float 为img 布局

5、IE9一下浏览器不能使用opacity
解决方案:
opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);

6、边距重叠问题;当相邻两个元素都设置了margin 边距时,margin 将取最大值,舍弃最小值;
解决方案:为了不让边重叠,可以给子元素增加一个父级元素,并设置父级元素为overflow:hidden;

7、cursor:hand 显示手型在safari 上不支持
解决方案:统一使用 cursor:pointer

8、两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;
解决方案:父级元素设置position:relative

原生JS

闭包
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭突破作用链域,将函数内部的变量和方法传递到外部。
闭包的特性:
1,函数内再嵌套函数
2,内部函数可以引用外层的参数和变量
3,参数和变量不会被垃圾回收机制回收 闭包的使用场景 常见的闭包的使用场景就是模块化,用来做模块内部的实现通过接口的扩展贡块使用
在就是闭包可以用来缓存值,减少不必要的技术,例如 vue 里面的计算属性
闭包的适用场景
闭包的适用场景非常广泛,首先从闭包的优点出发就是:

  • 减少全局环境的污染生成独立的运行环境

模块化就是利用这个特点对不同的模块都有自己独立的运行环境,不会和全局冲突, 模块和模块之间通过抛出的接口进行依赖使用 以及像我们常用的jquery类库(避免和全局冲突使用闭包实现自己独立的环境)

  • 可以通过返回其他函数的方式突破作用域链 可以利用这个功能做一些值的缓存工作

例如常见的设计模式(单例模式),以及现 在比较火的框架vue中的计算属性
其实当遇到以下场景的时候都可以使用闭包
1.维护函数内的变量安全,避免全局变量的污染。
2.维持一个变量不被回收。
3.封装模块
闭包的缺点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大。所以在闭包不用之 后,将不使用的局部变量删除,使其被回收。在IE中可能导致内存泄露,即无法回收 驻留在内存中的元素,这时候需要手动释放
构造函数

  • new实例之后发生了什么

    function New(func){
          //声明一个中间对象,该对象为最终返回的实例
         var res = {};
         if(func.prototype != null){
         //将实例的原型指向构造函数的原型
        res.prototype = func.prototype;
        }
        //ret为构造函数执行的结果,这里通过```apply```,将构造函数内部的```this```指向修改为指向```res```,即实例对象
        var ret = func.apply(res,Array.prototype.slice.call(arguments,1));
        //当我们在构造函数上明确指定了返回对象时,那么```new```的执行结果就是该返回对象
        if((typeof ret === 'object' || typeof ret === 'function')&&ret != null){
               return ret;
        }
     return res;
     }
    

1、声明一个中间对象
2、将该中间对象的原型指向构造函数的原型
3、将构造函数中的this指向该中间对象
4、返回该中间对象,即返回实例对象

  • 构造函数存在的问题:

每个方法都要在每个实例上重新创建一遍。(每定义一个函数就是实例化了一个对象),不同实例上的同名函数是不相等的。其解决方法便是使用原型模型
原型模式:

  • 每个函数都有一个属性prototype,这个属性对应的值是一个对象,我们叫做原型对象
    原型对象的作用:该对象的属性和方法是被所有的实例共享的,换句话就是所有的实例都能使用原型对象的属性和方法

  • 原型对象有一个constructor属性指向构造函数
    即Person.prototype.constructor指向Person

  • proto

function A(){
}
var a1 = new A();
console.log(A.prototype.constructor===A);//true
console.log(a1.proto===A.prototype);//true
var A = new Function()
//A是一个函数 A是Function的一个实例
console.log(A.proto===Function.prototype);//true
//Array 构造函数 是Function的一个实例每个对象都有这个属性,实例的__proto__指向的是原型对象(该属性对应的值就是原型对象)

变量提升配合作用域链
原型链

  • 原型链继承
    每个构造函数都有一个指向原型对象的属性(prototype),每个原型对象也有一个指向构造函数的一个属性(constructor),
    每个实例都有一个指向原型对象的属性(proto)

如果我把某个类型(假如A)原型对象指向另外一个类型(假如是B)的实例,
该A的原型对象是不是也有一个属性指向另外一个类型的(B)原型对象,如果我再把B的原型对象指向另外一个类型(假如是C),上面的结论仍然成立,
层层递进,形成了实例与原型对象的一个链条,就被称作原型链

function A(){
    }
function B(){
    }
A.prototype = new B();
console.log(A.prototype.constructor==B)//TRUE
console.log(A.prototype.__proto__==B.prototype)//TRUE
console.log(B.prototype.__proto__==Object.prototype)//TRUE
//A继承B  B继承Object
console.log(Object.prototype.__proto__);//null

注意:
使用原型链的方式进行继承,子类型定义自己的方法或者子类型重写父类型的方法,注意书写的位置,
要放在原型链继承的那条语句下面
当对象访问属性或方法时,先从自身查找,找不到就去构造函数的原型对象上找,如果找不到,就去原型对象的原型对
象上找,直到 Object.prototype.proto == null. 如果没找到,返回 undefined。

原型链继承的问题:
父类型的引用类型的属性会被子类型所有的实例共享
原型链继承一般不会单独使用

  • 构造函数继承
    在子类型的构造函数里面调用父类型的构造函数,使用call或者apply
    但是构造函数继承解决原型链引用数据类型的问题,但是它还有作为构造函数自己的问题
    构造函数继承一般也不会单独使用
function B(name,age,famliy){
        this.name = name;
        this.age = age;
        this.famliy = famliy;
        this.friends = ["zhangsan","lisi","wangwu"];
    }
B.prototype.say = function(){
        console.log("能说话");
    }
 function  A(name,age,famliy){
       (第一种方法) B.call(this,name,age,famliy);
       (第二种)B.apply(this,[name,age,famliy]);
       (第三种)B.apply(this,arguments);    this指s1
    }
s1 = new A("aa",21,"张");
 B.prototype.say = function(){
        console.log("能说话");
    }
 s1.say();     //报错
  • 通常使用原型链和构造函数结合起来进行继承
   function Father(name,age){
        this.name = name;
        this.age = age;
        this.friends = ["zhangsan","lisi","wangwu"];
    }
    Father.prototype.say = function(){
        console.log("能说话");   //能说话
    }
    function Son(name,age){
        Father.call(this,name.age);//this指s1
    }
    Son.prototype = new Father();
    var s1 = new Son("heihei",20);
    console.log(s1.friends);//["zhangsan", "lisi", "wangwu"]
    s1.say();
  • 系统自带继承关系

在javascript 中,继承就是靠原型链来实现的。
Array 继承了Object Function 继承了Object Date 继承了Object RegExp 继承了Object

    Array.prototype=new Object()
    Array.prototype.__proto__===Object.prototype
    Function.prototype.__proto__===Object.prototype
    Date.prototype.__proto__===Object.prototype
    Object.prototype.__proto__===null
  • 确定原型和实例的关系:
    实例 instanceof 构造函数
    原型对象.isPrototypeOf(实例)

event loop
event delegation/proxy
节流与防抖
防抖,直到事件触发间隔频率大于一定时间再触发一次

export function Debounce(func, ms=500){
let timer = 0;
return function(){
        window.clearTimeout(timer);
        timer = setTimeout(()=>{
            func()
        }, ms)
    }
}

节流,事件每隔一定时间一定触发一次

export function Throttle(func, ms=500){
let start = +new Date();
return function(){
        let current = +new Date();
        if (current - start > ms){
            func()
            start = current;
        }
    }
}

Promise原理

  • Promise的实例有三种状态

    1 成功 resolve 2 失败 reject 3 进行中 pending

  • promise的实例有一个then方法
    该方法有两个参数,第一个参数是成功对应的函数,第二个参数是失败对应的函数;
    第二个参数可以省略不写,可以写到catch里面

p1.then(function(){}).catch(funtion(){})

  • Promise的两个方法
    Promise.all([p1,p1]) all方法接收一个由多个Promise组成的数组作为参数,返回一个新的Promise实例
    当数组里面的所有的实例都是成功的状态,那么这个新的实例它的状态才是成功,
    并且返回的数据是这多个实例返回的数据组合成的数组
    失败的状态:有一个实例失败,那么这个新实例的状态就是失败,并且新实例返回的数据是最先失败的那个实例的数据
    race
    和all方法类似,接收一个由多个Promise组成的数组作为参数,返回一个新的Promise实例
    哪一个实例最先执行完,该实例对应的状态就是新的实例的状态,并且返回的数据也是新的实例的数据

SPA路由原理
前端路由: 随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载
优点:
1、用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,界面展现快。
2、可以再浏览器中输入指定想要访问的url路径地址。
3.实现了前后端的分离,方便开发。有很多框架都带有路由功能模块。
缺点:
1、对SEO不是很友好
2、在浏览器前进和后退时候重新发送请求,没有合理缓存数据。
3,初始加载时候由于加载所有模块渲染,会慢一点。

  • SPA 中前端路由有2中实现方式
    修改 url 中 Hash
    利用 H5 中的 history

hash
www.test.com/#/ 就是 Hash URL,当 # 后面的哈希值发生变化时,可以通 过 hashchange 事件来监听到
URL 的变化,从而进行跳转页面,并且无论哈希值如何 变化,服务端接收到的 URL 请求永远是 www.test.com
window.addEventListener(‘hashchange’, () => { // … 具体逻辑 })Hash
模式相对来说更简单,并且兼容性也更好。
History 模式
History 模式是 HTML5 新推出的功能,主要使 用 history.pushState 和 history.replaceState 改变 URL。
通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录。
// 新增历史记录 history.pushState(stateObject, title, URL)
// 替换当前历史记录 history.replaceState(stateObject, title, URL)
当用户做出浏览器动作时,比如点击后退按钮时会触发 popState 事件
window.addEventListener(‘popstate’, e => {
// e.state 就是 pushState(stateObject) 中的 stateObject console.log(e.state)
})

  • 两种模式对比
    1.Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的 同源 URL
    2.History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更 改哈希值,也就是字符串
    3.Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者 刷新页面的时候会发起 URL 请求,后端需要配置 index.html 页面用于匹配不到静态资 源的时候

本地存储localStorage、sessionStorage与cookie之间的区别
cookie是网站为了标示用户身份而储存在用户本地终端上的数据(通 常经过加密),cookie还可以设置有效时间 cookie数据始终在同源的http请求中携带(即使不需要),会在浏览器和服务器间 来回传递, 每次ajax请求都会吧cookie传送到后台,cookie一半用做用户登陆,后台可以根cookie信息判断用户是否登陆状态
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
区别在于
存储大小:
cookie数据大小不能超过4k。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得 多,可以达到5M或更大。
有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

Vue

深入Vue的响应原理?
“响应式”,是指当数据改变后,Vue 会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新。
当一个Vue实例创建时,vue会遍历data选项的属性,用Object.defineProperty将它们转为getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。

Vue多版本之间的区别(运行时依赖,运行时编译)?
Vue中computed、watch与methods的区别
https://blog.csdn.net/lfcss/article/details/89136943
多种指令与自定义指令

  • 局部自定义指令(只针对组件内的元素)
directives:{
    // 自定义指令的名字
    autoFocus:{
      // 钩子函数,被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
      inserted(el){
        el.focus()
        console.log( 'inserted' );
      }
   }
}
  • 定义全局自定义指令
    在任意页面的任意input里加上v-autoFcs
Vue.directive('autoFcs',{
  // 钩子函数,被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
  inserted(el){
    el.focus()
    console.log( 'inserted' );
  }
}

路由传参与导航守卫

  • 父子传参
    props
    父组件上,通过动态属性传递
    子组件,props接收
    1.数组形式接收
    2.对象形式接收

props:{
属性名:类型
}

  • 子父传参

子组件里面使用$emit
$emit(’事件名称‘,‘实参1’,‘实参2’) 触发

 <button @click="$emit('addCount',count)"></button>

父组件里面的子组件使用
@事件名称=’事件处理程序‘

<list @addCount='add'></list>

  • 非父子通信
    在main.js里面Vue.prototype.$bus=new Vue()
    子组件
    在methods里面

this.$bus.$emit('addCount',num,id)

非父组件 $bus
在created 生命周期写

this.$bus.$on('addCount',(num,id)=>{
    
})

Element UI && so on
什么是MVVM?
MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。
【模型】指的是后端传递的数据。
【视图】指的是所看到的页面。
【视图模型】mvvm模式的核心,它是连接view和model的桥梁。
它有两个方向:
一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信
在这里插入图片描述

React

虚拟dom和真实dom

  • 虚拟DOM的损耗计算:
    总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删改 + (较少的节点)排版与重绘

  • 直接使用真实DOM的损耗计算:
    总损耗 = 真实DOM完全增删改 + (可能较多的节点)排版与重绘
    VDOM的渲染流程
    获取数据
    根据数据创建VDOM (相当于给对象赋值)
    根据VDOM渲染生成真实DOM ( 根据createElmeent(‘DIV’) )
    当数据发生改变后,又会生成新的VDOM
    通过 diff 算法 比对 多次生成的 VDOM, 将不同的内容比对出来,然后在进行真实DOM渲染,
    一样的内容是不会进行渲染的,这就是VDOM 的 ‘就地复用’ | ‘惰性原则’
    React与Vue的区别与联系?

  • 监听数据变化的实现原理不同
    Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染

  • 数据流的不同
    Vue中默认是支持双向绑定的
    React一直提倡的是单向数据流,他称之为 onChange/setState()模式。

  • 模板渲染方式的不同
    React 是通过JSX渲染模板
    Vue是通过一种拓展的HTML语法进行渲染
    React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的
    Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现

  • Vuex 和 Redux 的区别
    在 Vuex 中,$store 被直接注入到了组件实例中
    在 Redux 中,我们每一个组件都需要显示的用 connect 把需要的 props 和 dispatch 连接起来。
    Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改

详细介绍生命周期(三个阶段,生命周期的触发顺序)?
三个阶段:挂载、更新、卸载
在这里插入图片描述
新生命周期
出生阶段
1.constructor :初始化设置
2.static getDerivedStateFromProps 更新state状态 监听props变化
return 对象 state变化会重复这个生命周期
return null 不会重复调用
3.render 渲染dom节点
4.componentDidMount 组件初始渲染完成
成长阶段 state或者props发生变化都会执行
1.static getDerivedStateFromProps 更新state状态 监听props变化
2.shouldComponentUpdate 是否要执行更新
return true/false
3.render
4.getSnapshotBeforeUpdate 组件更新完成之前执行 snapshot 快照
必须配合componentDidUpdate 这个生命周期使用
该函数的返回值 就是componentDidUpdate 的第三个参数
5.componentDidUpdate 组件更行新完成
6.死亡阶段componentWillUnmount
合成事件与改变this指向的三种方式及之间的区别?
React合成事件一套机制:React并不是将click事件直接绑定在dom上面,而是采用事件冒泡的形式冒泡到document上面,然后React将事件封装给正式的函数处理运行和处理。
改变this指向
在构造函数constructor this.fn=this.fn.bind(this)
在调用函数时绑定 this.fn.bind(this)
箭头函数 fn=()=>{}
样式绑定与CSS Modules
多种组件创建方式及其区别?

  • 函数定义的无状态组件
    为了创建纯展示组件 只负责根据传入的props来展示,不涉及到要state状态的操作,无生命周期,不能访问this对象
  • React.Component
  • 其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。

什么是受控组件?
假设我们现在有一个表单,表单中有一个input标签,input的value值必须是我们设置在constructor构造函数的state中的值,然后,通过onChange触发事件来改变state中保存的value值,这样形成一个循环的回路影响。也可以说是React负责渲染表单的组件仍然控制用户后续输入时所发生的变化。

高阶组件与装饰器
组件通信的多种方式及其之间的区别

  • 父组件向子组件通信
    props
  • 子组件向父组件通信
    利用回调函数
    父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信
  • 跨级组件之间通信
    中间组件层层传递 props
    使用 context 对象
    在这里插入图片描述
let Context=React.createContext();
   console.log(Context)   //Provider提供者   Consumer 消费者
let {Provider,Consumer}=React.createContext();

父组件
在这里插入图片描述
孙子组件
在这里插入图片描述

  • 非嵌套组件间通信(同级)
    利用发布订阅者模式 先监听后触发
    可以找有共同有关系的父组件
yarn add events
let Bus=require('events');
export default new Bus()
引入
import Bus from './bus'
Bus.on('事件名',('参数1','参数2')=>{})
Bus.emit('事件名','参数1','参数2')

React Router及其简单实现

react-router依赖基础 - history
yarn add react-router-dom
BrowserRouter  不会返回dom节点 只是监听history事件

Redux数据流向及三个中间件(redux-logger、redux-thunk、redux-saga)

仓库对象里面的方法
   store.getState() 获取仓库状态    
          得到reducer函数返回值
   store.dispatch()      //会触发reducer函数
          派发reducer  必须传入一个对象action  
          action就是描述仓库状态的一个对象  对象里面必须要有一个type属性
   store,subscribe()  监听

connect实现原理
在这里插入图片描述
Ant Design && so on

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值