<!DOCTYPE html>
|
<html lang="en">
|
<head>
|
<meta charset="UTF-8">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
|
<script src='https://cdn.bootcdn.net/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js'></script>
|
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
|
<title>Document</title>
|
<style>
|
table {
|
border: 1px solid #000;
|
border-collapse: collapse;
|
}
|
td {
|
width: 50px;
|
height: 50px;
|
border: 1px solid #ccc;
|
}
|
</style>
|
</head>
|
<body>
|
<div id="app">
|
<p draggable="true">按钮</p>
|
<!-- <table border="1" ></table> -->
|
</div>
|
</body>
|
<script type="text/babel">
|
|
window.onload = function () {
|
let rows = 10;
|
let cols = 10;
|
let layout = createTableLayout({rows, cols})
|
console.log(layout)
|
const {useEffect,useState} = React;
|
const app = document.getElementById('app')
|
const AppContainer = function () {
|
const [data,setData] = useState(layout)
|
const [mouseDown,setMouseDown] = useState(false)
|
const [position,setPosition] = useState({})
|
const [showMenu,setShowMenu] = useState(false)
|
const [select,setSelect] = useState([])
|
const [ranges,setRange] = useState([])
|
const onMousedown = (e,v) => {
|
if (e.button !==0) return
|
setMouseDown(true)
|
setShowMenu(false)
|
setSelect([v])
|
}
|
const contextmenu = e => {
|
e.preventDefault()
|
e.stopPropagation()
|
let {pageX:left,pageY:top} = e
|
setShowMenu(true)
|
setPosition({
|
left,top
|
})
|
}
|
const onMouseMove = (e,v) => {
|
if(!mouseDown) return
|
setSelect([select[0], v])
|
}
|
// 合并
|
const merge = (e) => {
|
const layoutNew = [...layout]
|
const {x,x1,y,y1} = ranges
|
let addRow = ranges.x1 - ranges.x
|
let addCol = ranges.y1 - ranges.y
|
|
for(var i=x;i<=x1;i++) {
|
for(var j=y;j<=y1;j++) {
|
if (i==x && j==y) {
|
layoutNew[i][j].rowspan = ranges.x1 - ranges.x + 1
|
layoutNew[i][j].colspan = ranges.y1 - ranges.y + 1
|
} else {
|
layoutNew[i][j].rowspan = 0
|
layoutNew[i][j].colspan = 0
|
layoutNew[i][j].parent = [x,y] // 归属父级
|
}
|
}
|
}
|
setData(layoutNew)
|
setRange({x,y,x1:x,y1: y})
|
setShowMenu(false)
|
}
|
// 拆分
|
const split = e => {
|
const layoutNew = [...layout]
|
const {x,x1,y,y1} = ranges
|
for(var i=x;i<=x1;i++) {
|
for(var j=y;j<=y1;j++) {
|
if (i==x && j==y) {
|
layoutNew[i][j].rowspan = 1
|
layoutNew[i][j].colspan = 1
|
} else {
|
layoutNew[i][j].rowspan = 1
|
layoutNew[i][j].colspan = 1
|
layoutNew[i][j].parent = null // 归属父级
|
}
|
}
|
}
|
setData(layoutNew)
|
setRange({x,y,x1:x,y1: y})
|
setShowMenu(false)
|
}
|
const addRow = () => {
|
console.log('--------')
|
let layoutNew = [...layout]
|
let row = []
|
for(var i=0;i<cols;i++) {
|
row.push({
|
rowspan: 1,
|
colspan: 1,
|
rowIndex: rows + 1,
|
colIndex: i,
|
type: ''
|
})
|
}
|
rows +=1
|
layoutNew.push(row)
|
console.log(layoutNew)
|
setData(layoutNew)
|
}
|
const addCol = () => {
|
let layoutNew = [...layout]
|
let row = []
|
for(var i=0;i<rows;i++) {
|
layoutNew[i].push({
|
rowspan: 1,
|
colspan: 1,
|
rowIndex: i,
|
colIndex: cols + 1,
|
type: ''
|
})
|
}
|
cols +=1
|
layoutNew.push(row)
|
console.log(layoutNew)
|
setData(layoutNew)
|
}
|
useEffect(() => {
|
// document.querySelector('body').addEventListener('click', e => {
|
// setShowMenu(false)
|
// })
|
document.querySelector('body').addEventListener('mouseup', e => {
|
setMouseDown(false)
|
})
|
document.querySelector('table').addEventListener('mouseleave', e => {
|
console.log('leave')
|
setMouseDown(false)
|
// setShowMenu(false)
|
})
|
document.querySelector('table').addEventListener('contextmenu', e => {
|
e.preventDefault()
|
e.stopPropagation()
|
let {pageX:left,pageY:top} = e
|
setShowMenu(true)
|
setPosition({
|
left,top
|
})
|
console.log(ranges,'>>>>>>>')
|
})
|
},[]);
|
const getParent = (v,layout) => {
|
if (v.rowspan === 0) {
|
return getParent(layout[v.parent[0]][v.parent[1]],layout)
|
} else {
|
return v
|
}
|
}
|
useEffect(() => {
|
console.log('已选择',select)
|
let data
|
if (select.length > 1) {
|
// 起始行号 不包含合并
|
let x = Math.min(select[0].rowIndex,select[1].rowIndex)
|
let x1 = Math.max(select[0].rowIndex + select[0].rowspan -1,select[1].rowIndex + select[1].rowspan -1)
|
let y = Math.min(select[0].colIndex,select[1].colIndex)
|
let y1 = Math.max(select[0].colIndex + select[0].colspan -1 ,select[1].colIndex + select[1].colspan -1 )
|
// 范围内碰到合并格
|
for(var i=x;i<=x1;i++) {
|
for(var j=y;j<=y1;j++) {
|
let v = getParent(layout[i][j],layout)
|
x = Math.min(x,v.rowIndex)
|
y = Math.min(y,v.colIndex)
|
x1 = Math.max(x1,v.rowIndex + v.rowspan -1 )
|
y1 = Math.max(y1,v.colIndex + v.colspan - 1)
|
}
|
}
|
data = {x,y,x1,y1}
|
|
} else if(select.length === 1) {
|
let x = select[0].rowIndex
|
let y = select[0].colIndex
|
let x1 = select[0].rowIndex + select[0].rowspan -1
|
let y1 = select[0].colIndex + select[0].colspan -1
|
data = {x,y,x1,y1}
|
}
|
// 范围内碰到
|
// for(var i=x;i<=x1;i++) {
|
// for(var j=y;j<=y1;j++) {
|
// if()
|
// }
|
// }
|
console.log('range:',data)
|
setRange(data)
|
}, [select])
|
return <div style={{position: 'relative'}}>
|
<table>
|
{data.map((item,i) => {
|
return <tr>{
|
item.filter(v=> !(v.rowspan === 0 || v.colspan ===0)).map((v,j) => <td rowspan={v.rowspan} colspan={v.colspan} style={{background: (ranges && ranges.x > -1 && v.rowIndex >=ranges.x && v.rowIndex<=ranges.x1 && v.colIndex>=ranges.y && v.colIndex<=ranges.y1) ? '#ccc' : ''}} onContextMenu={contextmenu} onMouseDown={e=>onMousedown(e,v)} onMouseMove={e => onMouseMove(e,v)}></td>)
|
}</tr>
|
})}
|
</table>
|
{showMenu ? <div class="btns" style={{position: 'absolute',zIndex: 999,...position}}>
|
<div style={{cursor: 'pointer'}} onClick={e => merge(e)}>合并</div>
|
<div style={{cursor: 'pointer'}} onClick={e => split(e)}>拆分</div>
|
<div style={{cursor: 'pointer'}} onClick={e => addRow(e)}>增加行</div>
|
<div style={{cursor: 'pointer'}} onClick={e => delRow(e)}>删除行</div>
|
<div style={{cursor: 'pointer'}} onClick={e => addCol(e)}>增加列</div>
|
<div style={{cursor: 'pointer'}} onClick={e => delCol(e)}>删除列</div>
|
</div> : null}
|
</div>
|
};
|
ReactDOM.render(
|
<AppContainer />,
|
document.getElementById('app')
|
);
|
}
|
|
|
|
function createTableLayout ({
|
rows,
|
cols,
|
}) {
|
let data = []
|
for(var i=0;i<rows;i++) {
|
let arr = []
|
for(var j=0;j<cols;j++) {
|
arr.push({
|
rowspan: 1,
|
colspan: 1,
|
rowIndex: i,
|
colIndex: j,
|
type: ''
|
})
|
}
|
data.push(arr)
|
}
|
return data
|
}
|
</script>
|
</html>
|