#javascript #jquery
Как изменить значение input по клику на кнопки (+/-) и взять значение из имеющейся таблицы если комплектов кнопок и input на странице может быть несколько? $(function() { var countInputs = document.getElementsByClassName('count-buttons'); for (var input in countInputs) { if (!countInputs.hasOwnProperty(input)) { continue; } var butM = input.getElementsByClassName('btn-minus'); var butP = input.getElementsByClassName('btn-plus'); var units = countInput.value.replace(/\d/g, ''); butP.onclick = function() { countInput.value = parseInt(countInput.value) + 1 + units; }; butM.onclick = function() { if (parseInt(countInput.value) > 1) { countInput.value = parseInt(countInput.value) - 1 + units; } }; $(function() { document.querySelector('.count-buttons').onmouseover = (function() { document.querySelector('.count-buttons__table').style.display = 'table'; }); document.querySelector('.count-buttons__table').onmouseout = (function() { document.querySelector('.count-buttons__table').style.display = 'none'; }); var elems = document.querySelectorAll('.count-buttons__table-td'); for (var i = elems.length - 1; i >= 0; i--) { elems[i].addEventListener('click', myFunc, false); } function myFunc() { document.getElementsByClassName('qty').value = this.innerHTML; } });jsfiddle UPD Суть в том, что значения для value можно получить двумя способами: по нажатию кнопки + или - (соответственно, число либо увеличивается на 1 либо уменьшается) пример выбрать число из выпадающей таблицы (числа никогда не меняются) пример
Ответы
Ответ 1
Можно как-то так решить эту задачу. var Counter = function(counter) { // Сохраняем все, чтобы можно было использовать в методах // Счетчик this.counter = counter; // Ячейки таблицы this.cells = counter.querySelectorAll('.table__td'); this.cells = Array.prototype.slice.call(this.cells); // Кнопку «минус» this.minus = counter.querySelector('.counter__minus'); // Кнопку «плюс» this.plus = counter.querySelector('.counter__plus'); // Инпут this.field = counter.querySelector('.counter__input'); // Инициализируем события this.events(); } // Метод отвечающий за вызов слушателей Counter.prototype.events = function() { // Обработчик кнопки «плюс» this.plus.addEventListener('click', this.increment.bind(this)); // Обработчик кнопки «минус» this.minus.addEventListener('click', this.decrement.bind(this)); // Пробегаемся по ячейкам таблицы for(var cell in this.cells) { // и на каждый навешиваем обработчик this.cells[cell].addEventListener('click', this.changeFromTable.bind(this, this.cells[cell])); } } // Берет значение из ячейки и ставит его в инпут Counter.prototype.changeFromTable = function(cell) { this.field.value = cell.textContent; } // Метод увеличивает значение в поле на 1 Counter.prototype.increment = function() { this.field.value = parseInt(this.field.value) + 1; } // Метод уменьшает значение в поле на 1 Counter.prototype.decrement = function() { // Сохраняем новое значение в переменную var newValue = parseInt(this.field.value) - 1; // Если оно меньше нуля - делаем нулем if(newValue < 0) { newValue = 0; } // Меняем значение в инпуте this.field.value = newValue; } // Собираем список всех счетчиков на странице var counters = document.querySelectorAll('.counter'); // Превращаем в массив counters = Array.prototype.slice.call(counters); // Проблегаемся по счетчикам counters.forEach(function(counter) { // И инициализируем каждый new Counter(counter); }); .table { font-size: 0; margin-top: 5px; } .table__td { cursor: pointer; font: 14px sans-serif; display: inline-block; padding: 2px 5px; border-radius: 3px; border: 1px solid #ccc; } .table__td + .table__td { margin-left: 5px; } .table__td:hover { background-color: #f5f5f5; } hr { height: 1px; margin: 15px 0; background-color: #ccc; color: #ccc; border: none; }61218243036
Если непонятно что происходит, почему я использую this, prototype и new, то прочитайте главы «ООП в прототипном стиле» и «Методы объектов и контекст вызовов».61218243036Ответ 2
К сожалению, предложенный @dmitryshishkin ответ мне не подошел, т.к. возникала странная ошибка - при клике на кнопки +/- значение увеличивалось/уменьшалось сразу на два числа... В итоге, мне подошел этот код: counters = [].slice.call(document.querySelectorAll('.count-buttons')); counters.forEach(function(counter) { var input = counter.querySelector('.input-text'); counter.querySelector('.btn-minus').onclick = function () { var newValue = +input.value - 1; if (newValue >= 1) { input.value = newValue; } }; counter.querySelector('.btn-plus').onclick = function () { input.value = +input.value + 1; }; counter.querySelector('.count-buttons__table').onclick = function (evt) { input.value = evt.target.textContent; this.style.display = 'none'; } });Ответ 3
Задача не совсем ясна. Если хотите поле ввода с кнопками -/+ и всплывающими вариантами, то вот: var $d = document, cbsTable, callerEl; $d.addEventListener('DOMContentLoaded', () => { cbsTable = $d.createElement('table'); cbsTable.id = 'cbtn-table'; cbsTable.addEventListener('click', onTableClick); $d.body.appendChild(cbsTable); let cbs = $d.getElementsByClassName('cbtn-combobox'); for (let cb of cbs) { cb.addEventListener('click', onCbClick); cb.addEventListener('input', onCbInput); cb.addEventListener('blur', () => setTimeout(() => { if (!$d.activeElement.classList.contains('cbtn-combobox')) cbsTable.style.visibility = 'hidden'; }, 150)); cb.contentEditable = true; } console.log('Клик по значению вызывает всплывающую таблицу.'); }); function onCbInput(e) { let cPos = getCaretPosCe(this, true), newVal = +(this.textContent.match(/\d/g) || [0]).join(''); this.textContent = Math.min(99999, newVal); setCaretPosCe(this, cPos, true); } function onCbClick(e) { let cs = getComputedStyle(this), btnW = parseInt(cs.getPropertyValue('--btn-width')), mX = e.clientX - this.getBoundingClientRect().left, crrVal = parseInt(this.textContent) || 0, newVal = null; newVal = (mX < btnW) ? --crrVal : (mX > this.offsetWidth - btnW) ? ++crrVal : null; if (newVal !== null) { this.textContent = Math.min(99999, Math.max(0, newVal)); setCaretPosCe(this, 0, true); } callerEl = this; showPopupTable(); } function showPopupTable() { let tDataStr = callerEl.dataset.table; if (!tDataStr) return; cbsTable.innerHTML = ''; let row; tDataStr.split('|').forEach(rowStr => { row = cbsTable.insertRow(); rowStr.split(',').forEach(cellValue => { row.insertCell().textContent = cellValue; }); }); let bcr = callerEl.getBoundingClientRect(); cbsTable.style.top = (bcr.bottom + 2) + 'px'; cbsTable.style.left = bcr.left + (callerEl.offsetWidth - cbsTable.offsetWidth) / 2 + 'px'; cbsTable.style.visibility = 'visible'; } function onTableClick(e) { let clckd = e.target; if (clckd.tagName.toLowerCase() === 'td') callerEl.textContent = parseInt(clckd.textContent) || 0; } function getCaretPosCe(el, fromEnd = false) { let pos = 0, sel = window.getSelection(); if (sel.rangeCount) { let rng = sel.getRangeAt(0); if (rng.commonAncestorContainer.parentNode === el) { pos = !fromEnd ? rng.endOffset : el.textContent.length - rng.endOffset; } } return pos; } function setCaretPosCe(el, pos, fromEnd = false) { let sel = window.getSelection(), rng = document.createRange(); if (fromEnd) pos = Math.max(0, el.textContent.length - pos); else pos = Math.min(pos, el.textContent.length); rng.setStart(el.childNodes[0], pos); rng.collapse(true); sel.removeAllRanges(); sel.addRange(rng); } #container { display: flex; justify-content: space-around; margin: 25vh 10vw; } .cbtn-combobox, #cbtn-table td { background-color: #fff; font: 16px monospace; } .cbtn-combobox { --btn-width: 20px; width: calc(3ch + var(--btn-width) * 2 + 24px); display: inline-flex; line-height: 1.8em; text-align: center; border: 1px solid #ccc; } .cbtn-combobox:before, .cbtn-combobox:after { display: inline-block; flex: 0 0 var(--btn-width); background-color: #eee; cursor: pointer; visibility: hidden; } .cbtn-combobox:before { content: '-'; margin-right: auto; } .cbtn-combobox:after { content: '+'; margin-left: auto; } .cbtn-combobox:focus:before, .cbtn-combobox:focus:after, .cbtn-combobox:hover:before, .cbtn-combobox:hover:after { visibility: visible; } #cbtn-table { position: absolute; z-index: 99; border-collapse: collapse; background-color: #eee; box-shadow: 0 2px 5px 0 #0002; visibility: hidden; } #cbtn-table td { width: calc(3ch + 10px); line-height: 1.8em; text-align: center; border: 1px solid #ccc; }Плюс вариант, таблица из кастомных "input'ов": var $d = document; $d.addEventListener('DOMContentLoaded', () => { let tds = $d.getElementsByClassName('cbtn-table-td'); for (let td of tds) { td.addEventListener('click', onTdClick); td.addEventListener('input', onTdInput); td.contentEditable = true; } console.log('Кнопки показываются при наведении на ячейку') }); function onTdInput(e) { let cPos = getCaretPosCe(this, true), newVal = +(this.textContent.match(/\d/g) || [0]).join(''); this.textContent = Math.min(999, newVal); setCaretPosCe(this, cPos, true); } function onTdClick(e) { let cs = getComputedStyle(this), btnW = parseInt(cs.getPropertyValue('--btn-width')), mX = e.clientX - this.getBoundingClientRect().left, crrVal = parseInt(this.textContent) || 0, newVal = null; newVal = (mX < btnW) ? --crrVal : (mX > this.offsetWidth - btnW) ? ++crrVal : null; if (newVal !== null) { this.textContent = Math.max(0, newVal); setCaretPosCe(this, 0, true); } } function getCaretPosCe(el, fromEnd = false) { let pos = 0, sel = window.getSelection(); if (sel.rangeCount) { let rng = sel.getRangeAt(0); if (rng.commonAncestorContainer.parentNode === el) { pos = !fromEnd ? rng.endOffset : el.textContent.length - rng.endOffset; } } return pos; } function setCaretPosCe(el, pos, fromEnd = false) { let sel = window.getSelection(), rng = document.createRange(); if (fromEnd) pos = Math.max(0, el.textContent.length - pos); else pos = Math.min(pos, el.textContent.length); rng.setStart(el.childNodes[0], pos); rng.collapse(true); sel.removeAllRanges(); sel.addRange(rng); } .cbtn-table { --btn-width: 20px; --td-width: calc(3ch + var(--btn-width) * 2 + 8px); font: 16px monospace; } .cbtn-table-tr, .cbtn-table-td { margin: 0; padding: 0; } .cbtn-table-tr { display: flex; line-height: 1.8em; padding: 0; margin-top: -1px; white-space: nowrap; } .cbtn-table-td:first-child { margin: 0; } .cbtn-table-td { display: inline-flex; min-width: var(--td-width); margin-left: -1px; text-align: center; border: 1px solid #ccc; } .cbtn-table-td:first-child { margin: 0; } .cbtn-table-td:before, .cbtn-table-td:after { display: inline-block; flex: 0 0 var(--btn-width); cursor: pointer; visibility: hidden; } .cbtn-table-td:before { content: '-'; margin-right: auto; } .cbtn-table-td:after { content: '+'; margin-left: auto; } .cbtn-table-td:hover:before, .cbtn-table-td:hover:after { visibility: visible; background-color: #ddd; }421231Код далеко не кроссбраузерный, это только примеры.621218243036
Комментариев нет:
Отправить комментарий