숫자가있는 테이블이 있습니다. 표에서 셀을 클릭하면 활성 상태가 전환됩니다. 하나의 셀을 선택하고 crtl을 누르고 다른 셀을 선택하고 결과적으로 첫 번째와 두 번째 사이의 셀이 활성화됩니다. 그것을 구현하는 방법?
코드 펜 https://codepen.io/geeny273/pen/GRJXBQP
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
const grid = document.getElementById("grid")
grid.onclick = (event) => {
event.stopPropagation();
const { className } = event.target;
if (className.includes('cell')) {
if (className.includes('active')) {
event.target.className = 'cell';
} else {
event.target.className = 'cell active';
}
}
}
시프트 하이라이트처럼 작동하고 양방향으로 작동합니다.
답변
이 시도:
const cells = document.querySelectorAll(".cell");
let lastClicked;
function handleClick(e) {
// Toggle class active
if (e.target.classList.contains("active")) {
e.target.classList.remove("active");
} else {
e.target.classList.add("active");
}
// Check if CTRL key is down and if the clicked cell has aready class active
let inRange = false;
if (e.ctrlKey && this.classList.contains("active")) {
// loop over cells
cells.forEach(cell => {
// check for the first and last cell clicked
if (cell === this || cell === lastClicked) {
// reverse inRange
inRange = !inRange;
}
// If we are in range, add active class
if (inRange) {
cell.classList.add("active");
}
});
}
// Mark last clicked
lastClicked = this;
}
cells.forEach(cell => cell.addEventListener("click", handleClick));
#grid {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(2, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
}
.active {
background-color: #80aaff;
}
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
답변
Javascript 부분을 프로그래밍 한 것과 완전히 다르게 프로그래밍했습니다 . 여전히 사용할 수 있기를 바랍니다. 그러나 그것은 당신이 요구 한 것을 정확하게 수행합니다.
Shift + Cell을 사용하면 사이의 모든 셀을 선택할 수 있습니다.
var $lastSelected = [],
container = $('#grid'),
collection = $('.cell');
container.on('click', '.cell', function(e) {
var that = $(this),
$selected,
direction;
if (e.shiftKey){
if ($lastSelected.length > 0) {
if(that[0] == $lastSelected[0]) {
return false;
}
direction = that.nextAll('.lastSelected').length > 0 ? 'forward' : 'back';
if ('forward' == direction) {
// Last selected is after the current selection
$selected = that.nextUntil($lastSelected, '.cell');
} else {
// Last selected is before the current selection
$selected = $lastSelected.nextUntil(that, '.cell');
}
collection.removeClass('selected');
$selected.addClass('selected');
$lastSelected.addClass('selected');
that.addClass('selected');
} else {
$lastSelected = that;
that.addClass('lastSelected');
collection.removeClass('selected');
that.addClass('selected');
}
} else {
$lastSelected = that;
collection.removeClass('lastSelected selected');
that.addClass('lastSelected selected');
}
});
.selected {background-color: #80aaff;}
#grid{
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(2, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
행운을 빕니다 😉
답변
사용 previousElementSibling
하여compareDocumentPosition()
const grid = document.getElementById("grid");
const cells = [...grid.querySelectorAll(".cell")];
let recentActive;
grid.onclick = event => {
event.stopPropagation();
const { className } = event.target;
if (!className.includes("cell")) {
return;
}
let compareMask = recentActive && recentActive.compareDocumentPosition(event.target);
let property = compareMask == 2 ? "nextElementSibling" : "previousElementSibling";
let state = event.target.classList.toggle("active");
let sibiling = event.target[property];
while (event.ctrlKey && state && !sibiling.classList.contains("active")) {
sibiling.classList.add("active");
sibiling = sibiling[property];
}
recentActive = event.target;
};
실무 데모
답변
정방향 및 역방향 기능을 갖춘 완벽한 솔루션 :
const grid = document.getElementById("grid");
var lastactive = "";
grid.onclick = (event) => {
event.stopPropagation();
const { className } = event.target;
if (className.includes('cell')) {
if (className.includes('active')) {
event.target.className = 'cell';
if(lastactive != "" && event.target === lastactive) {
lastactive = "";
let cells = document.querySelectorAll('.cell');
for(let i = 0; i < cells.length; i++) {
if(cells[i].className.includes('active')) {
lastactive = cells[i];
break;
}
}
}
}
else {
event.target.className = 'cell active';
if(event.ctrlKey && lastactive != "") {
let current = event.target;
if(event.target.compareDocumentPosition(lastactive) == 4 /*event target is before or after last active?*/) {
while(current != lastactive) {
current.className = 'cell active';
current = current.nextElementSibling;
}
}
else {
while(current != lastactive) {
current.className = 'cell active';
current = current.previousElementSibling;
}
}
}
lastactive = event.target;
}
}
console.log(lastactive);
}
#grid {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(3, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
cursor: pointer;
user-select: none;
}
.active {
background-color: #80aaff;
}
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
<div class="cell">7</div>
<div class="cell">8</div>
<div class="cell">9</div>
</div>
답변
선택한 요소의 색인을 저장하여 작성했습니다. (2-> 6) 및 (6-> 2) 두 가지 방식으로 작동합니다.
const grid = document.getElementById("grid")
var cells = []
function activate_cell(min, max) {
for (var i = 0; i < grid.children.length; i++) {
// Clear all selection
var el = Array.from(grid.children)[i]
el.classList.remove("active");
}
for (var i = min; i <= max; i++) {
var el = Array.from(grid.children)[i]
el.classList.toggle("active");
}
}
grid.onclick = (event) => {
event.stopPropagation();
const { className } = event.target;
const index = Array.from(grid.children).indexOf(event.target)
cells.push(index)
if (event.ctrlKey) {
activate_cell(Math.min(...cells), Math.max(...cells))
} else {
cells.length = 0 // Empty selection if ctrl is not pressed
cells.push(index)
activate_cell(Math.min(...cells), Math.max(...cells))
}
}
#grid {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(2, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
}
.active {
background-color: #80aaff;
}
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
답변
하나 또는 간격을 선택하십시오. 그러나 Ctrl 키를 누르고 세 번째를 클릭하면 이전 선택이 재설정되고 첫 번째 항목부터 새로 시작됩니다 (확장하기 어렵지 않음).
const grid = document.getElementById("grid")
var previousCell = [];
function toggle(event) {
event.stopPropagation();
var target = event.target;
if (target.className.indexOf('cell') > -1) {
var cells = target.parentElement.getElementsByClassName("cell");
if (event.ctrlKey || previousCell[0] == previousCell[1]) {
if (!event.ctrlKey) previousCell = [];
previousCell.push(target);
prepareRange(cells, previousCell);
switchRange(cells, previousCell);
previousCell = [target];
prepareRange(cells, previousCell);
}
document.getElementById("range").innerText = previousCell[0]+1;
}
}
function prepareRange(cells, previousCells) {
for(var i=0;i<cells.length;i++) {
var pos = previousCell.indexOf(cells[i]);
if (pos > -1 && previousCell.length < 4) {
previousCell.push(i);
}
}
if (previousCell.length == 2) {
previousCell[0] = previousCell[1];
} else {
previousCell[1] = previousCell.pop();
previousCell.pop();
previousCell.sort();
}
}
function switchRange(cells, previousCells) {
for(var i = previousCells[0];i <= previousCells[1]; i++) {
target = cells[i];
if (target.className.indexOf('active') > -1) {
target.className = 'cell';
} else {
target.className = 'cell active';
}
if (previousCell.length == 1) break;
}
}
#grid {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(2, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
}
.active {
background-color: #80aaff;
}
<div id="grid" onclick="toggle(event)">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
Last cell:<div id="range"></div>
답변
약간 수정하면 다음과 같이 할 수 있습니다.
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title></title>
<style>
#grid {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(2, 50px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
}
.active {
background-color: #80aaff;
}
</style>
<script>
document.addEventListener('DOMContentLoaded',e=>{
const grid = document.getElementById('grid')
const cells= grid.querySelectorAll('div');
grid.addEventListener('click',function(e){
e.stopPropagation();
cells.forEach( cell=>{
cell.classList.remove('active')
});
event.target.classList.add('active');
if( event.ctrlKey ) {
Array.from(cells).some( cell=>{
cell.classList.add('active')
if( cell==event.target )return true;
})
}
});
});
</script>
</head>
<body>
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
</body>
</html>
이 기능은 거꾸로 작동하지 않는다는 의견에 따라 원본을 약간 다시 해시하여 선택의 두 방향 모두에서 작동합니다. 편집 된 버전은 dataset
속성 을 사용 하며이 경우 정수로 할당됩니다. 레코드는 초기 셀 클릭을 유지하고 ctrl
키를 누르면 사용자가 앞뒤를 선택하는지 여부를 결정하기 위해 간단한 계산이 수행되어 사용 된 루프와 활성 클래스 할당에 영향을 미칩니다. 변수를 사용하여 CSS를 약간 조정하면 편의상 …
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title></title>
<style>
:root{
--rows:2;
--cols:3;
--size:50px;
}
#grid {
display:grid;
grid-template-columns:repeat(var(--cols),var(--size));
grid-template-rows:repeat(var(--rows),var(--size));
width:calc(var(--size) * var(--cols));
}
.cell {
display: flex;
flex:1;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
margin:1px;
cursor:pointer;
}
.active {
background-color: #80aaff;
}
</style>
<script>
document.addEventListener('DOMContentLoaded',e=>{
let range=[];
const grid = document.getElementById('grid')
const cells = grid.querySelectorAll('div');
const getcell=function(i){
return grid.querySelector('[data-index="'+i+'"]');
}
const clickhandler=function(e){
e.stopPropagation();
range.push( e.target );
/* clear cells of the "active" class */
cells.forEach( cell=>{
cell.classList.remove('active')
});
/* Assign the initially selected cell as "active" */
e.target.classList.add('active');
if( e.ctrlKey ) {
/* Is the user selecting forwards or backwards? */
if( range[0].dataset.index < e.target.dataset.index ){
for( let i=range[0].dataset.index; i < e.target.dataset.index; i++ )getcell(i).classList.add('active')
} else if( range[0].dataset.index == e.target.dataset.index ){
e.target.classList.add('active')
} else {
for( let i=range[0].dataset.index; i > e.target.dataset.index; i-- )getcell(i).classList.add('active')
}
range=[];
}
};
/* assign an integer index to each cell within parent */
cells.forEach( ( cell, index )=>{
cell.dataset.index = index + 1;
});
grid.addEventListener( 'click', clickhandler );
});
</script>
</head>
<body>
<div id="grid">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell">6</div>
</div>
</body>
</html>
![](http://daplus.net/wp-content/uploads/2023/04/coupang_part-e1630022808943-2.png)