面试题
Vue:渐进式JavaScript框架(用到什么功能,只需要引入什么框架)
特点:易用,灵活,高效
1、请问一下,vue中为何model层数据改变了,view会自动更新最新的数据视图呀?(双向数据绑定的底层原理是什么?)
vue在创建vm的时候,会将数据配置到实例中,然后通过Object.defineProperty方法,为数据动态的添加getter与setter方法。
当获取数据的时候,会触发对应的getter方法,当设置数据的时候,触发对应的setter方法。
然后当setter方法触发完成的时候,内部会进一步触发watcher,从而数据改变了,视图则更新操作完毕。
2、computed和watch和方法区别?
1、watch的监听只是单个的监听,每次监听只能监听一个变量的修改,不能同时监听多个变量的同时更改。
而计算属性computed可以依赖多个数据的变化(并且只跟它所依赖项进行关联)
2、当需要在数据变化时执行异步或开销较大的操作时,只能选择采用watch去实现
3、与方法的区别就是方法里面的数据不会被缓存,并且每次渲染页面时都要重新执行该函数。computed的计算属性只有相关依赖发生变化才会进行更新
3、提供了v-on指令,实现dom点击事件
v-on:click v-on:keyup v-on:mouseover
v-on:click ===> @click
v-if 动态创建/删除
v-show 动态显示/隐藏
v-cloak指令:这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕
在Vue里可以使用mixins来做代码的抽离复用,便于维护
一个mixin其实就是一个纯粹的对象,上面挂载着抽离出来的配置,
/在某一个实例中,通过mixins选项导入后,此实例就拥有导入的mixin的配置
并且不会与原配置相互覆盖,而是合并到一起
4、事件修饰符?
.stop 阻止事件冒泡
.prevent 取消事件默认行为
.once 事件触发一次
.self 只能在自身上面触发
.capture
.passive
5、问题:问你请你说一下v-model底层原理?
绑定了value属性与监听了input事件,一旦数据改变了,input事件执行了。
6、问题: v-model的修饰符有哪些?
v-model.lazy 默认是同步更新,如果加了lazy修饰符,等光标离开之后才会更新视图
v-model.number 这个值无法被parseFloat解析的话,会原样返回,如果可以被解析,则返回解析后的结果
v-model.trim 去掉前后空格
7、v-if和v-show的区别?
v-if 是动态删除/添加 切换开销较大
v-show 是动态显示/隐藏 初始化渲染开销较大
如果是频繁切换,建议使用 v-show 反之,建议使用 v-if
8、为什么组件里面的data是一个函数?
内部必须是一个函数返回对象的形式,这样的话就能保证每一个组件里面用到的数据都是唯一的
一个组件的data必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
9、遇到过自定义指令吗?
答:在操作底层只是dom用过,例如输入框获取焦点
自定义指令的常用钩子函数:
bind inserted update componentUpdated unbind
页面加载时:bind inserted
更新组件时:update componentUpdated
卸载组件时:unbind
重新安装组件时:bind inserted
10、谷歌的文字如何能支持10PX大小?
用到一个css3里的属性:transform:scale()
11、spa的底层原理?
通过检测地址栏的变化来实现组件的安装与卸载
12、vue.use的原理
:调用install方法
13 SPA和MPA的区别:
SPA的优点:只有一个页面,内部是通过组件的卸载和装载实现页面的切换,用户体验好
MPA的优点:有利于搜索引擎的优化,有利于网站排名,爬取关键信息
14 hash模式背后原理:
其实就是调用了window.onhashchange方法 hash值的切换
15 history模式的原理:
本质使用H5的histroy.pushState方法来更改url
16 hash模式和history模式的区别
- hash模式较丑,history模式较优雅
- hash兼容IE8以上,history兼容IE10以上
- history模式需要后端配合将所有访问都指向index.html,否则用户刷新页面,会导致404错误
17 路由守卫有哪些及作用?
在某些情况下,当路由跳转前或跳转后、进入、离开某一个路由前、后,需要做某些操作,就可以使用路由钩子来监听路由的变化
会在任意路由跳转前执行,next一定要记着执行,不然路由不能跳转了
- 全局路由钩子:
router.beforeEach
router.afterEach - 单个路由钩子:
beforeEnter - 路由组件钩子:
beforeRouteEnter
beforeRouteLeave
beforeRouteUpdate—>需要配合动态的路径跳转
18 编程式导航在进行跳转时,需要调用什么方法?
this. $router.push()
19懒加载
懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时。
20、Vue中的全局方法
Vue.extend
Vue.nextTick
Vue.set
Vue.delete
Vue.directive
Vue.filter
Vue.component
Vue.use
Vue.mixin
Vue.compile
Vue.observable
Vue.version
21、axios的高级操作?
可以用来封装拦截器
1、请求之前的拦截:一般可以在发送请求的时候,携带一些数据给他们
2、响应之后的拦截:可以根据响应后的不同的状态码进行判断分析,给前端返回不同的符合条件的数据
一般在登录的功能的时候,通过vue-router提供的路由守卫拦截,当token失效时,需要用拦截器进行拦截
22、null和undefined的区别
1null是个对象,undefined就是undefined;2、undefined是定义了没赋值,null是空指针,给数组等引用数据类型赋空值,减少内存开销;后期事件解绑只需要给其赋null
23、ref关系链是用在父子关系中快速调用父子中内容的
24、vuex和storage的区别?
vuex是存在内存中,不是永久存储
一刷新,数据就不存在了
25、Vuex的项目结构:
1. 应用层级的状态应该集中到单个 store 对象中。
2. 提交 **mutation** 是更改状态的唯一方法,并且这个过程是同步的。
3. 异步逻辑都应该封装到 **action** 里面。
26、router-link和a的区别?
router-link组件避免了不必要的重渲染,它只更新变化的部分从而减少DOM性能消耗
反观<a>标签,每次跳转都得重渲染一次
27、keep-alive
是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。并且在切换组件的过程中只会经过created一次
28、代理服务器
所谓代理服务器就是位于发起请求的客户端与原始服务器端之间的一台跳板服务器,正向代理可以隐藏客户端,反向代理可以隐藏原始服务器。
正向代理:
用户知道目标服务器地址,但由于网络限制等原因,无法直接访问。这时候需要先连接代理服务器,然后再由代理服务器访问目标服务器。
反向代理:
反向代理对用户则是不可知的,比如我们访问百度网站,百度的代理服务器对外的域名为 https://www.baidu.com 。具体内部的服务器节点我们不知道,现实中我们通过访问百度的代理服务器后,代理服务器给我们转发请求到他们N多的服务器节点中的一个给我们进行搜索后将结果返回。
29、服务端渲染与客户端渲染区别?
客户端渲染不利于SEO搜索引擎优化
服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
服务端渲染对SEO友好,经过服务端渲染的页面,在网络传输的时候,传输的是一个真实的页面,所以爬虫就会对这个页面中的关键数据进行分析、收录。
服务端渲染缺点就是 对服务器压力比较大
客户端渲染减轻了服务器端的渲染压力,能够实现前后端分离开发
客户端渲染缺点就是 对SEO相当的不友好
30、异步请求放在Created中而不放在mounted中
有两个优点:
第一点:能更快获取到服务端数据,减少页面 loading 时间;
第二点:放在 created 中有助于一致性,因为ssr 不支持 beforeMount 、mounted 钩子函数。
31、Vue和React的区别是什么?
1、react严格上只能算是MVC的view层,vue则是MVVM模式。2、虚拟DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲 染整个组件树。3、数据绑不同,vue实现了数据的双向绑定,react数据流动是单向的。
32、vuex数据状态持久化
通过 vuex-persistedstate这个插件,来实现将数据存储到本地
33、key的作用
key的主要作用是为了高效的更新虚拟DOM,原理是vue在patch的过程中可以精准判断两个节点是否一致,从而避免了频繁更新不同元素,减少DOM操作量,提高性能。若不设置key,当一个元素添加的时候,后面的元素便会经历卸载与重新加载的过程。为了避免出错,尽量不要使用index作为key
34、Vue/React单向数据流的体现:数据只能从父级组件流向子级组件
35、前端开发如何优化?
1、减少HTTP请求达到性能优化
2、使用字体图标
3、适当合并脚本和样式表
4、CSS Sprites技术(网页中的背景图整合到一张图片中)
5、页面渲染优化
6、手机端优化
36、组件开发优点:
1.,标记鲜明,容易维护 组件化后,我们只需要对对应的组件进行维护,不会影响到其它文件。而且文件结构清楚,方便后台人员的使用。
2.,块状化结构,减少css 的书写,并且方便扩展 块状化结构,一个模块一个标识,标识加元素标签定位书写css,减少大量的class
需要注意的问题:
标签必须要闭合
2) 在外层只能有一个根元素
3) class ==> className
4) style ==> {{backgroundColor:‘red’}}
data写成函数返回对象格式
37、组件化和模块化的区别:
组件是具体的,模块是抽象的
38、自定义指令:
对普通DOM元素进行底层操作,
a、页面加载时:bind inserted
b、更新组件:update componentUpdated
c、卸载组件:unbind
d、重新安装组件:bind inserted
39、什么是回调函数?
回调函数就是函数以一个指针的形式以提供给其他函数调用,是同步操作,以便在获取某个数据之后,再进行其他操作
哪里用过呢?
计时器,请求数据的axios,ajax,fetch,resource,nextTick
40、nextTick
Vue.nextTick() or this.$nextTick()
下次DOM更新循环结束后执行的延迟回调,在修改数据之后,立即使用这个方法,可以获取更新后的DOM
同时可用此方法进行轮播图的实例化
41、request请求
axios.request是集成所有请求的一个集合体
42、在外部使用vuex状态的简写形式需要什么操作?
namespaced:true
43、观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
44、$use
Vue.use===this.$use
45、Vue全家桶
vue-cli + vue2.0 + vuex + vue-router + axios + element-ui
拦截器、路由守卫
46、Vuex和localstorage区别:
Vuex存储的数据在页面刷新时,自动销毁。localstorage永久存储数据,可以 通过 vuex-persistedstate这个插件,将vue-x的数据存储在localstorage内
47、什么是拦截器?
发生请求之前的一个拦截器:可以携带请求头给后端
服务器响应之后的拦截器:后台给前端返回很多的状态码,根据返回的状态码进行业务逻辑实现
48、Vuex流程
1、在vue的组件中,通过dispatch触发actions提交修改数据的操作
2、然后通过actions的commit来触发mutations来修改数据
3、mutation接受commit请求,就会通过Mutate来修改state里面的数据
4、最后由store触发每一个调用它的组件的更新
49、实现内容分发技术:slot
50、浏览器兼容
冒泡:e.stoppropagation||e.cancelBubble=true
阻止默认事件:e.preventDefault||window.event.returnValue=false
视口宽:document.documentElement.clientWidth||document.body.clientWidth
51、git操作
git init 初始化仓库
git add 添加文件到暂存区
git commit 提交暂存区到本地仓库
git push 上传代码
52、webpack和gulp
webpack:把项目当做一个整体,通过一个给定的主文件,Webpack将从这个文件开始找到你的项目的所有依赖文件,使用orders处理它们,最后打包为一个浏览器可识别的js文件
gulp:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务
53、jsonp跨域请求的原理:
动态创建script标签,然后利用script的src不受同源策略约束来跨域请求数据
常见问题
1、ES6新特性#######
1、let和const命令
2、变量的结构赋值:var [a,b,c] = [1,2,3]
3、字符串新增方法:trim()取消空格,includs查询是否找到了参数字符串
4、新增数组方法:find(回调函数)查找第一个符合条件的元素,findIndex()查找符合下标的元素,copyWithin(a,b,c)从位置a替换成b-c的元素,include()方法,查找是否包含元素的方法,forEach
5、新型字符串``
6、集合:set,map
2、export和export default区别:
1.export与export default均可用于导出常量、函数、文件、模块等
2.你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
3.在一个文件或模块中,export、import可以有多个,export default仅有一个
4.通过export方式导出,在导入时要加{ },export default则不需要
1.export
//a.js
export const str = "blablabla~";
export function log(sth) {
return sth;
}
对应的导入方式:
//b.js
import { str, log } from 'a'; //也可以分开写两次,导入的时候带花括号
2.export default
//a.js
const str = "blablabla~";
export default str;
对应的导入方式:
//b.js
import str from 'a'; //导入的时候没有花括号
使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名
//a.js
let sex = "boy";
export default sex(sex不能加大括号)
//原本直接export sex外部是无法识别的,加上default就可以了.但是一个文件内最多只能有一个export default。
其实此处相当于为sex变量值"boy"起了一个系统默认的变量名default,自然default只能有一个值,所以一个文件内不能有多个export default。
// b.js
本质上,a.js文件的export default输出一个叫做default的变量,然后系统允许你为它取任意名字。所以可以为import的模块起任何变量名,且不需要用大括号包含
import any from "./a.js"
import any12 from "./a.js"
console.log(any,any12) // boy,boy
导入导出方式
//第一种导出方式
// export const a = 10;
// export const b =20;
导入方式
import {a,b} from"./a"
//第二种导出方式
// const a = 10;
// const b = 20
// export{
// a,b
// }
导入方式
import {a,b} from"./a"
或者
import * as A from "./a"
第三种导出方式
export default{
a:1,
b:2
}
导入方式:
import A(写什么都行) from "./a"
或者
import B(写什么都行) from "./a"
这两种方式输出结果一样
注意://import是静态导入,不能用表达式和变量,require是动态导入
//例如:if(xxx){require()}是可行的,但import必须放在开头
3、闭包的优缺点
什么是闭包?1函数嵌套函数2内部函数可以调用外部函数的形参和变量3 内部函数的变量不会被内存回收机制回收
优点:1避免全局污染2、声明私有成员3希望有一个变量常驻在内存当中
缺点:闭包使得函数中的变量都被保存在内存当中,内存消耗很大,可能会造成内存泄漏,还有定时器未关
4、同源策略有哪些和处理方法
域名,端口号,协议。处理方法:
1、代理。2、通过后端CORS解决跨域问题:Access-Control-Allow-Origin。3、jsonP
5、filter和map 的区别:
filter是对原数组的元素进行筛选,将合格元素组成一个新数组进行返回;map是对每一个元素进行修改,返回修改后的数据组成一个新数组。换言之:filter之后的数组元素一定是之前元素中的一部分,map可能是修改后的数据
6、es6中的symbol?
每次生成唯一的值,也就是每次都不相等,
作用:让代码的可读性更强。
7、forin,foreach,forof
foreach遍历数组;forin遍历数组和对象;forof遍历set,map,String,arguments,Nodelist
8、内存泄漏:
闭包,定时器未关
9、bind,apply,call区别
bind不会被立即调用,而是返回一个新的函数,称为绑定函数,其内的this指向就是bind的第一个参数,第二个及以后的参数作为绑定函数的参数来调用
apply和call都是为了改变某个函数运行时的上下文而存在的,如果你要传递的参数不多,则可以使用fn.call(thisObj, arg1, arg2 ...)
如果你要传递的参数很多,则可以用数组将参数整理好调用fn.apply(thisObj, [arg1, arg2 ...])
10、border1px问题:
transform:scale(0.5)
11、上下左右居中:
1设置父元素为table-cell,添加virtical-align:center;
2设置子元素为inline-block,给父元素添加line-height=height,text-align:center;
3父元素添加position:relative;子元素添加:position:absolute;top:0;bottom:0;left:0;right:0;margin:auto;
4父元素添加position:relative;子元素添加:left:50%;margin-left:w/2;top:50%,margin-top:h/2;
5给父元素添加flex,添加item-alitn:center
12、原型链的特点
由多级父对象逐级继承,形成的链式结构,通过__ proto __实现子类共用原型链上的属性和方法,向上查找
13、数组去重方法
1、利用set去重
var arr = […new Set(arr)]
2、利用forfor循环,然后splice去重
3、利用indexOf去重
4、利用sort排序,将每相邻两位进行对比,然后生成新数组
14、函数防抖
在一段连续操作结束后,处理回调,利用clearTimeout和setTimeout实现。只关注一定时间连续触发的事件只在最后一次执行
例如:搜索框搜索输入,手机号、邮箱输入验证,窗口大小resize
//非立即执行
function debounce(func,delay){
let timer;
return function(){
let args = arguments;
timer&&clearTimeout(timer);
timer = setTimeout(()=>{
func.apply(this,args)
},wait)
}
}
//立即执行
function debounce(func,delay){
let timer;
return function(){
let context = this
let args = arguments;
timer&&clearTimeout(timer)
let callNow = !timer;
timer = setTimeout(()=>{
timer = null
},delay)
callNow&&func.apply(context,args)
}
}
15、节流
在一段连续操作中,每段时间只执行一次,频率较高的事件中使用来提高性能
滚动加载,高频点击
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
16、滚动加载
通俗的讲就是:当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。
17、渐进增强 progressive enhancement:
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
18、 优雅降级 graceful degradation:
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
19、深拷贝方法:
1、for…in循环配合递归封装函数实现深拷贝
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if (target === null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if (target.constructor === RegExp) {
result = target;
} else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}
2、JSON的parse和stringfy方法实现
let newObj = JSON.parse(JSON.stringify(obj))
3、JQ的extend方法实现
$.extend([deep],target,…object)
deep 表示深拷贝,Boolean
target 目标对象
…object 需要进行合并的对象
Object.assign只是浅拷贝,可以用来对象合并
20、兼容处理
21、一个元素绑定多个事件,通过addEventlistener
window.onloage = function(){
document.getElementById("btn").addEventListener('click',function(){alert(1)},false);
document.getElementById("btn").addEventListener('click',function(){alert(1)},false);
}
第一个参数是事件名称,没有on,第二个参数是回调函数,其实是浏览器调用的,第三个是是否捕获阶段触发
addEventlistener不支持IE8一下,可以用attachEvent方法来替代
21、数组的扁平化:指将一个多维数组变为一维数组
function flatten(arr) {
return arr.reduce((result, item)=> {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
22、函数的柯里化
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
函数封装:
function curry(fn){
let len = fn.length;
return function temp(){
let args = [...arguments];
if (args.length>=len){
return fn(...args);
}else{
return function(){
return temp(...args,...arguments)
}
}
}
}
X、遇到的问题
轮播图出现划不动情况,因为在created里面实例化
React
1、react中的核心算法react Fiber作用
React.Fiber的方法很简单—分片。将用时很长的任务分成很多小片,每一个小片的用时耗时很短,虽然总任务的时间依然很长,但是在每一个小片执行完成之后,都会给其他小片执行的机会,这样唯一的线程就不会拥堵,其他任务依然有运行的机会
2、jsx内部编译原理
1、编写jsx代码
2、jsx代码内部通过babel提供的核心方法react.createElement()
3、将jsx代码转成虚拟dom
4、ReactDOM.render()将虚拟dom转成真实dom
JSX代码 — > 使用react构造组件,bable进行编译(React.createElement方法)—> JavaScript对象(虚拟dom) — ReactDOM.render()函数进行渲染
—>真实DOM元素 —>插入页面
3、react中如何遍历数组,通过map迭代
key很关键!!!
key帮助React识别哪些元素改变了,比如被添加或者删除,因此应当给数组中的每一个元素赋予一个确定的标识
虚拟dom对比的时候,加key可以避免出错。如果不加key,当一个元素添加的时候,后面的元素就会经历卸载与重新加载的过程
为了避免出错,所以我们在开发过程中应该尽量避免用index作为key值,除非我知道index是不变的
4、React高性能的原理:
在改变数据变化时,React都会重构整个虚拟dom树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行真实DOM的更新。
尽管每一次都需要构造完整的虚拟DOM树,但因为虚拟DOM是存在于内存数据,性能是极高的,而对实际DOM的操作仅仅是Diff部分,因而能够达到提高性能的目的
5、react中数据改变,视图层不会发生变化,应该用什么函数?
setState,通过该函数,就可以实现数据改变,视图层也发生变化,但也存在小BUG,同时运行多个setState时,不会逐个运行,就像Object.assign的浅拷贝一样,后面调用的setState会覆盖同一周期的setState
6、如果后续状态取决于当前状态,我们建议使用updater函数的形式代替
this.setState((prevState)=>{
return{
count:prevState.count+1
}
})
7、setState两种写法的区别
(1)在类组件中,通过this.setState({count:this.state.count+1})
内部经过Object.assign()在一个短时间内进行合并,例如添加商品,看似多次,实际只添加一次
(2)在方法组件中,通过使用useState这个hooks去定义状态
const [count,setCount]=React.useState(1)
setCount(count+1)
相当于类组件中的写法:
constructor{
super()
this.state={
count:1
}
}
setCount=()=>{
this.setState({
count:this.state.count+1
})
}
8、受控组件和非受控组件
受控组件:受到数据的控制,使得React成为唯一的数据源
class App extends React.Component{
constructor(){
super()
this.state={
value:'123'
}
}
submit=(e)=>{
e.preventDefault()
console.log(this.state.value)
}
handleChange = (e)=>{
this.setState({
value:e.target.value
})
}
render(){
return (
<div>
<form onSubmit={this.submit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<p>{this.state.value}</p>
<input type="submit" />
</form>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById("app"))
非受控组件:只需要在DOM元素上通过ref进行绑定取值即可
class App extends React.Component{
submit = (e)=>{
e.preventDefault()
console.log(this.textInput.value)
}
render(){
return(
<div>
<form onSubmit={this.submit}>
<input type="text" name="123" ref={el=>this.textInput=el}/>
<input type="submit"/>
</form>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById("app"))
9、jsx的特性
1、 1)标签必须要闭合
2) 在外层只能有一个根元素
3) class ==> className
4) style ==> {{backgroundColor:‘red’}}
5) onClick
onClick={()=>{alert(1)}}
注意: this的指向 建议采用箭头函数(因为箭头函数内部的this与定义这个函数的外部this是同一个)
6)input的value值
<input value={this.state.value} onChange={(e)=>{this.setState({value:e.target.value})}} />
如果只是简单的显示值,就用defaultvalue,
7)checkbox checked必须配合onChange事件,写成受控组件的形式,否则就采用defaultchecked
8)label的属性 for==>htmlFor
9)jsx的注释:{/* jsx代码*/}
10)jsx的原理:将编写的jsx代码通过babel的React.CreatElement方法编译成虚拟dom,进而通过ReactDOM.render方法将虚拟dom渲染成真实dom
10、父子组件通信
父组件通过属性的方式将将自己的状态传递给子组件,子组件通过props接受父组件的状态
11、子父组件通信
父组件可以将一个更改自身状态的方法传递给子组件,然后子组件通过props接收后进行调用,相当于父组件的方法被执行了,从而改变自身的状态
12、兄弟组件通信
这个思想搬到代码里就是 EventHub。其主要的功能是就发布事件(on 监听)和订阅事件(trigger 触发)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eSArU8Gs-1602296290231)(C:\Users\liuli\AppData\Roaming\Typora\typora-user-images\image-20200902220155528.png)]
13、 mock数据工具 - json-server (可以将本地的一个json文件启动起来,做成一个接口服务)
https://gitee.com/rh_hg/json-server?_from=gitee_search
npm i json-server -g
json-server --version
json-server .\data.json --port 4000 -w
14、很多事件方法内,通过bind绑定数据来传值
15、react中代理的配置
如果后端没有帮助我们配置跨域处理,需要我们前端手动的进行代理配置
node_modules>react-scripts>config>devServer.js
proxy:{
"/api":{
target:"http://47.96.0.211:9000",
changeOrigin:true,
pathRewrite:{
"^/api":""
}
}
}
但是有问题? 后续安装新的模块的时候,内部yarn.lock文件实时的检测node_modules下面的文件是否手动的
更改过,如果更改的话,重新变成初始状态。
解决方案一:
可以通过 yarn eject 进行react-scripts相关配置文件的抽离操作。
报错?
.git删掉
git init
git add *
git commit -m "first commit"
git push
再去进行 yarn eject Y
解决方案二:
yarn add http-proxy-middleware
src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app){
app.use("/api",
createProxyMiddleware({ target: 'http://47.96.0.211:9000', changeOrigin: true , pathRewrite:{ "^/api":"" } })
)
}
16、React挂载阶段的钩子函数:
1、constructor
只在初始化的时候执行一次
作用:
**1、可以用来初始化组件状态。2可以给一些事件函数绑定this **
2、getDerivedStateFromProps
在这个钩子函数里面,钩子函数属于类,前面需要加static修饰,所以不能访问this
这个方法返回会什么,状态里的属性就会变成什么
如果你的组件的某个状态就想由外部传入的属性进行关联控制,希望属性变化了,组件内部的状态也发生变化,那么就把这个状态变成派生状态,使用此钩子函数即可,这样,组件内部不能改变该属性。
3、render
render什么时候被执行?
1初始化的时候被执行。2当组件内部调用setState时。3当外部调用props改变时。4forceUpdate(强制更新)时
4、componentDidMount
只在初始化的过程中执行一次
17、React挂载阶段废弃掉的钩子函数
17.x版本中不推荐使用的钩子函数
1、componentWillMount
内部为什么不进行异步请求?
这个钩子函数受到React16.x Fiber协调算法影响,导致这个钩子函数可能会执行多次,如果异步请求放在这里,执行多次显然是不科学的
2、componentWillReceiveProps
3、componentWillUpdate
18.React更新阶段的钩子函数
1、getDerivedStateFromProps
在这个钩子函数里面,钩子函数属于类,前面需要加static修饰,所以不能访问this
这个方法返回会什么,状态里的属性就会变成什么
如果你的组件的某个状态就想由外部传入的属性进行关联控制,希望属性变化了,组件内部的状态也发生变化,那么就把这个状态变成派生状态,使用此钩子函数即可,这样,组件内部不能改变该属性。
2、shouldComponentUpdate(相当于一个过滤网,只将发生改变的数据进行render更新)
询问是否进行更新操作,false,不进行render重新渲染操作,通过减少render的执行次数来提升react的性能
在类组件中:
Component+shouldComponentUpdate===PureComponent
可以用PureComponeng来实现,不过纯组件用的是浅拷贝,会判断地址是否一样:
基本类型:根据外部传入的数据,新的数据与旧的数据是否一致?如果一致,render就不会执行
引用类型:根据外部传入的数据,新的数据与旧的数据地址是否一致,render也不会执行
再去进行更新操作
在方法组件中
可以用***React.memo(functional Component)***
3、render
4、getSnapshotBeforeUpdate
必须配合componentDidUpdate一起使用,并且可以返回一个更新之前的值;一般用于聊天室的滚动
5、componentDidUpdate
轮播图的实例化在此函数当中,
轮播图的实例化不能在componentDidMount的原因:
在该钩子函数当中请求数据后,在进行虚拟DOM的对比,对比成功后才会有真实DOM元素。如果将实例化放在componentDidMount中,name虚拟DOM对比的时候就会进行实例化,这样是不对的
19、卸载阶段的钩子函数
1、componentWillUnmount
在删除组件前进行善后处理