Удаление добавление классов

Как сделать что бы при зажатой мышки выделялись элементы и так-же только при зажатой становились прежними?

То есть при зажатой мышки добавлялся класс и так-же при зажатой удалялся?

let but = document.querySelectorAll('.but');

const handler = e =>
  e.buttons === 1 && e.target.classList.contains('but')
  ? e.target.classList.add('active')
  : e.target.classList.remove('active');


for (let i = 0; i < but.length; i++) {
  but[i].addEventListener('mousedown', handler);
  but[i].addEventListener('mousemove', handler);
}
.but {
  display: inline-block;
  background: mediumvioletred;
  padding: 3px;
  width: 18px;
  text-align: center;
  cursor: pointer;
}

.active {
  background: black;
  color: white;
}
<div class="but">1</div>
<div class="but">2</div>
<div class="but">3</div>
<div class="but">4</div>


Ответы (2 шт):

Автор решения: Денис Степанов

Работает криво-косо, но все равно.

let isMouseDown = false;
let mouseDownTarget = null;

document.body.onmousedown = function(e) {
  mouseDownTarget = e.target;
  mouseDownTarget.closest(".block") && mouseDownTarget.closest(".block").classList.toggle('active');
  
  
  isMouseDown = e.button === 0;
}

document.body.onmouseup = function(e) {
  isMouseDown = e.button === 0 ? false : isMouseDown;
}

document.querySelector('.block-container').addEventListener('click', (e) => {
  isMouseDown && 
      e.target.closest(".block") &&
      e.target.closest(".block") !== mouseDownTarget.closest(".block") &&
      e.target.closest(".block").classList.toggle('active');
});

document.querySelector('.block-container').addEventListener('mouseover', (e) => {
  isMouseDown && e.target.closest(".block") && e.target.closest(".block").classList.toggle('active');
})
body {
  height: 100vh;
}

.block-container {
  display: flex;
  
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -o-user-select: none;
  user-select: none;
}

.block {
  width: 40px;
  height: 40px;
  background: #122;
  border: 2px solid #122;
}

.active {
  background-color: tomato;
}
<div class="block-container"><div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  </div>

→ Ссылка
Автор решения: qwabra

.btn {
  display: inline-block;
  background: mediumvioletred;
  padding: 3px;
  width: 18px;
  text-align: center;
  cursor: pointer;
  user-select: none;
}

.active {
  background: black;
  color: white;
}
<script type="module">

import { html, render } from 'https://unpkg.com/lit-html?module';

const length = 4;

test(elList => {
    elList.forEach(el => el.addEventListener('mousedown', e => {
        el.classList.toggle('active');
    }));
});

test(elList => {
    elList.forEach(el => el.addEventListener('mousedown', ({ altKey }) => {
        if (altKey)
            el.classList.toggle('active');
    }));
});

test(elList => {
    elList.forEach(el => el.addEventListener('mouseenter', () => {
        const q = ({ code }) => {
            // console.log({ code })
            if ('KeyS' === code)
                el.classList.add('active');
            if ('KeyD' === code)
                el.classList.remove('active');
        };
        window.addEventListener('keydown', q);
        el.addEventListener('mouseleave', () => {
            window.removeEventListener('keydown', q);
        });
    }));
});


// --------------------------------------------------------

function btn(q) { return html `<div class="btn">${q}</div>`; }
function genBtnList() { return Array.from({ length }, (_, i) => btn(i)); }

function genRoot() {
    const root = document.body.appendChild(document.createElement('div'));
    render(html `${genBtnList()}<hr>`, root);
    return root;
}
function test(f) {
    const root = genRoot();
    const elList = Array.from(root.getElementsByClassName('btn'));
    f(elList);
}

</script>

→ Ссылка