需求:点击按钮出现弹窗,点击空白地方弹窗消失
关联的问题:e.stopPropgation() 不起作用;
这种需求在我看来说很简单的,给document 绑定 click事件,点击后选择关闭弹窗,在窗体使用 e.stopPropgation() 来阻止冒泡行为。思路是这样,但是在React 中却不能单纯如此,因为e.stopPropgation() 不能阻止冒泡行为的发生,原因在于react 把事件绑定委托给document ,当你阻止冒泡的时候,document 早就接受到了点击事件,需要使用React 的e.nativeEvent
const [show,setShow]=useState(false)
const Clik=(e)=>{
e.stopImmediatePropagation()
setShow(false)
}
useEffect(()=>{
document.addEventListener('click',Clik)
return ()=>{document.removeEventListener('click',Clik)}
},[show])
...
// 以show 作为关闭窗口的开关
{show?
<div onClick=(e)=>{e.nativeEvent.stopImmediatePropagation();} >窗体</div>:
''}
当然在开发过程中遇到了一些问题,如:react 在 document 上绑定事件的时候,获取的 state 是初始化的,react 在路由改变后重新进入的时候,绑定的改变状态的事件还在,组件却不对其做出改变了,当然这些问题与需求是 Hooks 的使用不规范所导致的问题,在你将其不规范的地方改正后,这些问题都会消失
问题:用户短时间内点击多次所产生的多次请求的问题
关联的问题:中断之前的网络请求;防止用户的多次点击;函数节流与防抖
这样的问题,在很多情况下都会出现,这涉及到前端的一些解决思路节流和防抖。
以按钮点击来举例节流和防抖
函数节流:以固定的频率执行执行函数,不管你点击多快,没达到设定的时间就不执行
函数防抖:类似游戏的释放法术,只要你点击了就会重新读条,读条完成才会执行函数
中断网络请求
不同的框架封装着不同的打断方式,
JS与JQ
//方法就是将XHR对象指向currentAjax,再调用currentAjax的.abort()来中止请求
var currentAjax = null;
function startAjax(){
if(currentAjax) {currentAjax.abort();}
currentAjax = $.ajax({
type:'POST',
beforeSend:function(){},
url:'test.php',
data:'username=xxx',
dataType:'JSON',
error:function(){alert('error')},
success:function(data){alert(data)}
});
}
Angular
//通过注入 `$q` 服务,使用`$q.defer`来停止
var _enj;
$scope.clconversations=function(){
if(_enj){_enj.resolve()};
_enj = $q.defer();
$http.get('/Iridium/public/tcpanalysis/getconversations',{
params:{
start_time: $scope.start_time,
end_time:$scope.end_time,
},
timeout:_enj.promise
}).then(function(response){
console.log('')
});
}
需求:数据表格,要求竖向滚动,表头固定,横向滚动,表头能跟随
关联的问题,传统表格中 display:table 系列和高度产生滚动条的冲突
这样的问题在很多时候我们都会遇到,在 Html 中,可以通过 html + js 的方式创建 div 模拟 table 表格来进行展示。
在react中,我需要把它单独抽出,这样其他地方时候也能用到。
import * as React from 'react'
var $ = require('jquery')
export class LTable extends React.Component<any,any>{
constructor(props:any) {
super(props);
this.resize=this.resize.bind(this)
this.state = {
id:this.props.id||'l_'+(new Date().getTime()+Math.random()).toFixed(3),
clas:this.props.className||'',
height:this.props.height||'300px',
}
}
static contextTypes={
router: function(){
return null
}
}
mounted = false;
componentWillMount(){
this.mounted = true;
}
componentDidMount() {
window.addEventListener('resize', this.resize)
this.resize()
}
componentDidUpdate(){
this.resize()
}
componentWillUnmount(){
window.removeEventListener('resize',this.resize);
this.mounted = false;
}
resize(){
let id=this.state.id
let tbody=this.props.tbody
if(tbody.length>0){
let ltable=document.getElementById(id)!.getElementsByTagName('table')
let thead0=ltable[0].getElementsByTagName('thead')[0]
let thead1=ltable[1].getElementsByTagName('thead')[0]
let ltbody=document.getElementById(id)!.getElementsByClassName('l_table_body')[0]
let th0=thead0.getElementsByTagName('th')
let th1=thead1.getElementsByTagName('th')
thead0.style.minWidth=thead1.offsetWidth+'px'
ltable[0].style.width=ltable[1].offsetWidth+'px'
for(let i=0;i<th1.length;i++){
th0[i].style.width=th1[i].offsetWidth+'px'
}
$(ltbody).scroll(function(e:any){
let div=document.getElementById(id)!.getElementsByClassName('l_table_head')[0]
div.scrollLeft=e.target.scrollLeft
})
}
}
render(){
let thead=this.props.thead,tbody=this.props.tbody
return (
<div id={this.state.id} className={"l_table "+this.state.clas}>
{this.props.title?
<h3 className="l_table_title">{this.props.title}</h3>:''
}
<div className="l_table_head l_scroll_hide">
<table>
<thead>
<tr>
{thead.map((e:any,i:any)=>
<th key={i}>{e.title}</th>
)}
</tr>
</thead>
</table>
</div>
<div className="l_table_body" style={{height:this.state.height}}>
{tbody.length>0?
<table>
<thead>
<tr>
{thead.map((e:any,i:any)=>
<th key={i}>{e.title}</th>
)}
</tr>
</thead>
<tbody>
{tbody.map((tr:any,a:any)=>
<tr key={a}>
{thead.map((td:any,b:any)=>{
if(td.render){
return <td key={b}>{td.render(tr)}</td>
}else{
return <td key={b}>{td.title}</td>
}
})}
</tr>
)}
</tbody>
</table>:
<div className="l_nodata">
<span>No Date</span>
</div>
}
</div>
</div>
)
}
}