某次在Uniapp群看到有人問uniapp如何操作dom元素。 ![](https://img2023.cnblogs.com/blog/3112483/202306/3112483-20230605170528006-986335874.png) 他想對這張表標紅的區域,做dom元素獲取,因為產品 ...
某次在Uniapp群看到有人問uniapp如何操作dom元素。
他想對這張表標紅的區域,做dom元素獲取,因為產品想讓紅色色塊點擊時,成為可編輯,渲染1~4月份之間的行程安排。
於是,有小伙伴說讓他用position定位這裡,點擊時使紅色色塊層級抬高,弄個input上去。
但提問的小伙伴並沒有決定這麼做,隨後不了了之。
在初步自學了一段時間React後,我覺得可以試一下用React實現這種效果。
以下圖二為練習之作,實際上對應的月份編輯已經實現
如果要寫成如圖1那種展示和編輯,就需要td裡加入div容器並對其絕對定位
而相應公式了我粗略的整理了一下,並附上
<td className='sTh'>
{/* 做判斷,迴圈時得到的月和次月的做比較,如果次月依舊屬於其中,則繼續,直到次月不在算入規劃中 */}
{/* 預設 1個月為 width 90 * 1 + '%' right:'-5%' */}
{/* 那麼 如果2月份也是 width 90 * 2 + '%' right:'-90%' */}
{/* 那麼 如果3月份也是 width 90 * 3 + '%' right:'-185%' -85為一刻度,初始-5% */}
{/* 預設右側偏移量是 100*1 - 5% *1 */}
{/* 新增1個單位 等於 100*2 - 5% *2 */}
{/* 新增2個單位 等於 100*3 - 5% *3 */}
{/* (item.name, index + 1) */}
<div className='sPo' style={{ width: 90 * 4 + '%', right: '-280%' }}
contentEditable={true}
suppressContentEditableWarning={true}
onBlur={() => handleEdit}
ref={editRef}>
{/* <INput /> */}
</div>
</td>
具體做法,其實已經不遠。
感興趣的小伙伴可以體驗一下,當然,如果發現有什麼地方存在問題或缺陷bug,歡迎指正。
table 無狀態組件
import React, { useState, useRef } from 'react';
const Table = () => {
const [data, setData] = useState([{ name: '張三', li: [4, 9, 5, 6] }, { name: '李四', li: [11] }]);
const editRef = useRef('null');
// 被操作的名字
// 被操作的月份
// 被操作的值
const handleEdit = (name, month, e) => {
const newData = [...data];
const item = newData.find((item) => item.name === name);
item.li[month] = parseInt(e.target.innerText);
setData(newData);
};
const renderTable = () => {
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
const tableData = [];
// 添加表頭
const headerRow = [<th key="name" className='sTh'>姓名</th>];
months.forEach((month) => {
headerRow.push(<th key={month} className='sTh'>{month}</th>);
});
tableData.push(<tr key="header" className='sTh'>{headerRow}</tr>);
// 添加數據行
data.forEach((item) => {
const dataRow = [<td key="name" className='sTh'>{item.name}</td>];
months.forEach((month, index) => {
if (item.li.includes(index + 1)) {
const value = item.li[index + 1] || '';
dataRow.push(
<td
key={month}
style={{ backgroundColor: 'red' }}
contentEditable={true}
suppressContentEditableWarning={true}
onBlur={(e) => handleEdit(item.name, month, e)}
ref={editRef}
className='sTh'
>
{value}
</td>
);
} else {
dataRow.push(<td key={month} className='sTh'></td>);
}
});
tableData.push(<tr key={item.name} className='sTh'>{dataRow}</tr>);
});
return tableData;
};
return (
<table className='sTab'>
<tbody>{renderTable()}</tbody>
</table>
);
};
</details>
.sTab {
border-collapse: collapse;
border: 1px solid gray;
width: 100%;
text-align: center;
font-size: 0.28rem;
}
/*
1. separate:預設值,邊框會被分開,不會忽略border-spacing 和 empty-cells 屬性。
2. collapse:如果可能,邊框會合併為一個單一的邊框。會忽略 border-spacing 和 empty-cells 屬性。
3. inherit:規定應該從父元素繼承border-collapse 屬性的值
*/
.sTh {
border: 1px solid gray;
border-top: none;
border-left: none;
position: relative;
}
.sPo{
height: 15px;
position: absolute;
top: 2px;
right: -2%;
z-index: 10;
width: 100%;
background: red;
}
/*
contenteditable 編輯時帶來的黑框
*/
[contenteditable]:focus {
outline: none;
}