Ctrl + tıklama ile birden çok hücre nasıl seçilir


16

Numaraları olan bir tablo var. Tablodaki bir hücreye tıkladığımda, etkin durumu değiştirir. Bir hücre seçmek ve crtl tuşuna basıp başka bir hücre seçmek istiyorum ve ilk ve ikinci arasındaki sonuç hücreleri aktif hale gelecek. Nasıl uygulanır?

codepen 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';
    }  
  }
}

Vardiya vurgulama gibi çalışmalı ve her iki yönde de çalışmalıdır


10
Bu işlev normalde shift tuşuyla yapılmıyor mu?
Wimanicesir

dan, döngü tarafından aktif lastclicketmek thisclickve aynı zamanda kontrol ctrltıklama
Antony Jack

Çok fazla belirsiz durum var - belirli bir hücre aralığını veya hala hücre aralığını değiştirmek istiyor musunuz, aralık gibi kaydırma benzeri bir vurgulama (/ geçiş) yapmak veya tek bir hücre vb. Seçmek istiyor musunuz. ..
Tom

1
@Wimanicesir Shift genellikle başlangıç ​​ve akım arasındaki aralığı seçerken ctrl seçime ekler
Emanuel Vintilă

1
@ EmanuelVintilă Ama soru "birinci ve ikinci arasındaki hücreler", ki bu da Shift tuşunun beklenen davranışıdır.
John Montgomery

Yanıtlar:


11

Bunu dene:

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>

codepen


6

Javascript bölümünü c senden tamamen farklı programladım . Umarım hala kullanabilirsin. Ama tam olarak istediğini yapıyor.

Shift + Cell ile aradaki tüm hücreleri seçebilirsiniz.

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>

iyi şanslar ;)


rağmen OP ne istediğini değil ama denemek için güzel! +1
Ma'moun othman

@ Ma'mounothman ... ama shift tuşuna bastığınızda ilk ve ikinci tıklama arasındaki tüm hücrelerin işaretlenmesini istiyor ... ve bu benim çözümümle böyle çalışıyor. ya da ne istiyor ??
SwissCodeMen

üzgünüm bu şekilde ifade etmedi, bir şey çözümünüzün seçilen hücreleri ayrı ayrı seçecek, ancak tamam olup olmadığından emin değilim, çözümünüzün yine de çalışması dışında, kontrol edilmesi gereken tek şey bu!
Ma'moun othman

5

kullanılması previousElementSiblingvecompareDocumentPosition()

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;
};

Çalışma Demosu

https://codepen.io/aswinkumar863/pen/QWbVVNG


Tersine çalışmaz, örneğin 6'yı seçin ve ctrl + 2'yi seçin
Anurag Srivastava

@AnuragSrivastava düzeltildi
Kullanıcı863

4

İleri ve geri işlevselliği ile komple çözüm:

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>


4

Seçilen öğenin dizinini saklayarak oluşturdum. Her iki şekilde (2 -> 6) ve (6-> 2) çalışır

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>


4

Bir veya aralık seçin, ancak Ctrl tuşuna basıp 3. kez tıklatırsanız önceki seçim sıfırlanır ve 1. öğeden yeni başlar (uzatmak çok zor değildir).

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>


4

Hafif bir değişiklikle bunu şöyle yapabilirsiniz:

<!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>

Bu geriye doğru çalışma ile ilgili yorumdan sonra orijinal her iki yönde çalışır böylece biraz yeniden hashed. Düzenlenen sürüm datasetnitelikleri kullanır - bu durumda tamsayı olarak atanır. İlk hücrenin tıklandığı bir kayıt tutulur ve ctrltuşa basıldığında, kullanıcının ileri veya geri seçip seçmediğini belirlemek için basit bir hesaplama yapılır - bu da kullanılan döngüyü ve dolayısıyla etkin sınıfın atanmasını etkiler. Değişkenleri kullanarak CSS'de küçük bir değişiklik sadece rahatlık içindi ...

<!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>


Tersine çalışmaz, örneğin 6'yı seçin ve ctrl + 2'yi seçin
Anurag Srivastava

bunun gerekli olduğunu bilmiyordu
RamRaider

Pekala, kim amirite için tam bir çözüme ihtiyaç duyar? :)
Anurag Srivastava

1
seni neden ilgilendiriyor? Benim kontrolümün ötesinde bir şey gönderdikten sonra ne olur ve tamamen yukarı veya aşağı giderse tamamen diğer kullanıcılara iner ... benim adıma bazı jiggery pokery önermek sürece bu durumda farklı.
RamRaider

3

Jquery'ye açıksanız, işte bir çözüm. Ters seçimde çalışmadığını unutmayın

$(() => {
  $(".cell").on("click", function(e) {
    $(this).toggleClass("active")
    if (e.ctrlKey) {
      $(this).prevUntil(".active").addClass("active")
    }
  })
})
#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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.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>


bu da tam tersi değil
RamRaider

Cevabım açıkça belirtiyor
Anurag Srivastava
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.