Я ищу способ автоматически подсчитывать указанные слова в текстовом поле, не нажимая для этого кнопку, и в этом случае автоматически обновлять его, если есть изменения.
Вот мой хаотичный код:
function findWord1() {
var outputDiv = $('#opening-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){ }\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a>');
}
function findWord2() {
var outputDiv = $('#closing-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord3() {
var outputDiv = $('#opening-added-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[A>";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord4() {
var outputDiv = $('#closing-added-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "lt;A]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord5() {
var outputDiv = $('#opening-deleted-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[D>";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord6() {
var outputDiv = $('#closing-deleted-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "lt;D]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<button onclick = "findWord1();findWord2();findWord3();findWord4();findWord5();findWord6();">Count</button>
<table>
<thead>
<tr>
<th scope = "col">Items</th>
<th scope = "col">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>[A></td>
<td><a id = "opening-added-bracket"></a></td>
</tr>
<tr>
<td><A]</td>
<td><a id = "closing-added-bracket"></a></td>
</tr>
<tr>
<td>[D></td>
<td><a id = "opening-deleted-bracket"></a></td>
</tr>
<tr>
<td><D]</td>
<td><a id = "closing-deleted-bracket"></a></td>
</tr>
<tr>
<td>[</td>
<td><a id = "opening-bracket"></a></td>
</tr>
<tr>
<td>]</td>
<td><a id = "closing-bracket"></a></td>
</tr>
</tbody>
</table>
<textarea id = "textarea3" rows = "5">
[A>
lt;A]
[D>
lt;D]
</textarea>
Также, если возможно, я хотел бы сохранить кнопку «Подсчет», чтобы я мог сделать это вручную в случае сбоя других частей кода.
Извините, если мой код выглядит так плохо, но заранее спасибо за любую помощь.
Спасибо за ваш отзыв, это один из моих планов объединить их все под одной функцией, я просто еще не придумал, как я это сделаю..
Необходимо исправить значения wordMatch
findWord4
и findWord6
, а также соответствующие значения текстовой области... <A]
/<D]
вместо текущего lt;A]
/lt;D]
.
Используйте keyup
Просто сделайте так
function countWordFunc() {
let myText = document.getElementById("myText").value;
let wordsArr = myText.trim().split(" ")
let countWords = wordsArr.filter(word => word !== "").length
let counter = document.getElementById("counter");
counter.innerHTML = `Total Words: ${countWords}`;
}
<textarea onkeyup = "countWordFunc()" id = "myText">Hello, World</textarea>
<div id = "counter"></div>
@GMKHussain ... рассмотрите возможность удаления этого ответа, поскольку он полностью упускает из виду всю проблему и не соответствует ни одному из требований ОП.
Создайте функцию для вызова всех остальных. Это шаг к упрощению вашего кода. Затем создайте прослушиватель событий для события input
текстовой области с новой функцией в качестве обратного вызова.
Этот вопрос, по сути, дублирует многие другие вопросы, связанные с событиями. См. https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events для получения полезной информации и ищите дополнительные ответы здесь, если у вас есть дополнительные вопросы.
function findAllWords() {
findWord1();
findWord2();
findWord3();
findWord4();
findWord5();
findWord6();
}
document.getElementById('textarea3').addEventListener('input', findAllWords);
function findWord1() {
var outputDiv = $('#opening-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){ }\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a>');
}
function findWord2() {
var outputDiv = $('#closing-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord3() {
var outputDiv = $('#opening-added-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[A>";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord4() {
var outputDiv = $('#closing-added-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "lt;A]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord5() {
var outputDiv = $('#opening-deleted-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "[D>";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
function findWord6() {
var outputDiv = $('#closing-deleted-bracket');
var searchText = $('#textarea3').val();
var wordMatch = "lt;D]";
outputDiv.empty();
var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<table>
<thead>
<tr>
<th scope = "col">Items</th>
<th scope = "col">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>[A></td>
<td>
<a id = "opening-added-bracket"></a>
</td>
</tr>
<tr>
<td><A]</td>
<td>
<a id = "closing-added-bracket"></a>
</td>
</tr>
<tr>
<td>[D></td>
<td>
<a id = "opening-deleted-bracket"></a>
</td>
</tr>
<tr>
<td><D]</td>
<td>
<a id = "closing-deleted-bracket"></a>
</td>
</tr>
<tr>
<td>[</td>
<td>
<a id = "opening-bracket"></a>
</td>
</tr>
<tr>
<td>]</td>
<td>
<a id = "closing-bracket"></a>
</td>
</tr>
</tbody>
</table>
<textarea id = "textarea3" rows = "5">
[A>
lt;A]
[D>
lt;D]
</textarea>
Большое спасибо, что нашли время ответить на мой запрос. Это решение именно то, что мне нужно прямо сейчас. Только один вопрос, поскольку я еще не пробовал, я предполагаю, что все еще можно использовать основную функцию findAllWords()
для создания кнопки, которая может вручную считать слова? (Это нужно, чтобы сценарий, который у меня есть, программно обновлял текст, и я предполагаю, что он не будет обновлять счетчик после изменения текста).
Конечно, но используйте прослушиватель событий и для кнопки. Держите свой JavaScript подальше от вашего HTML.
Попробуйте это, объединив функции в одну:
let textarea = $('#textarea3');
textarea.on('keyup', _ => counting());
function counting() {
var searchText = $('#textarea3').val();
let words = [];
words['[A>'] = '#opening-added-bracket';
words['<A]'] = '#closing-added-bracket';
words['[D>'] = '#opening-deleted-bracket';
words['<D]'] = '#closing-deleted-bracket';
words['['] = '#opening-bracket';
words[']'] = '#closing-bracket';
for (const word in words) {
var outputDiv = $(words[word]);
outputDiv.empty();
let count = searchText.split(word).length - 1;
searchText = searchText.replaceAll(word,'');
outputDiv.append('<a>' + count + '</a>');
}
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onclick = "counting();">Count</button>
<table>
<thead>
<tr>
<th scope = "col">Items</th>
<th scope = "col">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td>[A></td>
<td><a id = "opening-added-bracket"></a></td>
</tr>
<tr>
<td><A]</td>
<td><a id = "closing-added-bracket"></a></td>
</tr>
<tr>
<td>[D></td>
<td><a id = "opening-deleted-bracket"></a></td>
</tr>
<tr>
<td><D]</td>
<td><a id = "closing-deleted-bracket"></a></td>
</tr>
<tr>
<td>[</td>
<td><a id = "opening-bracket"></a></td>
</tr>
<tr>
<td>]</td>
<td><a id = "closing-bracket"></a></td>
</tr>
</tbody>
</table>
<textarea id = "textarea3" rows = "5">
[A>
<A]
[D>
<D]
</textarea>
В приведенной выше реализации массив words
используется как своего рода объектная карта. Можно рассмотреть возможность его изменения соответственно, например. let words = {};
@ixcode ... еще хуже <A]
и <D]
вообще не учитываются. Вместо этого количество ]
обновляется неправильно... и то же самое относится к [A>
и [D>
, которые оба неправильно влияют на количество [
... что фактически делает весь подход бесполезным.
Есть следующие проблемы с кодом OP...
код, основанный на конкретном элемент id
s, никогда не может быть преобразован во что-то достаточно общее с точки зрения повторно используемого кода.
подсчет одиночных скобок опасен, особенно потому, что они являются частью других совпадающих последовательностей символов (которые OP называет словами).
Таким образом, можно было бы рассмотреть как можно более настраиваемый и общий, компонентный подход для бедняков, аналогичный следующему приведенному примеру кода, где...
один напр. можно настроить совпадающие элементы с помощью шаблонов регулярных выражений.
кроме того, можно настроить поведение UI/UX компонента, например автоматический подсчет.
каждая конфигурация основана на data-*
атрибуты и его аналоге HTMLElement. набор данных.
из-за вышеприведенного третьего пункта компонент не зависит от своей разметки, пока необходимые атрибуты data-*
предоставляются правильно.
Подход также можно резюмировать, как в одном из моих комментариев...
"Initialize a component like structure by reading and computing the config settings, and upon the latter register the count handler with the correct events. The count handler itself then is a straightforward regex based pattern matching (which also works correctly unlike all the other solutions) and count rendering task. Element IDs are not needed, markup is freely selectable, configurations are applied via markup and data attributes. One does not need to touch JS code in order to introduce more to be matched items/words."
function displayItemCount(itemRoot, target) {
const elmPattern =
target && itemRoot?.querySelector('[data-reg-pattern]');
const elmCount =
elmPattern && itemRoot?.querySelector('[data-match-count]');
const regXItem =
elmCount && RegExp(elmPattern.dataset.regPattern, 'g');
if (regXItem) {
elmCount.textContent = (target.value.match(regXItem) ?? []).length;
}
}
function displayItemCountsOfBoundComponentData() {
const { rootNode, countsTarget } = this;
rootNode
.querySelectorAll('[data-item-match]')
.forEach(itemRoot =>
displayItemCount(itemRoot, countsTarget)
);
}
function initializeItemCountsComponent(rootNode) {
const { dataset } = rootNode;
let {
countsTargetSelector = '',
triggerCountsSelector = '',
autoCount = false,
} = dataset;
countsTargetSelector = countsTargetSelector.trim();
triggerCountsSelector = triggerCountsSelector.trim();
const countsTarget = (
rootNode.querySelector(countsTargetSelector || null) ||
document.querySelector(countsTargetSelector || null)
);
if (countsTarget) {
let countsTriggers = rootNode
.querySelectorAll(triggerCountsSelector || null);
if (countsTriggers.length === 0) {
countsTriggers = document
.querySelectorAll(triggerCountsSelector || null);
}
const isAutoCount = (
(countsTriggers.length === 0) || (
(autoCount !== false) && (
(autoCount.trim() === '') ||
(autoCount.trim().toLowerCase() === 'true')
)
)
);
const displayItemCounts =
displayItemCountsOfBoundComponentData.bind({
rootNode,
countsTarget,
});
countsTriggers.forEach(elmNode =>
elmNode
.addEventListener('click', displayItemCounts)
);
if (isAutoCount) {
countsTarget
.addEventListener('input', displayItemCounts);
// trigger component's initial item counts.
displayItemCounts();
}
}
}
function main() {
document
.querySelectorAll('[data-item-counts]')
.forEach(initializeItemCountsComponent);
}
main();
body { margin: 0; }
article { position: relative; display: inline-block; margin: 0 20px 0 0; }
[data-item-counts] { float: left; margin: 0 10px 0 0; }
textarea { margin: 0; }
button { position: absolute; left: 0; top: 175px; }
<article>
<table
data-item-counts
data-counts-target-selector = "#textarea3"
data-trigger-counts-selector = "#count-textarea3-items"
>
<thead>
<tr>
<th scope = "col">Items</th>
<th scope = "col">Count</th>
</tr>
</thead>
<tbody>
<tr data-item-match>
<td data-reg-pattern = "\[A>" title = "Opening Added Bracket">[A></td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "<A]" title = "Closing Added Bracket"><A]</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "\[D>" title = "Opening Deleted Bracket">[D></td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "<D]" title = "Closing Deleted Bracket"><D]</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "\[(?!A|D)" title = "Opening Bracket">[</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "(?<!<A|D)]" title = "Closing Bracket">]</td>
<td data-match-count>.?.</td>
</tr>
</tbody>
</table>
<textarea
id = "textarea3"
cols = "16"
rows = "12">
[A><A][D><D][[]][]<A][D>
[A><A][D><D][[]][]<A][D>
... explicitly triggered count.</textarea>
<button id = "count-textarea3-items">Count Items</button>
</article>
<article>
<table
data-item-counts
data-counts-target-selector = "#textarea54"
data-auto-count
>
<thead>
<tr>
<th scope = "col">Items</th>
<th scope = "col">Count</th>
</tr>
</thead>
<tbody>
<tr data-item-match>
<td data-reg-pattern = "\[A>" title = "Opening Added Bracket">[A></td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "<A]" title = "Closing Added Bracket"><A]</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "\[D>" title = "Opening Deleted Bracket">[D></td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "<D]" title = "Closing Deleted Bracket"><D]</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "\[(?!A|D)" title = "Opening Bracket">[</td>
<td data-match-count>.?.</td>
</tr>
<tr data-item-match>
<td data-reg-pattern = "(?<!<A|D)]" title = "Closing Bracket">]</td>
<td data-match-count>.?.</td>
</tr>
</tbody>
</table>
<textarea
id = "textarea54"
cols = "16"
rows = "12"
>[[]][]<A][D>[A><A][D><D]
... auto-count while editing.</textarea>
</article>
Этот вопрос очень прост и не заслуживает таких сложностей.
@YounesBennour ... В приведенном выше подходе нет ничего сложного. Инициализируйте структуру, подобную компоненту, прочитав и вычислив настройки конфигурации, а затем зарегистрируйте обработчик счетчика с правильными событиями. Тогда сам обработчик count представляет собой простое сопоставление шаблонов на основе регулярных выражений (которое также работает правильно, в отличие от всех других решений) и задачу рендеринга count. Идентификаторы элементов не нужны, разметка выбирается свободно, конфигурации применяются через разметку и атрибуты данных. Не нужно трогать JS-код, чтобы ввести больше совпадающих элементов/слов.
Там куча повторений. Вероятно, вам следует создать одну повторно используемую функцию и передать свою строку в качестве аргумента или перебрать массив из них. Кроме того, вам не нужны отдельные элементы скрипта для каждой функции.