工作中的遇到的一些小知识 6

React Hooks和React Hot Loader默认配置相冲突

设置RHL的pureSFC配置为true,详见讨论

1
setConfig({ pureSFC: true })

一个简单的rollup配置样例

最近有一个开发前端录音库(严格来说是改进)的需求,目标是发布到npm管理平台上,在打包库上rollup的发挥要优于webpack。刚好想用用试试,就用了rollup作为打包工具。因为场景比webpack更简单,配置上也比webpack好配很多,基本看看官方文档就可以上手了。

不过,文档里用的babel版本还是6.x,使用新版本babel后,配置文件rollup.config.js.babelrc有些改动,这里列在下面。

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
33
34
35
36
37
38
// rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import { terser } from "rollup-plugin-terser";

export default {
input: 'src/index.js',
output: {
file: 'index.js',
format: 'es'
},
plugins: [
resolve(),
commonjs(),
babel({
exclude: 'node_modules/**'
}),
terser()
]
};


// .babelrc
{
presets: [
[
'@babel/env',
{
loose: true,
modules: false
}
]
],
plugins: [
['@babel/proposal-object-rest-spread', { loose: true }]
]
}

mouseoutmouseleave事件的区别

mouseout: https://developer.mozilla.org/en-US/docs/Web/Events/mouseout
mouseleave: https://developer.mozilla.org/en-US/docs/Web/Events/mouseleave

  • mouseout在鼠标离开该元素表面时触发,包括进入到该元素的子元素中
  • mouseleave在鼠标离开该元素区域时触发,即离开该元素和所有子元素区域

sublime goto definition 快捷键

参考这里

只lint changed file的脚本方案

利用git diff-index。下面以tslint为例。

1
2
3
4
files=$(git diff-index --relative --name-only --cached HEAD | grep -e '\\.ts$' -e '\\.tsx$');
if test -n \"$files\";
then echo $files | xargs tslint --fix -t codeFrame;
fi

升级版

使用lint-staged,只lint staged的文件内容,代替上面冗长的脚本。

吸顶样式效果

CSS

参考:MDN

最简洁的实现方式,缺点是支持度较差,只在iOS平台支持度较好。除非做中后台,否则需要谨慎使用。

1
2
3
4
.stick {
position: sticky;
top: 20px;
}

JS

不用赘述,检查滚动元素的scrollTop属性做判断即可,在指定位置上,设置position:fixed配合z-index等实现吸顶。

另外有意思的一点是,在position:fixed的情况下,如果没有设置leftleft将相对当前元素相对定位

一个更友好的图片加载组件

需求

提供类似知乎App内的体验:

  • 在图片加载时有相同大小的占位图和文案提示
  • 图片加载失败后有相同大小的占位图和文案提示,点击文案可以重新加载图片

思路

重点在需要图片大小相同的占位图,这通常意味着:

  • 图片的大小需要伴随图片下发
  • 客户端的图片宽度或高度固定(通常是宽度)

点击重新加载可以通过在图片url后拼接每次不一样的参数实现,例如时间戳。

遮罩可以用图片背景色 + :after伪元素或另外的元素实现。剩下的把loading、loaded、failed状态处理好,工作并不困难。

下面是粗略实现的一个demo。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* @desc smart image provide more friendly image loading experience inspired by zhihu
* @author shenlvmeng<xin_yuanming@163.com>
*/
import React, { Component } from 'react';

import './index.less';

interface IProps {
width: number;
height: number;
src: string;
onLoad?: () => void;
onError?: () => void;
}

interface IState {
src: string;
loaded: boolean;
failed: boolean;
}

class SmartImage extends Component<IProps, IState> {
public readonly state: IState = {
src: this.props.src,
loaded: false,
failed: false
};

public render() {
const { width, height } = this.props;
const { src, loaded, failed } = this.state;

return (
<div className="smart-image-container">
<img
className="smart-image"
width={750}
height={750 * height / width}
src={src}
onLoad={this.handleSuccess}
onError={this.handleError}
/>
{!loaded
? (
<div className="smart-image-hint" onClick={this.handleRetry}>
{failed
? <span>图片加载失败,点此重试</span>
: <span>图片加载中...</span>
}
</div>
)
: null
}
</div>
);
}

private handleSuccess = () => {
this.setState({
failed: false,
loaded: true
});
if (this.props.onLoad) {
this.props.onLoad();
}
}

private handleError = () => {
this.setState({ failed: true });
if (this.props.onError) {
this.props.onError();
}
}

private handleRetry = () => {
if (!this.props.src.startsWith('http') || !this.state.failed) {
return;
}
this.setState({
failed: false,
src: `${this.props.src}?ts=${Date.now()}`
});
}
}

export default SmartImage;