index.tsx中
import React, { Component, createRef } from 'react';
import './index.less'
interface Props{
}
interface State{
ButtonList:List[]
Index:number
}
interface List{
id:string,
txt:string
}
export default class ImitationBrowser extends Component<Props,State> {
constructor(props:Props){
super(props);
this.state={
ButtonList:[
{
id:"内容1",
txt:"内容1"
}
],
Index:0
}
}
// 最后的坐标
x: number = 0;
y: number = 0;
parent = createRef<HTMLDivElement>();
// 按下元素
box?: HTMLDivElement;
// 父元素宽高
oldWidth: number = 0;
oldHeight: number = 0;
// 鼠标坐标
oldX: number = 0;
oldY: number = 0;
// 父元素坐标
oldLeft: number = 0;
oldTop: number = 0;
// 删除时要用到的数组
arr:List[]=[];
// 判断鼠标按下时是什么元素
tl:boolean=false;
bl:boolean=false;
tr:boolean=false;
br:boolean=false;
t:boolean=false;
b:boolean=false;
l:boolean=false;
r:boolean=false;
IfHeader:boolean=false;
FnDown(ev: MouseEvent) {
this.box = ev.target as HTMLDivElement;
ev.stopPropagation();
ev.preventDefault();
this.oldWidth = this.getParent().offsetWidth;
this.oldHeight = this.getParent().offsetHeight;
this.oldX = ev.clientX;
this.oldY = ev.clientY;
this.oldLeft = this.getParent().offsetLeft;
this.oldTop = this.getParent().offsetTop;
this.tl=this.box.classList.contains('tl');
this.bl=this.box.classList.contains('bl');
this.tr=this.box.classList.contains('tr');
this.br=this.box.classList.contains('br');
this.t=this.box.classList.contains('t');
this.b=this.box.classList.contains('b');
this.l=this.box.classList.contains('l');
this.r=this.box.classList.contains('r');
this.IfHeader=this.box.classList.contains('header');
document.onmousemove = this.FnMove.bind(this);
document.onmouseup = this.FnUp.bind(this);
}
FnMove(ev: MouseEvent) {
ev.stopPropagation();
ev.preventDefault();
this.box = ev.target as HTMLDivElement;
// 最终的位置=(之前的盒子坐标+(现在鼠标坐标-以前鼠标坐标))
this.y = (this.oldTop + (ev.clientY - this.oldY));
this.x = (this.oldLeft + (ev.clientX - this.oldX));
if (this.tl) {
this.getParent().style.width = this.oldWidth - (ev.clientX - this.oldX) + 'px';
this.getParent().style.height = this.oldHeight - (ev.clientY - this.oldY) + 'px';
this.getParent().style.left = this.x + 'px';
this.getParent().style.top = this.y + 'px';
}
else if (this.bl) {
this.getParent().style.width = this.oldWidth - (ev.clientX - this.oldX) + 'px';
this.getParent().style.height = this.oldHeight + (ev.clientY - this.oldY) + 'px';
this.getParent().style.left = this.x + 'px';
this.getParent().style.bottom = this.oldTop + (ev.clientY + this.oldY) + 'px';
}
else if (this.tr) {
this.getParent().style.width = this.oldWidth + (ev.clientX - this.oldX) + 'px';
this.getParent().style.height = this.oldHeight - (ev.clientY - this.oldY) + 'px';
this.getParent().style.right = this.oldLeft - (ev.clientX - this.oldX) + 'px';
this.getParent().style.top = this.y + 'px';
}
else if (this.br) {
this.getParent().style.width = this.oldWidth + (ev.clientX - this.oldX) + 'px';
this.getParent().style.height = this.oldHeight + (ev.clientY - this.oldY) + 'px';
this.getParent().style.right = this.oldLeft - (ev.clientX - this.oldX) + 'px';
this.getParent().style.bottom = this.oldTop + (ev.clientY + this.oldY) + 'px';
}
else if (this.t) {
this.getParent().style.height = this.oldHeight - (ev.clientY - this.oldY) + 'px';
this.getParent().style.top = this.y + 'px';
}
else if (this.b) {
this.getParent().style.height = this.oldHeight + (ev.clientY - this.oldY) + 'px';
this.getParent().style.bottom = this.y + 'px';
}
else if (this.l) {
this.getParent().style.height = this.oldHeight + 'px';
this.getParent().style.width = this.oldWidth - (ev.clientX - this.oldX) + 'px';
this.getParent().style.left = this.x + 'px';
}
else if (this.r) {
this.getParent().style.height = this.oldHeight + 'px';
this.getParent().style.width = this.oldWidth + (ev.clientX - this.oldX) + 'px';
this.getParent().style.right = this.x + 'px';
}
if (this.IfHeader) {
this.getParent().style.left = this.x + 'px';
this.getParent().style.top = this.y + 'px';
}
}
FnUp() {
document.onmousemove = null;
document.onmouseup = null;
}
componentDidMount() {
this.getParent().onmousedown = this.FnDown.bind(this);
}
getParent() {
return this.parent.current as HTMLDivElement
}
AddPage(){
this.arr=this.state.ButtonList;
let num =this.state.ButtonList.length+1;
let obj:List={id:'内容'+num,txt:'内容'+num};
this.arr.push(obj);
this.setState({
ButtonList:this.arr,
Index:num-1
})
}
Cut(index:number){
this.setState({
Index:index
})
}
close(id:string) {
let arr = [...this.state.ButtonList]
arr = arr.filter((item) => {
return item.id !== id
})
let num=this.state.ButtonList.length;
this.setState({
ButtonList:arr,
Index:num-2 //这里有点问题
})
}
allClose(){
this.getParent().remove();
}
render() {
return (
<div className="box" ref={this.parent}>
{/* 可以拖动的头部区域 */}
<div className="header">
<div className="left">
{this.state.ButtonList.map((item,index)=>
<div className={this.state.Index===index?"button-list ac":"button-list"} onClick={this.Cut.bind(this,index)} key={item.id}>
<div className="text">{item.txt}</div>
<div className="del" onClick={this.close.bind(this,item.id)}>x</div>
</div>
)}
<div className="add" onClick={this.AddPage.bind(this)}>+</div>
</div>
<div className="right" onClick={this.allClose.bind(this)}>x</div>
</div>
{/* 边框与角 */}
<span className="r"></span>
<span className="l"></span>
<span className="t"></span>
<span className="b"></span>
<span className="br"></span>
<span className="bl"></span>
<span className="tr"></span>
<span className="tl"></span>
{/* 内容区域 */}
<div className="inner">
{this.state.ButtonList.map((item,index)=>
<div className="content-list" style={{display:this.state.Index===index?"block":"none"}} key={index}>
{item.txt}
</div>
)}
</div>
</div>
)
}
}
index.less中
.box {
width: 1000px;
height: 800px;
// border: 1px solid #ccc;
position: absolute;
box-sizing: border-box;
//位置的值必须加上,不然定位可能会不准确
top: 0;
left: 0;
.header {
height: 100px;
text-align: center;
border-bottom: 1px solid #ccc;
padding-right: 20px;
display: flex;
align-items: center;
overflow-x: scroll;
justify-content: space-between;
.left {
display: flex;
align-items: center;
.button-list {
font-size: 30px;
padding: 5px;
min-width: 200px;
height: 90px;
line-height: 90px;
text-align: center;
background-color: #fff;
border: 1px solid #ccc;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
display: flex;
align-items: center;
justify-content: space-around;
.del {
font-size: 30px;
}
}
}
.right{
font-size: 50px;
}
.button-list.ac {
font-size: 30px;
padding: 5px;
min-width: 200px;
height: 90px;
line-height: 90px;
text-align: center;
background-color: pink;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
}
.add {
font-size: 60px;
color: #ccc;
}
}
.header::-webkit-scrollbar {display:none}
/*四边*/
.t,
.b,
.l,
.r {
position: absolute;
z-index: 1;
background: #666;
}
.l,
.r {
width: 10px;
height: 100%;
top: -5px;
cursor: col-resize;
}
.t,
.b {
width: 100%;
height: 10px;
cursor: row-resize;
}
.t {
top: 0;
}
.b {
bottom: 0;
}
.l {
left: -5px;
}
.r {
right: 0;
}
/*四角*/
.tl,
.bl,
.br,
.tr {
width: 20px;
height: 20px;
position: absolute;
background: #fff;
border: 1px solid #666;
z-index: 2;
cursor: nwse-resize
}
.tl,
.bl {
left: -5px;
}
.tr,
.br {
right: -5px;
}
.br,
.bl {
bottom: -5px;
}
.tl,
.tr {
top: -5px;
}
.tr,
.bl {
cursor: nesw-resize;
}
/*内核*/
.inner {
width: 100%;
height: 90%;
.content-list {
font-size: 50px;
width: 100%;
height: 100%;
text-align: center;
line-height: 100%;
}
}
}