0%

碰到了个问题,就是子元素设置了 position: absolute; 但是没有相对于上一级的父元素进行定位

我当时 我直接疑惑.jpg 这个表情

后来查了一下,原来是上一级的父元素要设置 position: relative; 属性

需求

元素 A 相对于元素 B 定位

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
#father {
position: relative;
}

#son1 {
position: absolute;
top: 0;
}

#son2 {
position: absolute;
bottom: 0;
}
1
2
3
4
<div id="father">
<div id="son1"></div>
<div id="son2"></div>
</div>

自嘲

3年了,3年了!你前端弄了3年了,这都不知道?

css 最基础的相对定位都不会,这前端怕是白学了

后记

等会,为啥父元素要加 position: relative; 才能生效?

被大佬Diss

你谈的是css样式表,是针对HTML元素生效的, 不是针对什么组件生效的

原来文章中用的是 “组件”

文章中的 “组件” 修改为 “元素”

感谢这位大佬。云香水识,然后这位大佬在招人,Flow+了解一下?

PS: 进这个大佬厂子一年,有大佬带,进去一年顶普通厂子三年,想去的可以给我留言。

我实在是太菜了,一个前端,连这个都不会,还需要查?

CSS :: child set to change color on parent hover, but changes also when hovered itself

需求

鼠标移到父 div 的时候,子 div 显示,鼠标移出父 div 的时候,子 div 隐藏。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.parent {
padding: 50px;
border: 1px solid black;
}

.parent span {
position: absolute;
top: 200px;
padding: 30px;
border: 10px solid green;
}

.parent:hover span {
border: 10px solid red;
}

.parent span:hover {
border: 10px solid green;
}
1
2
3
4
<a class="parent">
Parent text
<span>Child text</span>
</a>

自嘲

一个快 3 年的前端,连着都没玩过,还要查资料确认,乐色 乐色 真的乐色 too low

梵大的第一道题,怎么构建一个 express,入口函数实现。

这儿指的应该不是用 express,用 express 太简单了。。

应该是用 node 的 api 实现一个简单的 express。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const http = require('http');
const url = require('url');
const fs = require('fs');

http
.createServer(function (req, res) {

let { url: requestUrl } = req
let q = url.parse(requestUrl, true);

var filename = '.' + q.pathname;

fs.readFile(filename, function (err, data) {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html' });
return res.end('404');
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(data);
return res.end();
});
})
.listen(8080);

后记

开始我没加入

1
res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' });

这行代码,然后返回的中文是乱码的

然后我查了一下资料加上了这段话就好了。

等一下,还有,这是第一题的具体要求,我只写了简单的http模块,url处理

还有3、4我还没写

  1. http 模块
  2. url 处理
  3. 路由识别, 优先级
  4. 资源识别、响应头设置、压缩、流式输出、缓存

函数实现
next 怎么处理

在同事的项目中,我经常看到他们会用到 useCallback 我抽了点时间去了解它,但是越了解这个函数给我带来的困扰越大。

参见官方文档:useCallback

然而,,,可能理解能力太差了,我不是很理解。

官方说明

1
2
3
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);

返回一个 memoized 回调函数。

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。

网上查资料

思否上的文章,不错:你不知道的 useCallback

尽管作者已经解释的很详细了,但是我的困扰确实是越来越多了,后来我看到了另外一篇国外的文章,恍然大悟

Your Guide to React.useCallback()

这是一篇英文文章。

它再最开始,举出了这样的例子

1
2
3
4
5
6
7
8
9
10
11
12
function factory() {
return (a, b) => a + b;
}

const sum1 = factory();
const sum2 = factory();

sum1(1, 2); // => 3
sum2(1, 2); // => 3

sum1 === sum2; // => false
sum1 === sum1; // => true

这样理解起来就方便多了,组件在重绘的时候,会重新执行方法,也就是会重新构造一个函数。

1
2
3
4
5
6
7
8
9
import React, { useCallback } from 'react';

function MyComponent() {
const handleClick = useCallback(() => {
// handle the click event
}, []);

return <MyChild onClick={handleClick} />;
}

看一下上面的这段代码,当组件重绘的时候,不使用 useCallback 的时候就会重新生成一个 handleClick 方法,虽然方法是一模一样的,但是它确实是重新生成了。

如果函数方法非常复杂耗时很长的话就会产生性能问题,所以就有了useCallback,我在群里也有问过,德巨和另外一个扫地憎级(不好意思我忘记叫啥了)的大佬回答了我这一问题。

德巨说的是:当xxxx改变的时候 我这个函数才重新创建

非常通俗易解

后记

可能我的理解还有很多不到位的地方,上面我有提到有一篇文章给我带来了困扰是这段话

上面的例子中,如果不用useCallback, 任何一个输入框的变化都会导致另一个输入框重新渲染。

这段话没有问题,但是出现在了不适当的位置。。

他应该说的是:“任何一个输入框的变化,都会导致另一个输入框中的onChange事件重新创建”合适一些。

