1,react diff算法特点: React组件配合 state 创建一个虚拟DOM树
根据虚拟DOM树,生成一个真正的 DOM 树,再渲染到页面中
当 state 或者 props 变化时,根据新的数据生成一个新的虚拟DOM树
将新旧虚拟 DOM 树进行对比,通过diff算法找到新旧虚拟DOM的差异点,最后将差异点更新到页面上
4,useMemo、useCallback使用场景: 1、useMemo和useCallback用法差不多,都是在第一次渲染的时候执行,然后在依赖项改变时再次执行,不同点在于,useMemo返回缓存的变量,useCallback返回缓存的函数,使用场景是:有一个父组件,其中包含子组件,子组件接收一个函数作为props;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新。
5,useEffect、useLayoutEffect区别: useEffect是异步执行,而useLayoutEffect是同步执行的。useEffect是在页面渲染完毕之后执行hooks,uselayoutEffect是在页面渲染之前执行hooks,所以uselayoutEffect会导致页面渲染堵塞,而useEffect有可能会导致页面闪动,99的情况下都用useeffect。
6, redux的三个原则、如何写一个中间件 1.数据来源的唯一性2.state只能是只读的状态3.使用纯函数进行改变
-
redux是的诞生是为了给 React 应用提供「可预测化的状态管理」机制。
-
Redux会将整个应用状态(其实也就是数据)存储到到一个地方,称为store
-
这个store里面保存一棵状态树(state tree)
-
组件改变state的唯一方法是通过调用store的dispatch方法,触发一个action,这个action被对应的reducer处理,于是state完成更新
-
组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件
-
其它组件可以通过订阅store中的状态(state)来刷新自己的视图
7,dva和redux的区别是什么: 1、定位:dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。dva = React-Router + Redux + Redux-saga;redux就是全局状态管理。
8,react和vue的区别: react整体上是函数式的思想,组件使用jsx语法,all in js,将html与css全都融入javaScript,jsx语法相对来说更加灵活。
vue的整体思想仍然是拥抱经典的html(结构)+css(表现)+js(行为)的形式,vue鼓励开发者使用template模板,并提供指令供开发者使用如v-if、v-show、v-for等指令,因此在开发vue应用的时候会有一种在写经典web应用(结构、表现、行为分离)的感觉。
一些老生常谈的 数据管理(props、data vs state),组件写法等这里就不比较了。
9,react class 组件constructor 中的super的作用
10,react组件名称为什么要大写:
babel在进行转义JSX语法时,是调用了 React.createElement() 这个方法,这个方法需要接收三个参数:type, config, children 。第一个参数声明了这个元素的类型。创建自定义组件时没有首字母大写。 而 babel 在转义时把它当成了一个字符串 传递进去了,如果传递的是一个字符串,那么在创建虚拟DOM对象时,React会认为这是一个简单的HTML标签,如果首字母大写,那么就会当成一个变量传递进去,这个时候React会知道这是一个自定义组件,因此他就不会报错了。
11,react class和hooks区别
Hooks是一个新的React特性提案,组件尽量写成纯函数,如果需要外部React特性(比如状态管理,生命周期),就用钩子把外部特性"钩"进来,通常函数名字都是以use开头。react16.8之前,函数组件中不能拥有自己的状态(state)。在hooks之前函数组件是无状态的,都是通过props来获取父组件的状态,在react16.8之后呢,出现了hooks,hooks提供了useState来维护函数组件内部的状态。。 无论是从语法的简洁性,还是逻辑组件的复用性,还是代码的可读性,hooks都比class高出一筹。
15,hooks优势是什么、使用情况
1,更容易复用代码,类组件如果要复用代码,经常需要高阶组件,但是高阶组件hoc需要在原组件上进行包括和嵌套,如果大量使用hoc会产生大量的嵌套,代码的可读性就会很擦,这让调试变得更加困难。而react hooks中通过自定义hooks可以将组件中类似的状态逻辑抽取出来,做成一个usehook,这样需要这个逻辑的页面直接调用这个自定义的hooks就好了,非常的简单便捷。代码量比较少。
3,react hooks之前是有很多生命周期的,但是react hooks下没有生命周期,几乎所有的操作都在useEffect中进行处理,而且这个useEffect的执行时机是在更新渲染之后异步执行的,不会造成浏览器阻塞
6,代码的可读性更强。
2. Hook使你在无需修改组件结构的情况下复用状态逻辑。我们经常维护一些组件,在类组件中,每个生命周期常常包含一些不相关的逻辑。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。如此很容易产生 bug,并且导致逻辑不一致。
4. React 组件一直更像是函数,而Hooks则拥抱了函数,使得React的框架理念更接近于Javascript。
5. Hooks 和现有代码可以同时工作,你可以渐进式地使用,无需放弃原有的class组件,但是使用hooks有一些注意事项:1,只在最顶层使用hook,2,不要再循环,条件或嵌套函数中使用hook。3,只在react函数中使用hook,不要再javascript函数中使用hook。
**12,react路由原理**
react-router等前端路由的原理大致相同,可以实现无刷新的条件下切换显示不同的页面。路由的本质就是页面的URL发生改变时,页面的显示结果可以根据URL的变化而变化,但是页面不会刷新。通过前端路由可以实现单页(SPA)应用,
13,react-redux原理 react-redux有两个核心,提供器provider和连接器connect,一般我们把顶层的组件包裹在provider组件中,所有的子组件都能通过props属性访问到store里的状态,connect连接器配置props能访问到state状态,connect里有两个方法,一个是mapstateprops和mapdispatchprops,这两个方法分别把state状态和各种dispatch方法映射到props里使用。
redux和react-redux的区别: react-redux和redux没有什么关系,redux是状态管理库,主要是解决了组件间状态共享的问题,原理是集中式管理。 react-redux是为了方便react使用,在redux上封装的一个库,在实际的项目中可以使用redux也可以直接使用react-redux。
14,react生命周期 为什么新增了两个静态的 目的是什么
16,react里 setState和class组件this.setState区别是什么. this.setState是修改初始化的state数据的。
react懒加载:当react项目非常庞大的时候,会导致打包文件build.js文件也特别复杂,庞大,从而导致首页加载缓慢,影响用户体验。所以我们希望有些比较大的组件,只在此组件被加载时,内部资源才被引用。这就是代码分割,也就是react.lazy的作用。
react cdn打包优化:1,在webpack.config.js里新增esternals配置项,新增files配置项,之后在build.js中配置cdn引入,最后在html文件中引入配置cdn js和css的链接就完成了cdn打包优化。 react其他优化方式:全球cdn加速,图片压缩,gzip压缩,资源懒加载,按需加载,按需打包,双页面应用。
18-react的key值的作用:
而元素key属性的作用是用于判断元素是新创建的还是被移动的元素,从而减少不必要的元素渲染。
key值作用的补充:
react中的key属性,它是一个特殊的属性,它是出现不是给开发者用的,而是给React自己使用,有了key属性后,就可以与组件建立了一种对应关系,react利用key来识别组件,他是一种身份标识。每个key 对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应组件都不会被创建。在render函数执行的时候,新旧两个虚拟DOM会进行对比,如果两个元素有不同的key,那么在前后两次渲染中就会被认为是不同的元素,这时候旧的那个元素会被销毁,新的元素会被创建。如果提供了唯一的标识key且是相同的key,且元素类型相同, 若元素属性有所变化,则React只更新组件对应的属性,这种情况下,性能开销会相对较小。
19.typescript使用:
简单来说就是因为JavaScript是弱·类型, 很多错误只有在运行时才会被发现
而TypeScript提供了一套静态检测机制, 可以帮助我们在编译时就发现错误
21,# react获取上一轮的props和state(接用 useEffect, useRef实现) 利用ref对象内容变化不会引发组件重新渲染的原理,使用useEffect结合useRef实现获取上一轮props和state的功能。因为ref对象内容发生变化时,useref并不会通知你,变更.current属性不会引发组件重新渲染。 实例代码:
**22,props是什么? **
props是属性,它是javascript对象。- props 是调用方传递给组件的数据(类似于函数的形参),而 state 是在组件内被组件自己管理的数据(类似于在一个函数内声明的变量)。
props是不可修改的,所有React组件都必须像纯函数一样保护它们的props不被更改。 由于props是传入的,并且它们不能更改,因此我们可以将任何仅使用props的React组件视为pureComponent,也就是说,在相同的输入下,它将始终呈现相同的输出。
23,useEffect详解 一,effect hook可以让你在函数组件中执行副作用操作,副作用操作包括:1,数据获取。2,设置订阅。3,获取react组件中的dom。 二,如果你熟悉react class类组件的生命周期函数,可以把useEffect hook看做componentDidMount,componentDidUpdate和componentWillUnMount这三个生命周期函数的组合
(选背)三,在React组件中有两种常见的副作用操作,有需要清除的和不需要清除的。 比如发送网络请求,手动变更dom,记录日志,这些就是常见的无需请求的操作,因为我们在执行完这些操作后就可以忽略他们了。有些副作用是需要清除的,比如订阅外部数据源,这种情况下,清除工作是非常重要的。可以防止内存泄漏。
**20什么是副作用函数?能举几个例子吗?**
解答:讲到副作用,那么你就不得不提到另外一个概念:纯函数 纯函数就是确定的输入,产生确定的输出,与执行次数,时间无关,不产生副作用 常见的副作用就是:1,系统IO相关API 2,Date.now()、Math.random()等不确定性方法 3,在函数体内修改函数外变量的值 4,在函数体内修改函数参数的值 5,调用会产生副作用的函数 6,http请求. 总结:具有不确定性的操作,你都可以理解为是不纯的,不纯的那么意味可能带来副作用。
3,typeof(null) = object是一个历史遗留的bug,它不应该是一个对象的,如果修改了这个bug会导致很多问题,所以索性就不修改了。
4,foreach()中的return只会结束此次循环,执行下一次循环 for中的return和break会直接跳出循环,不在执行下面的循环 如何让foreach()直接跳出循环:使用try,catch方法捕获异常实现。
1,js数组中查找目标值: find()
2,Object对象本身就有一个toString()方法,返回的是当前对象的字符串形式,原型上的toString()返回的才是我们真正需要的包含对象数据类型的字符串。
24,useEffect第二个参数可以是函数吗?
25.浅拷贝的几种方式: Object.assign,slice(),concat(),扩展运算符. 深拷贝的几种方式:_.cloneDeep(),JSON.parse(JSON.stringify()),循环递归.
26.基本类型和引用类型: 基本类型有6种:Number,String,Boolean,Undefined,Null,symbol. 基本类型存储在栈中,引用类型存储在堆中。
27.new操作做了什么事情: 1,创建一个新的对象obj,2,将对象与构造函数通过原型链连接起来。3,将构造函数中的this绑定到新建的对象obj上。4,判断构造函数返回值类型,如果是原始值则被忽略,如果是对象则需要正常处理。
28。ES6中class与构造函数的关系 class为构造函数的语法糖,即class的本质是构造函数,class的继承extends本质为构造函数的原型链的继承。 类的写法: class Person{ constructor(name,age){//constructor是一个构造方法,用来接收参数 this.name = name, this.age = age //this代表实例对象。 }
say(){ //这是一个类的方法,注意千万不要加上function return this.name + this.age } }
let obj = new Person('六小格','18') console.log(obj.say())
构造函数的写法: function Person(name,age){ this.name = name, this.age = age //this.代表实例对象 } Person.prototype.say = function(){ return this.name + this.age } let obj = new Person('六小格','18') //通过构造函数创建person对象,必须使用new运算符。 console.log(obj.say())
总结:通过class定义的类,和通过构造函数定义的类二者本质相同,并且在js执行时,会将第一种转换成第二种执行,所以class的写法实质就是构造函数。
29.new是干啥用的: new一个构造函数可以搞出来一个实例化对象. 构造函数与普通函数的区别:
*对象和数组 初始化的时候不要用构造函数,要用函数声明式
构造函数开头是大写,普通函数是小写
构造函数可以用new 函数名和实例调用,普通函数就是函数名和实例
构造函数在new的时候就创建了一个实例化对象,而且将this指向指向了这个实例化对象,而普通函数的在函数输入实例化对象执行后,this指向也是实例化以后的对象
构造函数通过new调用能够返回一个实例化以后的对象
webpack里的chunk是什么:chunk是module模块的封装单位,chunk包含着多个模块。 souceMap是什么? sourcemap是将编译打包,压缩后的代码映射回源代码的过程,打包压缩后的源码不具备可读性,而sourcemap可以调试源码
我最近的做的项目是是个ctrm风险管理系统,这个后台管理系统主要是对风险管理平台的期货数据展示,是给内部人员开发的一个管理平台,内容人员可以通过工作台看到当前市场快讯和期货展示(利用websocket技术获取接口数据)以及产品展示。管理员可以添加员工账号并赋予员工一定的权限。 这个项目所用到的技术栈有 react ,react-router,axios,hox,echarts和antdesign,websocket , 我在这个项目里主要是负责登录模块,路由导航模块和期货数据展示模块,产品动态展示模块,axios封装模块等,登录模块:用户在登录的时候输入账号和密码通过请求登录接口返回token和用户信息,返回的token值我是放在了localstorage中。在这个项目里对axios进行二次封装,其中封装了axios请求拦截器axios.interceptors.request.use ,在请求拦截器中将登录获取到的token值保存到请求头中以方便每天请求都携带token,和响应拦截器axios.interceptors.response.use以便于对服务器返回的数据进行拦截修改操作(可以做登录失效返回login登录页面重新获取token值),用户导航模块首先是获取接口数据,返回对应用户的路由映射表之后通过antdesign里的menu导航组件渲染对应用户的路由侧边栏,路由表通过map循环遍历出路由item,首先是通过判断数据中每个item中的路由是否有children对象字段,如果有的话就证明是父子路由就渲染submenu标签,反之则渲染menuitem标签,用递归的方法在函数内在调用此函数就能形成递归并循环出子路由。 在用户权限模块我是先获取用户权限列表渲染用户权限,然后实现分配用户权限的功能,利用antdesign的tree树形组件对用户的权限以树状图的形态进行展示,并根据需求封装了递归函数,对每个 用户的权限进行递归循环处理,将用户权限目录转换成树形结构的数据展示出来。在这个项目我还负责期货数据展示模块,由于展示的是期货数据,数据是在很短的时间内就要更新的,这个时候如果只是简单的请求接口获取数据的话,每次需要数据更新的时候我还要点击刷新浏览器才能更新,这样显然是不行的,这个时候我想到了两个方法,第一个方法是ajax请求函数轮询,第二个方法就是使用websocket,websocket协议简称双向绑定协议,客户端既能向服务端发送数据,反之服务端也能向客户端发送请求。这个是用来实现数据无刷更新的功能,这个模块主要是使用echarts框架配合,websocket双向通信协议,这里我用到了echarts的矩形树图,首先是请求数据接口获取到数据之后,使用map方法遍历数据并修改数据中的某个值,修改好后定义一个变量把数据赋值给变量,同时建立websocket请求,首先初始化websocket实例并封装websocket函数,我封装的这个websocket函数中里有三个参数,第一个变量是请求的url地址,第二个变量是请求的参数,第三个变量放入请求返回的数据信息,在这里我判断websocket状态,如果状态是open的话就是正常返回数据,状态为closed的的话就返回连接异常,如果返回数据成功了就对通过websocket返回成功的数据和之前通过请求期货数据接口所获得的数据进行替换操作,方法是通过map循环对比两个数据体的type值,如果type值相同的话,就进行数据替换,这样就能实现数据实时更新的效果,而websocket的特性就是第一次连接成功后之后就不需要再次连接很方便,且没有同源限制,客户端可以与任意的服务器端通信,不存在跨域的问题。 项目扩展: 1,封装Table表格组件并具有搜索,编辑和删除的功能:在这个项目里有许多模块都需要用到table组件来展示期货的产品,所以我索性封装了table组件,首先这个table组件具有添加产品,搜索产品,和删除产品的功能,因为好多的页面只有table表格,且样式几乎都是一样的,所以我在定义页面路由的时候,将不同path地址所对应的组件都设置成一个组件地址,在这几个页面路由中加入category字段,在点击切换路由跳到这个table组件的时候传入对应的category字段来请求数据,这样每次请求的数据都是不同的,就实现了多个页面使用一个组件的功能,之后就是获取table表格接口数据渲染table表格,搜索table表格的数据的功能是通过修改请求表格接口的参数重送数据请求来实现搜索的功能,添加产品的功能是通过请求添加产品的接口返回数据,通过数组的扩展运算符和原数据的数组拼接在一起以达到添加产品的功能,删除产品的功能是通过请求删除接口放入对应id来实现删除产品的功能。
**** 2,local时效性,私密性,命名规范:*** localStorage是HTML5本地存储的api,使用键值对的方式进行存取数据,存取的数据只能是字符串。 localStorage的好处就是,存储空间大,长时间保存,同一浏览器,标签页全部共享。不好的地方就是永久有效,除非手动清除。所以如果有数据时效性的需求,就需要自己来处理下,可以和数据一起存易data时间戳。
const set = (key, value) => { const curTime = new Date().getTime(); Window.localStorage.setItem(key, JSON.stringify({ data: value, time: curTime }));
}; const get = (key, exp) => { const localData = localStorage.getItem(key); const localDataObj = JSON.parse(localData); const nowTime = new Date().getTime(); if (nowTime - localDataObj.time > exp) { console.log("数据已过期"); //删除 localStorage.removeItem(key); return false; } else { const data = JSON.parse(localDataObj.data); return data; } }; const value = '{"name":"yd"}'; set("info", value) get("info", 1000) get("info", 1000 * 60 * 60)
1,react17特性 2,hooks是什么 3,说一下webpack 4,hox简单说一下 5,react-router路由权限搭配动态路由和路由拦截简单说一下。 6,axios封装配合api封装简单说一下 7,路由侧边栏怎么渲染的 8,期货数据怎么渲染的说一下 9,封装localstorage时效性说一下 10,请求拦截器和响应拦截器分别做了什么? 11,react项目优化方式? 12,table表格如何封装? 13,说一下useEffect是干什么的,useEffect第二个参数是函数会是什么情况 14,useRef特性 ,15,umi是什么,16,webpack在项目中做了哪些配置,17,promise对axios封装的实际运用场景,18,讲一下rem+flex百分比方案适配首页,19,讲一下系统如何优化,20,如何封装tree组件,21,
1,react17特性:
React 17中的 JSX 转换不会将 JSX 转换为 React.createElement,
而是自动从 React 的 package 中引入新的入口函数并调用。
另外此次升级不会改变 JSX 语法,旧的 JSX 转换也将继续工作。
说一下hox: hox 是完全拥抱 React Hooks 的状态管理器,model 层也是用 custom Hook 来定义的,它有以下几个特性:
- 只有一个 API,简单高效,几乎无需学习成本
- 使用 custom Hooks 来定义 model,完美拥抱 React Hooks
- 完美的 TypeScript 支持
- 支持多数据源,随用随取
-
定义 Model
react hooks性能优化方式:
react里定义的state变量,每个值的变化都会触发一次渲染,举个例子,现在有个父子组件,子组件依赖父组件传入的name属性,但是父组件name属性和text属性变化都会导致parent函数重新执行,即使传入子组件props没有任何变化,甚至子组件没有依赖任何props属性,都会导致子组件渲染。
想要解决重复渲染的问题,有几种方式。
方式1,react.memo,方式2,useMemo。方式3,useCallback
react.memo:使用 memo 包裹子组件时,只有 props 发生改变子组件才会重新渲染。使用 memo 可以提升一定的性能。
useCallback:useCallback 用于缓存函数,只有当依赖项改变时,函数才会重新执行返回新的函数,对于父组件中的函数作为 props 传递给子组件时,只要父组件数据改变,函数重新执行,作为 props 的函数也会产生新的实例,导致子组件的刷新(使用 useCallback 可以缓存函数。需要搭配 memo 使用)
useMemo用于数值计算,并缓存数值,下次获取值就不用重复计算。
2022.7.30 面试题: 问题一,bfc解决了什么实际上的问题? 答: 1,解决margin重叠(塌陷),当两个标签设置同一个属性,属性里面设置的margin为100px,按道理说两个标签的上下边距为margin-top+margin-bottom = 200px,但实际上边距是100px,这就是marign重叠(塌陷),解决方法就是给其中一个标签用一个带有bfc属性的标签嵌套,这样就能解决margin塌陷问题。 2,清除浮动,设置了一个父div标签,里面有两个标签,当父元素里面其中一个标签设置float属性,则该父元素就会失去支撑,从而没有高度,形成高度塌陷,这个时候可以给父元素设置overflow:hidden形成bfc属性,这样就能清除float浮动从而解决高度塌陷。 overflow:hidden作用是当元素内的内容溢出的时候使它隐藏溢出的部分,即超出部分隐藏。
问题二,Promise.all 和 Promise.race的区别? 1,promise.all里可以放多个数据,比如ajax请求,返回的数据顺序不会改变,即使第二条的数据返回速度比第一条快,最后的返回顺序依旧是从上往下的,如果有一条数据返回失败,下面的请求数据就不会再执行。 2,promise.race相当于赛跑,里面放多个数据请求,哪个数据先请求完就返回先请求完的数据,其他数据不返回,不管结果是成功还是失败,失败的请求返回的快也可以返回。 使用场景:有些时候我们做一个操作可能需要不同接口返回的数据,这个时候可以用promise.all 有时候我们比如有好几个服务器的好几个接口都提供同样的服务,我们不知道哪个接口更快,这个时候就可以用promise.race比较哪个接口更快并返回数据。
问题三,useState里第二个set方法和class类组件里的setstate方法的区别是什么? 1,参数不同,setState(updata,[callback]) : updata是用于更新数据,callback用于获取更新后的state值, const [state,setstate] :state表示状态,setstate表示更改状态的方法。 2,setState会自动浅合并,而useState不会。 3,setstate和usestate都是异步操作,无法直接获取state的值。
问题四,websocket比ajax轮询的优势在哪里? websocket是基于tcp的socket通道进行传输数据,能够做到一次链接后复用。 轮询的本质还是通过http请求,每次会话都要建立链接,而后才能数据传输。
问题五,作用域是什么? es5的时候,作用域有函数作用域和全局作用域,在es6的时候有了块级作用域,就是一个{}里面定义变量,代码块外获取不到{}里的变量,这就是块级作用域。 let和const方法在{}内定义的变量可以使之成为块级作用域,而var定义的话是不行的。
任意一个 custom Hook ,用 createModel 包装后,就变成了持久化,且全局共享的数据。
import { createModel } from 'hox';
/* 任意一个 custom Hook */
function useCounter() {
const [count, setCount] = useState(0);
const decrement = () => setCount(count - 1);
const increment = () => setCount(count + 1);
return {
count,
decrement,
increment
};
}2
export default createModel(useCounter)
小知识:new Map():Map,它类似于对象,也是一种键值对的数据结构,但是键的范围不仅仅是字符串,各种的类型的值(函数,对象,数组)都可以当成键。map的实例属性和方法:size,set,get,delete,has,clear
项目一 难点1,: 通过安装webpack-bundle-analyzer依赖来分析项目打包速度和资源的体积,之后可以通过CDN抽离lodash、echarts等静态资源包(甚至可以抽取vue源码和vue.runtime.min.js),可以通过bootCDN这个链接网站来查找这些cdn包随后放到index.html中。因为cdn是具有缓存机制的,每次从cdn拉取的依赖和vue源码都会缓存在浏览器中使用,这些依赖就不会放到dist文件夹中,这样就能优化项目打包速度和资源的体积。 举例一些其他的优化方法:当项目的图片量过多的时候,就会占很大的内存,这个时候可以将img图片传给后端服务器上,然后让后端发图片对应的链接过来。 难点2,: 1,封装axios请求拦截器实现拦截重复请求: 当用户点击请求按钮的时候会向服务器发送请求,随后服务器返回信息给客户端,但是按钮是可以在短时间内重复点击的,这样的话就会导致重复的请求,因为服务器收到请求并响应是需要时间的,如果在短时间内收到了这么多的请求,就会增加服务器端的压力,而且收到了多少次请求,就会给客户端返回多少次数据,这样的话就会造成不必要的资源浪费,还有一种情况就是客户端被恶意脚本攻击后会在短时间内请求非常多次,这样严重危害到了服务端的安全,所以有必要在请求拦截器中对重复请求进行限制。首先初始化一个新的请求里面携带请求响应和请求时间参数,之后通过解构获取这两个参数,用来判断频繁请求和重复请求,如果请求后的时间减去当时请求的时间小于自己设定的时间,比如300毫秒,就会返回请求过于频繁的提示,且限制在一秒钟只能请求三次数据。通过观察请求响应参数的boolean值来判断请求响应是否成功返回,如果没有返回就提示请勿重复提交请求。
2,封装axios响应拦截器 响应拦截器也相当于一个中间商,后端可以将响应数据发送给响应拦截器,一般情况下,响应的数据里面都有三个参数,第一个是data响应成功后的数据体,第二个是响应失败后的message消息,第三个参数是status状态,使用响应拦截器就可以解构数据,判断数据里的status状态码,如果是请求成功的状态码的话,就向前端返回成功的数据,如果是失败的状态码的话就向前端返回失败的消息,前端直接请求数据接口获取数据就好了,不必重复判断status状态码。也可以利用这个机制判断用户的登录状态。
难点3,scss和less的作用: 在项目里,scss和less的作用除了样式嵌套之外,还有一些其他的作用,比如: 1,样式变量自定义: 就是设定样式赋值给一个变量,需要这个样式标签之前引入这个变量就可以了,在项目的体积越来越大的时候,要是突然需要修改许多地方字体颜色的话就是很麻烦,因为需要一个一个去找,但是设置了样式变量之后就完全不一样了,因为所有需要这个样式的标签都引用了这个变量,所以直接修改这个总样式文件的变量即可,非常的方便。 2,mixin混合 在css样式中使用mixin混合样式,可以在重复性样式里节省非常多的时间,首先用mixin设置样式名,在里面编辑样式,之后再通过include将样式赋给需要使用这个样式的标签,这样很简便,如果在这个标签里需要另外写别的样式,样式如果重复了,后面写的样式可以将mixin里写的样式给覆盖掉,其余样式不影响,这样就可以自由的去覆盖,去替换,去添加样式,非常的好用。
难点4,缓存预加载方案 因为有时候通过接口获取数据,有数据的获取速度比较慢,这个时候呢就是一直是loading的白屏状态并影响用户的体验,有一种方法可以先缓存旧页面的状态,获取到新页面状态之前先加载旧页面,等接口数据获取好了之后再加载新的页面,这就是缓存预加载方案。一般都是将缓存的数据放在localstorage中,因为localstorage的特性是数据永久保存,而一般来说不需要永久保存数据,所以需要设计缓存的有效时间,这里我设置了7天的有效时间,就是在setitem的时候放入存储时间,在getitem的时候让现在的时间减去当时缓存的时间是否小于7天,如果小于7天的话就证明缓存没有过期,那就正常返回缓存的数据,在获取新页面接口的时间段里就展示缓存的页面,这样能提高用户的体验。