zhaofeihao / znotes Goto Github PK
View Code? Open in Web Editor NEW自习室
License: MIT License
自习室
License: MIT License
事件处理程序(Event handlers)就是每当有事件被触发时决定要执行的动作或行为。
在 React 应用中,事件名使用小驼峰格式书写,意思就是 onclick
要写成 onClick
。
React 实现的合成事件机制给 React 应用和接口带来了一致性,同时具备高性能的优点。它通过将事件标准化来达到一致性,从而达到在不同浏览器和平台上都具有相同的属性。
合成事件是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation()
和 preventDefault()
。
合成事件的高性能是通过自动使用事件代理实现的。事实上,React 并不将事件处理程序绑定到节点自身,而是将一个事件监听器绑定到 document 的根元素上。每当有事件被触发,React 就将事件监听器映射到恰当的组件元素上。
在 React 中监听事件简单如下:
class ShowAlert extends React.Component {
showAlert() {
alert("Im an alert");
}
render() {
return <button onClick={this.showAlert}>show alert</button>;
}
}
在上面的例子中,onClick
属性是我们的事件处理程序,它被添加到目标元素上以便在元素被点击时执行要被执行的函数。onClick
属性设置了 showAlert
函数。
简单点儿说,就是无论何时点击该按钮,showAlert
函数都会被调用并显示一条信息。
在 JavaScript 中,类方法并不是默认绑定的。因此,将函数绑定到类的实例上十分重要。
render()
中绑定这种方式是在 render
函数中调用 bind
方法来进行绑定的:
class ChangeInput extends Component {
constructor(props) {
super(props);
this.state = {
name: ""
};
}
changeText(event) {
this.setState({
name: event.target.value
});
}
render() {
return (
<div>
<label htmlFor="name">Enter Text here </label>
<input type="text"
id="name"
onChange={this.changeText.bind(this)}
/>
<h3>{this.state.name}</h3>
</div>
);
}
}
在上面的例子中,我们使用 onChange
事件处理程序在 input 输入框上监听键盘事件,该操作是通过在 render 函数中绑定完成的。该方法需要在 render 函数中调用.bind(this)
。
为啥呢?
任何 ES6 类中的方法都是普通的 JavaScript 函数,因此其都从 Function 的原型上继承 bind()
方法。现在,当我们在 JSX 内部调用 onChange
时,this
会指向我们的组件实例。
使用这种方法可能会造成一些潜在的性能问题,因为函数在每次 render 后都被重新分配一次。这种性能代价可能在小型 React 应用上并不明显,但在较大应用上就要值得注意了。
constructor()
中绑定如果说在 render 中绑定的方法不适合你,你也可以在 constructor()
中进行绑定。例子如下:
class ChangeInput extends Component {
constructor(props) {
super(props);
this.state = {
name: ""
};
this.changeText = this.changeText.bind(this);
}
changeText(event) {
this.setState({
name: event.target.value
});
}
render() {
return (
<div>
<label htmlFor="name">Enter Text here </label>
<input type="text" id="name" onChange={this.changeText} />
<h3>{this.state.name}</h3>
</div>
);
}
}
如你所见,changeText
函数绑定在 constructor
上:
this.changeText = this.changeText.bind(this)
等号左边的 this.changeText
指向 changeText
方法,由于该步操作是在 constructor
中完成的,所以 this
指向 ChangeInput
组件。
等号右边的 this.changeText
指向相同的 changeText
方法,但是我们现在在其上调用了 .bind()
方法。
括号中的 this
作为我们传入 .bind()
中的参数指向的是上下文(context),也就是指向 ChangeInput
组件。
同样值得注意的是如果 changeText
不绑定到组件实例上的话,它就不能访问 this.setState
,因为这时的 this
会是 undefined
。
绑定事件处理函数的另一种方式是通过箭头函数。通过这种 ES7 的类特性(实验性的public class fields 语法),我们可以在方法定义时就进行事件绑定,例子如下:
class ChangeInput extends Component {
handleEvent = event => {
alert("I was clicked");
};
render() {
return (
<div>
<button onClick={this.handleEvent}>Click on me</button>
</div>
);
}
}
箭头函数表达式语法比传统的函数表达式简短且没有自己的 this
、arguments
、super
和 new.target
。
在上面的例子中,一旦组件被创建,this.handleEvent
就不会再有变化了。这种方法非常简单且容易阅读。
同在 render
函数中绑定的方法一样,这种方法也有其性能代价。
render
中绑定绑定的时候定义一个匿名函数(箭头函数),将匿名函数与元素绑定,而不是直接绑定事件处理函数,这样 this
在匿名函数中就不是 undefined
了:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
这种方法有一个问题,每次 LoggingButton
渲染的时候都会创建一个新的 callback
匿名函数。在这个例子中没有问题,但是如果将这个 onClick
的值作为 props
传给子组件的时候,将会导致子组件重新 render
,所以不推荐。
每当谈到 React 中的事件,只有 DOM 元素可以有事件处理程序。举个栗子,比如说现在有个组件叫 CustomButton
,其有一个 onClick
事件,但是当你点击时不会有任何反应,原因就是前面所说的。
那么我们要如何处理定制组件中的事件绑定呢?
答案就是通过在 CustomButton
组件中渲染一个 DOM 元素然后把 onClick
作为 prop 传进去,CustomButton
组件实际上只是为点击事件充当了传递介质。
class CustomButton extends Component {
render() {
const { onPress, children } = this.props;
return (
<button type="button" onClick={onPress}>
{children}
</button>
);
}
}
class ChangeInput extends Component {
handleEvent = () => {
alert("I was clicked");
};
render() {
return (
<div>
<CustomButton onPress={this.handleEvent}>Click on me</CustomButton>
</div>
);
}
}
本例中,CustomButton
组件接收了一个叫 onPress
的prop,然后又给 button
传入了一个 onClick
。
给事件处理程序传递额外参数是很常见的,比如 id
是行 ID,下面两种传参方式都可以:
<button onClick={(e)=>this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上面两种传参方式是等价的。
在两种传参方式中,参数 e
都代表 React 事件将要作为参数 id
后面的第二个参数来传递。区别在于使用箭头函数时,参数 e
要显示传递,但是使用 bind
的话,事件对象以及更多的参数将会被隐式的进行传递。
最近在做的项目后端一次性返回全部指标下的全部数据,然后前端进行筛选展示,各种情况十分繁琐,进行一下总结。
以下面的数据结构为例,分情况讨论一下筛选方法。
例子中 confidenceLevel 共有 85、90、95三种情况,又分别对应B、C、D三种不同的 expVersion。
"expData": [{
"conclusion": "样本满足",
"confidenceLevel": "85%",
"minSize": 231424,
"dimValue": "zong",
"expVersion": "B",
"sampleSize": 999823,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "90%",
"minSize": 273805,
"dimValue": "zong",
"expVersion": "B",
"sampleSize": 999823,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "95%",
"minSize": 349023,
"dimValue": "zong",
"expVersion": "B",
"sampleSize": 999823,
"dim": "zong_filter_error"
},{
"conclusion": "样本满足",
"confidenceLevel": "85%",
"minSize": 230838,
"dimValue": "zong",
"expVersion": "C",
"sampleSize": 1001696,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "90%",
"minSize": 273112,
"dimValue": "zong",
"expVersion": "C",
"sampleSize": 1001696,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "95%",
"minSize": 348140,
"dimValue": "zong",
"expVersion": "C",
"sampleSize": 1001696,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "85%",
"minSize": 230868,
"dimValue": "zong",
"expVersion": "D",
"sampleSize": 1000789,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "90%",
"minSize": 273148,
"dimValue": "zong",
"expVersion": "D",
"sampleSize": 1000789,
"dim": "zong_filter_error"
}, {
"conclusion": "样本满足",
"confidenceLevel": "95%",
"minSize": 348185,
"dimValue": "zong",
"expVersion": "D",
"sampleSize": 1000789,
"dim": "zong_filter_error"
}]
这种情况比较简单,一个find即可搞定。
随便举个例子,比如我想找 minSize === 273148
的那条数据
expData.find(item=> item.minSize===273148 );
// 返回值省略不表,只有一条数据符合要求
// [{...}]
// 当然把上面的find方法改成filter也可以实现单条件多数据筛选,但是不够洋气
// 下面的方法,稍微开始花里胡哨起来了
function filterByNames(target, names) {
let result = [];
names.map((item,index)=>{
result.push(target.filter(item=>item.confidenceLevel==names[index]))
})
return result;
}
// 测试
filterByNames(expData,['85%','90%'])
//成功返回我要的数据,这里的单条件是指只筛选 confidenceLevel 这一条件
// 平平无奇,波澜不惊
function filterByNames(target, confidenceLevel, expVersion) {
return target.filter(item => item.confidenceLevel == confidenceLevel && item.expVersion == expVersion)
}
// 测试
filterByNames2(expData,'95%','D')
注意!真正洋气的来了!
function multiFilter(target, filters) {
const filterKeys = Object.keys(filters);
return target.filter((item) => {
return filterKeys.every(key => {
if(!filters[key].length) {
return true;
}
return filters[key].indexOf(item[key]) > -1;
})
})
}
// 测试
var filters = {
confidenceLevel:['95%'],
expVersion:['B','C']
}
multiFilter(expData, filters); // done
let pattern = /^\d*\.{0,2}\d{0,2}$/ ;
pattern.test(1.2); // true
pattern.test('a.b'); //false
需要在服务器上安装环境?编辑配置文件?查看运行日志?命令到用时方恨少。
逼格是程序员的安身立命之本。同时不断扩展自己的边界,向外延伸。做最好的准备,成就更好的你(我可以做程序员鼓励师了)。让我从一点儿 Linux 基础命令开始吧。
ls = list // 显示一个目录或当前目录下的文件或文件夹
ls 文件夹名 // 显示指定文件夹下的目录
ls -a // 查看隐藏文件
ls -l // 查看文件详细信息,文件权限-文件所属人-文件所属组-文件大小(字节数)-文件最后修改时间
ls -lh // 同上,查看文件详细信息,但是文件大小是以容易阅读的方式显示的
cat 文件名 // 把文件输出到控制台(不适用大文件)
head -n 文件名 // n 为任意数字,表示可以查看前 n 行
tail -n 文件名 // n 为任意数字,表示可以查看后 n 行
tail -f 文件名 // 查看正在实时写入的文件
more 文件名 // 不止想看文件的开始结束,想看文件的更多内容,缺点是只能往前翻,不能往回翻
less 文件名 // 首先显示文件第一屏,shift + G 跳转到文件末尾,g 跳回文件首屏,输入 行号+g 跳到指定行,/+关键字(按n显示下一个匹配,shift+n显示上一个匹配),ctrl+u 向上翻页,ctrl+d 向下翻页
grep 关键字 文件名 // 查看文件中的指定关键字内容,可使用简单正则表达式匹配关键字
grep —color 关键字 文件名 //对匹配到的关键字加颜色,更显眼
egrep // 可以使用更强大的正则表达式
sort 文件名 //对文件内容进行字典序升序排列
sort 文件名 -r // 对文件内容进行倒序排列
sort 文件名 -k // 指定对某列进行排序
sort 文件名 -n // 按数字排序
uniq // unique,去重命令,如果有相同行就只输出一次
uniq -c // 除了输出这行外,还输出这行出现的次数,限制条件:相同行必须是挨着的,分开的话计数不准
sort 文件名 | uniq -c // 小技巧,先排序,再去重,就可以解决上面的问题
sort 文件名 | uniq -c | sort k1,1nr | head // 查看出现次数最多的前 10 行
wc 文件名// word count 统计文件中的行数,单词数,字节数
wc -l 文件名 // 只查看行数
wc -c 文件名 // 只查看字节数
vim 文件名 // G 跳到文件结尾,gg跳到文件开头,/+关键字查找指定关键字(n向下查找,N向上查找),
d // 移动光标可以删除一个字符
dw // 删除一个单词,其实这里面提到的删除是指剪切,存到buffer里去了
dd // 删除一行,u可以撤销刚才的操作
p // 粘贴,buffer 里的内容
i // 开启插入/编辑模式
a // 在当前字符的后面进行插入
A // 在当前行末尾插入
esc // 从编辑模式回到命令模式
: // 进入底行命令模式
:q // 退出当前文件
:w // 保存当前文件,加叹号 ! 强制保存
:wq // 保存并退出,缩写是 x
tar -zcvf tarTest.tgz tarTest/ // 将 tarTest 文件夹压缩为.tgz 格式的文件,tgz 代表使用 gzip 压缩的 tar 包,参数 -z 表示gzip压缩,c表示压缩,v 表示压缩的信息,f 表示如果文件存在的话覆盖它
tar -tvf tarTest.tgz // 显示压缩文件中的内容,不解包
tar -xzf tarTest.tgz // 解压包
// tar的优点就是能保存很多信息
文件常见的一种方式是用下面这个方法来下载一个文件。采用的方式就是拼URL然后去新开一个页面来下载文件。
window.open('someUrl' , '_blank');
该方法很方便,又不是很方便,问题有二:
所以尝试一下在此处能否进行改进:
在触发文件下载的事件中,使用axios请求这个接口。将接口响应的res.data(blob文件),传给 download 函数进行处理
axios.post(url, params).then( (res) => {
if (res.status === 200) {
this.download(res.data, 'fileName');
} else {
alert('接口出现了点儿问题', 'error');
}
}).catch(err => {
console.log(err);
})
最后,创建a标签,设置download属性,插入到文档中并click
function download (data, fileName) {
if (!data) {
return;
}
let url = window.URL.createObjectURL(new Blob([data]));
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', `${fileName}.xls`);
document.body.appendChild(link);
link.click();
},
以前写领券模块时总是用一张图来解决,这次打算手写一个方便日后的使用,除了带圆圈的「券」字用的是图以外其他都是用css画的(最后有点偷懒了,这里也可不用图),代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>优惠券</title>
<style>
.flashSale-bg {
display: flex;
justify-content: space-between;
border-radius: 8px;
margin: 0px 2.67%;
padding: 1.6%;
background-image: -webkit-linear-gradient(bottom, rgba(153,167,255,0.5) 55.67%, rgba(218,201,255,0.4));
}
.flashSale-left {
width: 49.27%;
height: 0;
padding-bottom: 23.94%;
}
.flashSale-right {
width: 49.27%;
height: 0;
padding-bottom: 23.94%;
}
.coupon{
border-radius: 6px;
overflow: hidden;
position: relative;
display: flex;
}
.coupon:after,.coupon:before{
content: "";
position: absolute;
display: block;
width:10px;
height:10px;
z-index: 2;
left: 74%;
border-radius: 5px;
}
.coupon:after{
bottom: -5px;
background: #c8cfff;
}
.coupon:before{
top: -5px;
background: #e8e3ff;
}
.coupon-left{
width: 75.74%;
background-color: #fff;
position: relative;;
}
.coupon-left-bg {
background-position: top right;
background-repeat: no-repeat;
background-size: 40%;
}
.coupon-left-uncollected-bg {
background-image: url('./yellow.png');
}
.coupon-left-collectedAndSellout-bg {
background-image: url('./gray.png');
}
.coupon-right:after{
content: "";
position: absolute;
top: 0;
display: block;
width: 6px;
height: 100%;
left: 75.74%;
z-index: 1;
background-position: 0px 0px;
background-color: transparent;
background-size: 6px 6px;
background-image: radial-gradient(circle at left, #fff 3px, transparent 0);
}
.coupon-right {
flex:1;
height: 0;
padding-bottom: 49.27%;
text-align: center;
}
.coupon-uncollected-status {
background-image: -webkit-linear-gradient(bottom, #FF5F00, #FDD76F);
}
.coupon-collected-status, .coupon-sellout-status {
background-image: -webkit-linear-gradient(bottom, #A29095, #CAC1C4);
}
#left-coupon-text, #right-coupon-text {
display: inline-block;
letter-spacing: 0.2px;
width: 15px;
font-size: 15px;
color: #fff;
line-height: 16px;
position: absolute;
top: 50%;
right: 0;
transform: translate(-68%,-50%);
}
.coupon-detail {
display: flex;
flex-direction: column;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 7%;
}
.coupon-value {
font-family: Helvetica;
font-size: 34px;
color: #FF714A;
}
.money-unit {
font-size: 12px;
}
.coupon-use-condition {
font-family: PingFangSC-Regular;
font-size: 11px;
color: #FF714A;
letter-spacing: 0.2px;
line-height: 16px;
}
.coupon-desc {
font-family: PingFangSC-Light;
font-size: 11px;
color: #564A39;
letter-spacing: 0;
line-height: 16px;
display: inline-block;
width: 121px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
</style>
</head>
<body>
<div class="flashSale-bg">
<div class="flashSale-left">
<div class="coupon">
<div class="coupon-left coupon-left-bg coupon-left-uncollected-bg">
<div class="coupon-detail">
<span class="coupon-value"><span class="money-unit">¥</span><span mp-role="couponValue">100</span></span>
<span class="coupon-use-condition" mp-role="useCondition">满500减100</span>
<span class="coupon-desc" mp-role="couponDesc">xx网站通用满减券</span>
</div>
</div>
<div class="coupon-right coupon-uncollected-status">
<span id="left-coupon-text" mp-role="couponBtn">立即领取</span>
</div>
</div>
</div>
<div class="flashSale-right">
<div class="coupon">
<div class="coupon-left coupon-left-bg coupon-left-collectedAndSellout-bg">
<div class="coupon-detail">
<span class="coupon-value"><span class="money-unit">¥</span><span mp-role="couponValue">50</span></span>
<span class="coupon-use-condition" mp-role="useCondition">满300减50</span>
<span class="coupon-desc" mp-role="couponDesc">xx网站通用满减券</span>
</div>
</div>
<div class="coupon-right coupon-sellout-status">
<span id="right-coupon-text" mp-role="couponBtn">已抢光</span>
</div>
</div>
</div>
</div>
</body>
</html>
业务中遇到一个需求就是点击提交按钮的时候,为了防止用户一直点击按钮,发送请求,当请求未返回结果之前对按钮进行禁用。因为按钮是用 <a>
标签写的,所以单纯的 disabled
不可取。
就这样遇到了 pointer-events
这个 CSS3 属性。其作用是指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target
。
pointer-events
属性相同,鼠标不会穿透当前层。在 SVG 中,该值和 visiblePainted 的效果相同。pointer-events
为其它值,比如auto,鼠标还是会监听这个子元素的。很遗憾,公司对浏览器兼容的最低标准是 IE10。白高兴一场,下方参考处有一个优雅的 polyfill 方案供参考。
在某些下拉框需求中会有下拉框收起时三角形朝下显示,下拉框弹出时三角形朝上显示。
这时可以通过 CSS 绘制该简单图形,通过切换类名达到切换显示效果。
具体实现:
.down {
width: 0px;
height: 0px;
border-top: 10px solid #ccc;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
.up {
width: 0px;
height: 0px;
border-bottom: 10px solid #ccc;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
箭头其实就是2个三角形,然后用白色三角形覆盖蓝色三角形,并且错开1px,刚刚好就形成了箭头。
左箭头:
.left{
position: absolute;
}
.left:before,.left:after{
position: absolute;
content: '';
border-top: 10px transparent dashed;
border-left: 10px transparent dashed;
border-bottom: 10px transparent dashed;
border-right: 10px #fff solid;
}
.left:before{
border-right: 10px #0099CC solid;
}
.left:after{
left: 1px; /*覆盖并错开1px*/
border-right: 10px #fff solid;
}
上箭头:
.top{
position: absolute;
}
.top:before,.top:after{
position: absolute;
content: '';
border-top: 10px transparent dashed;
border-left: 10px transparent dashed;
border-right: 10px transparent dashed;
border-bottom: 10px #fff solid;
}
.top:before{
border-bottom: 10px #0099CC solid;
}
.top:after{
top: 1px; /*覆盖并错开1px*/
border-bottom: 10px #fff solid;
}
最后可以通过 transform:rotate(90deg)
来搞定其他方向。
Error: getaddrinfo ENOTFOUND localhost
at errnoException (dns.js:50:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:95:26)
根据报错内容,推断是localhost的问题。有可能是localhost没有绑定127.0.0.1
回调函数:
import React, {Component} from 'react';
// 父组件
export default class Parent extends Component {
getName = (value) => {
console.log("receive name value is", value);
}
render() {
return(
<Child name={this.getName} />
)
}
}
// 子组件
export default class Child extends Component {
handleChange = (e) => {
let value = e.target.value;
this.props.getName(value);
}
render(){
return(
<input onChange={this.handleChange} />
)
}
}
import React, {Component} from 'react';
// 父组件
export default class Parent extends Component {
onRef = (ref) => {
this.child = ref;
}
click = (e) => {
this.child.myName();
}
render() {
return(
<div>
<Child onRef={this.onRef} />
<button onClick={this.click} >click</button>
</div>
)
}
}
// 子组件
class Child extends Component {
componentDidMount(){
this.props.onRef(this);
}
myName = () => console.log('Zzzzzzzzz')
render() {
return (
<div>子组件</div>
)
}
}
当在子组件中调用onRef
函数时,正在调用从父组件传递的函数。this.props.onRef(this)
这里的参数this
指向子组件本身,父组件接收该引用作为第一个参数:onRef = {ref =>(this.child = ref)}
然后它使用this.child
保存引用。之后,可以在父组件内访问整个子组件实例,并且可以调用子组件函数。
当存在多个子组件时,使用 this.child1、this.child2
即可,只是个绑定到父组件 this
上的参数名而已。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.