因为直接说重新渲染,我不知道这和useCallback有什么关系?

我的项目中,有个可编辑表单,多次复用了一个组件,但是父组件更新时,总是会更新子组件。然后页面就会有略卡的感觉,我意识到我应该优化一下项目了。

我查了一下 React 提供了 React.memo 方法可以让子组件在 prop 未发生变化的时候,不重新刷新 dom

参见 React.memo

React.memo

1
2
3
4
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});
React.memo 为高阶组件。

如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useStateuseReduceruseContextHook,当 context 发生变化时,它仍会重新渲染。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

1
2
3
4
5
6
7
8
9
10
11
function MyComponent(props) {
/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
/*
如果把 nextProps 传入 render 方法的返回结果与
将 prevProps 传入 render 方法的返回结果一致则返回 true,
否则返回 false
*/
}
export default React.memo(MyComponent, areEqual);

此方法仅作为性能优化的方式而存在。但请不要依赖它来“阻止”渲染,因为这会产生 bug。

需求

阻止事件冒泡

解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<Link
onClick={(event: {
preventDefault: () => void,
stopPropagation: () => void,
nativeEvent: { stopImmediatePropagation: () => void },
}) => {
event.preventDefault();
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
onSelect(item);
}}
>
{item.operationName}
</Link>

需求

匹配开头,但不包含开头的表达式

1
(?<=开头).+

匹配结尾,但不包含结尾的表达式

1
.+(?=结尾)

匹配结尾开头但不包含开头结尾的表达式

1
(?<=开头).+(?=结尾)

测试给了下面这些 url,要进行校验,你看看你的校验规则能通过吗?

1
2
3
4
www.baidu.com./hello
www.baidu.com123
http://www.baidu.com.cn.
www.baidu.com123./hello

流行的正则判断

开始我随便在网上找了个正则表达式进行判断

1
2
3
// 网址
const Url = /(https|http)?:\/\/([^\/\:]+)?(\:[0-9]+)?(\/[^\?]+)?(\?.+)?/;
Url.test('http://www.baidu.com./hello'); // true

emmmmm,这个正则可能?不太好使

使用浏览器自带的 URL 方法判断

1
2
3
4
5
6
7
8
9
10
11
12
13
const isUrl = (path) => {
if (!path.startsWith('http')) {
return false;
}
try {
const url = new URL(path);
return !!url;
} catch (error) {
return false;
}
};

isUrl('http://www.baidu.com./hello'); // true

我当时就是 ????

老老实实去正则

1
2
3
4
5
6
7
8
9
10
11
12
13
function validURL(str) {
const pattern = new RegExp(
'^(https?:\\/\\/)' + // 协议
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // 域名
'((\\d{1,3}\\.){3}\\d{1,3}))' + // IP
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // 端口
'(\\?[;&a-z\\d%_.~+=-]*)?' + // 请求参数
'(\\#[-a-z\\d_]*)?$',
'i'
);
return !!pattern.test(str);
}
validURL('http://www.baidu.com./hello'); // false

pomo巨佬提到过这个规则没有校验IPV6,我有时间就加上

后记

是不是我们的测试太严格了?一个负责的好测试,可以发现你代码中很多遗漏项和不足之处

让我想起来了一个网传,大概意思如下:

  • 低级开发
    测试:你看这有个 bug
    开发:什么,怎么可能有 BUG?你给我复现一下。

  • 中级开发
    测试:你看这有个 bug
    开发:嗯这个我知道我改过了,你重新构建一下就行。

  • 高级开发
    测试:你看这,这 bug 在哪找?
    开发:你想要啥 bug 我给你加上。

有一次后端返回了空对象给我,我的代码如下,然后导致逻辑通过。

1
2
3
if ({}) {
console.log(true);
}

判断是否空对象

后来我就加上了这个方法用于判断传进来的参数是不是空对象

1
2
3
4
5
6
function isEmptyObject(obj) {
if (!obj) {
return true;
}
return Object.keys(obj).length == 0;
}
1
2
3
if (!isEmptyObject({})) {
console.log(true);
}

后记

有时候还会有很多你意想不到的 bug,比如 if("0")

后端可能给你传过来一个字符串的 0,你会怎么做防范呢?

1
2
3
if ('0') {
console.log('后端想通过传0表示无数据');
}

由于一些原因,我不想引入 antd 的 less 文件,但是我引入一个外部 npm 组件的时候,这个组件调用了 antd 的 less 文件,会覆盖我司项目中的样式

解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
module.exports = {
module: {
rules: [
{
test: /\.less$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options: {
additionalData: async (content, loaderContext) => {
// More information about available properties https://webpack.js.org/api/loaders/
const { resourcePath, rootContext } = loaderContext;

const relativePath = path.relative(rootContext, resourcePath);

// 如果遇见antd的less文件,则返回空
if (/antd.*\.less$/.test(relativePath)) {
return '';
}

// 如果不是,则正常返回
return content;
},
},
},
],
},
],
},
};

解决过程及思路

阅读全文 »