Git Product home page Git Product logo

znotes's People

Contributors

zhaofeihao avatar

Stargazers

 avatar

znotes's Issues

React 事件处理 -- 各种绑定

React 事件处理

事件处理程序(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>
    );
  }
}

箭头函数表达式语法比传统的函数表达式简短且没有自己的 thisargumentssupernew.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 的话,事件对象以及更多的参数将会被隐式的进行传递。

参考

A guide to React onClick event handlers

事件处理

React 事件绑定的正确姿势

对象数组形式的数据筛选

最近在做的项目后端一次性返回全部指标下的全部数据,然后前端进行筛选展示,各种情况十分繁琐,进行一下总结。

以下面的数据结构为例,分情况讨论一下筛选方法。

例子中 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

前端开发也要学点儿 Linux 基础命令

干啥

需要在服务器上安装环境?编辑配置文件?查看运行日志?命令到用时方恨少。

有啥好处

逼格是程序员的安身立命之本。同时不断扩展自己的边界,向外延伸。做最好的准备,成就更好的你(我可以做程序员鼓励师了)。让我从一点儿 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

  • 模式切换(命令模式 / 编辑模式 / 底行命令模式)
  • 光标移动
  • 删除 / 复制 / 粘贴 / 插入
  • 文本查找
  • 退出保存
vim 文件名  // G 跳到文件结尾,gg跳到文件开头,/+关键字查找指定关键字(n向下查找,N向上查找),
d // 移动光标可以删除一个字符
dw // 删除一个单词,其实这里面提到的删除是指剪切,存到buffer里去了
dd // 删除一行,u可以撤销刚才的操作
p // 粘贴,buffer 里的内容
i // 开启插入/编辑模式
a // 在当前字符的后面进行插入
A // 在当前行末尾插入
esc // 从编辑模式回到命令模式
: // 进入底行命令模式
:q // 退出当前文件
:w // 保存当前文件,加叹号 ! 强制保存
:wq // 保存并退出,缩写是 x

打包与压缩

  • gzip / bzip2
  • tar
  • zip
  • zcat / zgrep / zmore / zless(查看gzip压缩包中的内容)
tar -zcvf tarTest.tgz tarTest/      // 将 tarTest 文件夹压缩为.tgz 格式的文件,tgz 代表使用 gzip 压缩的 tar 包,参数 -z 表示gzip压缩,c表示压缩,v 表示压缩的信息,f 表示如果文件存在的话覆盖它
tar -tvf tarTest.tgz  // 显示压缩文件中的内容,不解包
tar -xzf tarTest.tgz   // 解压包
// tar的优点就是能保存很多信息

动手操作一下效果更佳

Mac 解决端口占用问题

查看端口

lsof -i tcp: port_num

其中 port_num 可替换为任意端口号,如

lsof -i tcp: 80

image

杀进程

找到进程的PID,使用kill命令:kill PID(进程的PID,如2044),杀死对应的进程

kill pid

kill 30316

前端使用blob对象下载文件

文件常见的一种方式是用下面这个方法来下载一个文件。采用的方式就是拼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();
},

HTML+CSS绘制移动端优惠券组件

image

以前写领券模块时总是用一张图来解决,这次打算手写一个方便日后的使用,除了带圆圈的「券」字用的是图以外其他都是用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>

CSS3 pointer-events 属性小结

是啥

业务中遇到一个需求就是点击提交按钮的时候,为了防止用户一直点击按钮,发送请求,当请求未返回结果之前对按钮进行禁用。因为按钮是用 <a> 标签写的,所以单纯的 disabled 不可取。

就这样遇到了 pointer-events 这个 CSS3 属性。其作用是指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target

咋用

  • auto —— 效果和没有定义 pointer-events 属性相同,鼠标不会穿透当前层。在 SVG 中,该值和 visiblePainted 的效果相同。
  • none —— 元素不再是鼠标事件的目标,鼠标不再监听当前层而去监听下面的层中的元素。但是如果它的子元素设置了 pointer-events 为其它值,比如auto,鼠标还是会监听这个子元素的。
  • 其它属性值为SVG专用,这里不多提。

兼容性

pointer-events

很遗憾,公司对浏览器兼容的最低标准是 IE10。白高兴一场,下方参考处有一个优雅的 polyfill 方案供参考。

参考

MDN - pointer-events

前端观察 - CSS3 pointer-events介绍

张鑫旭 - CSS3 pointer-events:none应用举例及扩展

Github - pointer_events_polyfill.js

css 绘制三角形和箭头

三角形

在某些下拉框需求中会有下拉框收起时三角形朝下显示,下拉框弹出时三角形朝上显示。

down

image

这时可以通过 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;
}

left

上箭头:

.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;
}

top

最后可以通过 transform:rotate(90deg) 来搞定其他方向。

Mac使用小技巧 -- 持续复制粘贴中

跳过 brew install 的 update

每次brew install 一些东西的时候,都会update很长时间,甚是恼火。
我只想安装我需要的包。
那么就直接按 control + c 一次跳过吧。
两次的话就终止了,慎点。

Mac 解决端口占用问题

  • 查看端口
lsof -i tcp: port_num

其中 port_num 可替换为任意端口号,如

lsof -i tcp: 80

image

  • 杀进程
    找到进程的PID,使用kill命令:kill PID(进程的PID,如2044),杀死对应的进程
kill pid

kill 30316

npm run dev 报错:getaddrinfo ENOTFOUND localhost

报错信息:

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

解决方法(Mac)

  1. 打开 terminal
  2. 键入 sudo vi /etc/hosts
  3. 键入 i 进入编辑模式
  4. 输入 127.0.0.1 localhost
  5. 按下 esc 键
  6. 输入 :wq 保存并退出

React 中父组件获取子组件数据 / 调用子组件方法

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} />
        )
    }
}

2. 父组件调用子组件方法

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 上的参数名而已。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.