css篇
-
一、CSS中容易被忽视的 position属性sticky
-
为什么要学习position:sticky
在开发移动端app时,经常会碰到需要这样一种情况 —— 网站滚动到一定高度的时候,让一部分内容作为navbar,也就是置顶显示,我们一般会使用js监听scroll事件来实现,但是新增的css属性position:sticky可以简单实现
- 用法
{
position: 'sticky',
top: 0
}
- 直接拿去玩~~~😂
例子:
兼容性:
-
二、css BFC
BFC 全称:Block Formatting Context, 名为 "块级格式化上下文"。
W3C官方解释为:BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。
简单来说就是,BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。那么怎么使用BFC呢,BFC可以看做是一个CSS元素属性
出发BFC的条件:
- overflow: hidden
- display: inline-block
- position: absolute
- position: fixed
- display: table-cell
- display: flex
BFC规则
BFC就是一个块级元素,块级元素会在垂直方向一个接一个的排列BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签- 垂直方向的距离由margin决定, 属于同一个
BFC的两个相邻的标签外边距会发生重叠 - 计算
BFC的高度时,浮动元素也参与计算
解决了什么问题
-
父级元素内的子元素进行float浮动后父元素高度塌陷,此时父级设置颜色会失效。给父级设置display:inline-block;
-
三、css 垂直水平居中
-
1、行内元素
{
text-align:'center'
}
- 2、块元素
flex布局
justify-content: center;
align-items: center;
.box {
width: 200px;
height: 200px;
border: 1px solid red;
display: flex;
justify-content: center;
align-items: center;
}
.children-box
{
width: 100px;
height: 100px;
background: yellow;
}
绝对定位(两种)
.box {
width: 200px;
height: 200px;
border: 1px solid red;
position: relative;
}
.children-box {
width: 100px;
height: 100px;
background: yellow;
position: absolute;
left: 50%;
top: 50%;
margin: 0 auto;
transform: translate(-50%, -50%); //定义2d旋转位置
}
.box {
width: 200px;
height: 200px;
border: 1px solid red;
position: relative;
}
.children-box {
width: 100px;
height: 100px;
background: yellow;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto ;
}
-
四、CSS盒模型
- 1、 W3C 标准盒模型:
属性width,height只包含内容content,不包含border和padding。
content-box(标准盒模型): width = 内容的宽度 height = 内容的高度
-
- IE 盒模型:
属性width,height包含border和padding,指的是content+padding+border。
border-box(IE盒模型):width = border + padding + 内容的宽度;height = border + padding + 内容的高度。
-
JS篇
-
表单校验金额
<Form.Item
label="支付金额"
name="paymentAmount"
rules={[{ required: true, message: '请输入支付金额!' },
{ pattern: new RegExp(/^\d{1,9}(\.\d{1,2})?$/), message: '支付金额最多9位整数,2位小数!' }]}>
<InputNumber placeholder='请输入支付金额' maxLength={40} min={0} style={{ width: 200, height: 36 }} step={0.01}/>
</Form.Item>
-
js事件循环机制 eventLoop
console.log('script start');
setTimeout(function() { console.log('setTimeout'); }, 0);
Promise.resolve().then(function()
{
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
- 正确答案是:script start, script end, promise1, promise2, setTimeout
原文地址: juejin.cn/post/684490…
-
Promise (手写promiseAll)
let p1 = new Promise((reslove, reject) => {
setTimeout(() => {return reslove('我是P1'); }, 0)
})
let p2 = new Promise((reslove, reject) => {
return reslove('我是P22222');
})
let p3 = new Promise((reslove, reject) => {
setTimeout(() => {return reject('我是P333错了');}, 300)
})
function promiseAll(promiseList) {
let result = []
let num = 0
return new Promise((resolve, reject) => {
for (let i = 0; i < promiseList.length; i++) {
promiseList[i].then(res => {
num++
result[i] = res
if (num === promiseList.length) {
resolve(result);
}
}).catch(res => {
reject(res);
})
}
})
}
promiseAll([p1, p2, p3]).then(res => {
console.log(res)
})
// 手写promiseRace
function promiseRace(promiseList) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promiseList.length; i++) {
promiseList[i].then(resolve, reject);
}
})
}
-
防抖
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。如可以对获取
input输入内容的函数上使用防抖功能。这里可以结合自己做的demo或者自己在使用在项目上的实例去说,效果会更好。
function debounce(func,time){
let timer return function(){
clearTimeout(timer)
let args = arguments timer = setTimeout(() => { func.apply(this,args) },time)
}
}
-
节流
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。如可以在对监听
scroll的函数上使用节流。
function throttle(fun,time){
let t1 = 0; // 初始时间
return function(){
let t2 = new Date(); // 当前时间
if(t2-t1>time){
fun.apply(this,arguments)
t1=t2
}
}
}
-
使用postMessage进行react和iframe的数据通信
1、首先在父组件(react文件)内引入iframe。
<iframe
style={{border:0,width:"100%",height:"100%",}}
src='/url.html'
id='iframeDom'
//onLoad={this.sendToken}
/>
2、然后在父组件(react文件)内的Button按钮上绑定点击事件
<Button type="primary" onClick={this.handleClick.bind(this)}>点我</Button>
3、继续在父组件(react文件)内编写handleClick方法,使用postMessage传递数据。
handleClick = () =>{ //必须是iframe加载完成后才可以向子域发送数据 const childFrameObj = document.getElementById('calculation'); childFrameObj.contentWindow.postMessage(1233, '*'); //window.postMessage };
4.在iframe页面编写回掉函数并监听message事件
//回调函数
function receiveMessageFromIndex ( event ) {
console.log( '我是iframe,我接受到了:', event.data );
}
//监听message事件
window.addEventListener("message", receiveMessageFromIndex, false);
===or===
constructor(){
super();
this.state = {
modelId : '' //1.初始化一个接收数据的变量
};
};
componentDidMount(){ //问题延申:React数据获取为什么一定要在componentDidMount里面调用?
let self = this; //为了避免作用域及缓存
window.receiveMessageFromIndex = function ( event ) {
if(event!=undefined){
console.log( '我是react,我接受到了来自iframe的模型ID:', event.data );
self.setState({
modelId:event.data //2.给变量赋值
})
}
}
//监听message事件
window.addEventListener("message", receiveMessageFromIndex, false);
};
-
forEach终止执行
// 可以使用 抛出错误 的方式来真正的终止forEach循环:
let arr = [1, 2, 3]
try {
arr.forEach(item => {
if (item === 2) {
throw Error(‘终止for循环’);
}
})
} catch(err) {
if (err.message === 'End Loop') throw err // 抛出真正的错误
}
console.log('不影响下边代码执行')
React篇
-
React 中为什么不能在if 循环里写hooks。
react用链表来严格保证hooks的顺序。hook 相关的所有信息收敛在一个 hook 对象里,而 hook 对象之间以单向链表的形式相互串联。
以useState为例,在它的实现过程之有mount和update两个阶段
-
mountState(首次渲染)阶段会按useState声明的顺序构建出一个链表并渲染; -
updateState阶段会按顺序去遍历之前构建好的链表,取出对应的数据信息进行渲染。hooks 的渲染是通过“依次遍历”来定位每个 hooks 内容的。如果前后两次读到的链表在顺序上出现差异,那么渲染的结果自然是不可控的。 -
必须按照顺序调用从根本上来说是因为 useState 这个钩子在设计层面并没有“状态命名”这个动作,也就是说你每生成一个新的状态,React 并不知道这个状态名字叫啥,所以需要通过顺序来索引到对应的状态值。
-
React 组件map中key的作用是什么?
key有利于提高程序运行和渲染效率
- react的虚拟dom使用diff算法比对更改前后发生的最小差异,再对真实dom进行更改 我们用key的真实目的是为了标识在前后两次渲染中元素的对应关系,防止发生不必要的更新操作。
- 那为什么不能用index代替key呢?
如果我们用index来标识key,数组在执行插入、排序等操作之后,原先的index并不再对应到原先的值,那么这个key就失去了本身的意义 -
React中组件和组件之间的有哪些通信方式
- 父组件给子组件传递信息通过
props,子组件像父组件报告可以使用函数 - 使用 React 中的两个内置hooks,
useContent和useReducer - 使用
Redux实现通信,而且还可以跨页面级别组件通信
-
react内监听Iframe加载完成
componentDidMount(){
window.addEventListener('load',this.uploadApi())
}
uploadApi = () =>{
let that = this;
let _iframe = document.getElementById('iframeWin');
_iframe.onload = function () {
console.log("iframe加载完成")
that.setState({framflag:false})
};
}
-
react-memo
- memo: 结合了
pureComponent纯组件和componentShouldUpdate功能,会对传入的props进行一次对比,然后根据第二个函数返回值来进一步判断哪些props需要更新。 - 要注意
memo是一个高阶组件,函数式组件和类组件都可以使用。memo接收两个参数: -
- 第一个参数:组件本身,也就是要优化的组件。
-
- 第二个参数:(pre, next) => boolean,pre:之前的数据。next:现在的数据,返回一个布尔值,若为true则不更新,为false更新。
性能优化例子
import React, { Component } from 'react';
import { Button } from 'antd-mobile';
const Child = () => {
return <div>
{console.log('子组件渲染了吗????')}
我是子组件
</div>
}
class Index extends Component{
constructor(props){
super(props)
this.state={
flag: true
}
}
const HOCChild = memo(Child, (pre, next) => {
return true
})
render(){
const { flag } = this.state
return <div style={{padding: 20}}>
// 更新父级子组件会执行更新
<Child/>
// <HOCChild/> 这样就不更新了
<Button
color="primary"
onClick={() => this.setState({ flag: !flag })}
>状态切换{JSON.stringify(flag)}</Button>
</div>
}
}
export default Index;
第二个参数作用
import React, { Component, memo } from 'react';
import { Button } from 'antd-mobile';
const Child = ({ number }) => {
return <div>
{console.log('子组件渲染')}
大家好,我是小杜杜~
<p>传递的数字:{number}</p>
</div>
}
const HOCChild = memo(Child, (pre, next) => {
if(pre.number === next.number) return true
if(next.number < 7) return false
return true
})
class Index extends Component{
constructor(props){
super(props)
this.state={
flag: true,
number: 1
}
}
render(){
const { flag, number } = this.state
return <div style={{padding: 20}}>
<HOCChild number={number} />
<Button
color="primary"
onClick={() => this.setState({ flag: !flag})}
>状态切换{JSON.stringify(flag)}</Button>
<Button
color="primary"
style={{marginLeft: 8}}
onClick={() => this.setState({ number: number + 1})}
>数字加一:{number}</Button>
</div>
}
}
export default Index;
当数字小于7,才会出发`Child`的更新,通过返回的布尔值来控制。根据条件按需更新。
-
React-memo的注意事项与总结
React.memo与PureComponent的区别:
- 服务对象不同:
PureComponent服务与类组件,React.memo既可以服务于类组件,也可以服务与函数式组件,useMemo服务于函数式组件(后续讲到) - 针对的对象不同:
PureComponent针对的是props和state,React.memo只能针对props来决定是否渲染
这里还有个小的注意点:memo的第二个参数的返回值与shouldComponentUpdate的返回值是相反的,经常会弄混,还要多多注意
-
memo:返回true组件不渲染 , 返回false组件重新渲染。 -
shouldComponentUpdate: 返回true组件渲染 , 返回false组件不渲染。 -
React-forwardRef
父组件想要获取孙组件上的信息,我们直接用
ref传递会怎样(父级可以拿到子集、孙子级数据)
- 接下来看看利用
forwardRef来转发下ref,就可以解决这个问题了:
import React, { Component, forwardRef } from 'react';
const Son = ({sonRef}) => {
return <div>
<p>孙组件</p>
<p ref={sonRef}>大家好,我是小杜杜~</p>
</div>
}
const Child = ({ childRef }) => {
return <div>
<div>子组件</div>
<Son sonRef={childRef} />
</div>
}
const ForwardChild = forwardRef((props, ref) => <Child childRef={ref} {...props} />)
class Index extends Component{
constructor(props){
super(props)
}
node = null
componentDidMount(){
console.log(this.node)
}
render(){
return <div style={{padding: 20}}>
<div>父组件</div>
<ForwardChild ref={(node) => this.node = node} />
</div>
}
}
export default Index;
-
如此以来就解决了不能在
react组件中传递ref的问题,至于复用的组件可能会用到, -
react hooks mobx 使用
版本
"mobx": "^5.15.4",
"mobx-react": "^6.1.8",
import React, { useEffect } from 'react';
import { inject, observer } from 'mobx-react';
const Index =(props)=>{
const { handelClon } = props;
useEffect(()=>{
console.log(11111,props)
},[])
return <div onClick={handelClon}>11111</div>
}
export default inject("departmentStore")(observer(Index));
-
React-Fragment 与
<></>的不同
在
React中,组件是不允许返回多个节点的,我们都知道<></>是<Fragment></Fragment>的简写,从原则上来说是一致的。实际上,Fragment这个组件可以赋值key,也就是索引,<></>不能赋值。
-
React生命周期
在17.0的版本,官方彻底废除
componentWillMount、componentWillReceiveProps、componentWillUpdate如果还想使用的话可以使用:UNSAFE_componentWillMount()、UNSAFE_componentWillReceiveProps()、UNSAFE_componentWillUpdate()
-
React v16.8中的hooks
- useState:定义变量,可以理解为他是类组件中的
this.state
useState有点类似于PureComponent,会进行一个比较浅的比较,如果是对象的时候直接传入并不会更新,这点一定要切记。
- useEffect:副作用,你可以理解为是类组件的生命周期,也是我们最常用的钩子
那么什么是副作用呢?副作用(Side Effect:是指 function 做了和本身运算返回值无关的事,如请求数据、修改全局变量,打印、数据获取、设置订阅以及手动更改
React组件中的DOM都属于副作用操作都算是副作用。当useEffect不设立第二个参数时,无论什么情况,都会执行
useEffect(()=>{
//数据请求 挂载
return()=>{
//组件卸载
}
},[])//数组内可放基本类型作为监听更新
-
useContext
useContent:上下文,类似于Context:其本意就是设置全局共享数据,使所有组件可跨层级实现共享
useContent的参数一般是由createContext的创建,通过 CountContext.Provider 包裹的组件,才能通过 useContext 获取对应的值
<CountContext.Provider value={count}>
<Child />
<Brother/>
</CountContext.Provider>
- useReducer: 它类似于
redux功能的api。
const [state, dispatch] = useReducer(reducer, initialArg, init);
复制代码
state:更新后的state值dispatch:可以理解为和useState的setState一样的效果reducer:可以理解为redux的reducerinitialArg:初始值init:惰性初始化
例子::
import React, { useReducer } from 'react';
import { Button } from 'antd-mobile';
const Index = () => {
const [count, dispatch] = useReducer((state, action)=> {
switch(action?.type){
case 'add':
return state + action?.payload;
case 'sub':
return state - action?.payload;
default:
return state;
}
}, 0);
return <div style={{padding: 20}}>
<div>count:{count}</div>
<Button
color='primary'
onClick={() => dispatch({type: 'add', payload: 1})}
>
加1
</Button>
<Button
color='primary'
style={{marginLeft: 8}}
onClick={() => dispatch({type: 'sub', payload: 1})}
>
减1
</Button>
</div>
}
export default Index
-
useMemo
useMemo:与memo的理念上差不多,都是判断是否满足当前的限定条件来决定是否执行callback函数,而useMemo的第二个参数是一个数组,通过这个数组来判定是否更新回掉函数
当一个父组件中调用了一个子组件的时候,父组件的 state 发生变化,会导致父组件更新,而子组件虽然没有发生改变,但也会进行更新。
简单的理解下,当一个页面内容非常复杂,模块非常多的时候,函数式组件会从头更新到尾,只要一处改变,所有的模块都会进行刷新,这种情况显然是没有必要的。
我们理想的状态是各个模块只进行自己的更新,不要相互去影响,那么此时用useMemo是最佳的解决方案。
这里要尤其注意一点,只要父组件的状态更新,无论有没有对自组件进行操作,子组件都会进行更新,useMemo就是为了防止这点而出现的