Как визуализировать различное текстовое содержимое в зависимости от состояния переключения, инициируемого событием нажатия кнопки элемента?

#javascript #event-handling #state #togglebutton

Вопрос:

У меня есть кнопка, которая при нажатии изменяет текст с «Сообщить о проблеме» на «Закрыть» и открывает выпадающий текстовый ввод, Когда кнопка нажата снова, она остается в положении «Закрыть», в то время как я хотел бы, чтобы она вернулась к «Сообщить о проблеме». Я знаю только, как вызвать 2 события одним щелчком мыши, в то время как это было бы действие в два клика. Есть какие-нибудь идеи о том, как лучше всего подойти к этому?

 function change() {
  document.getElementById("myBtnToReportABug").innerHTML = "Close";
} 
 <button id="myBtnToReportABug" onclick="change()" type="button" class="btn btn-secondary float-right" data-toggle="myModal" data-target="#myModal"> Report A Problem </button> 

Комментарии:

1. Компонент, подобный кнопке, который переключает текст, может быть реализован без JavaScript с помощью контента, сгенерированного css, и data-* атрибутов флажка, таким образом, не зависит от библиотек на стороне клиента для локализации (l10n) / интернационализации (i18n).

Ответ №1:

Я бы использовал другой атрибут данных для отслеживания состояния переключения, например, в data-button-state качестве нового атрибута:

 function change() {
    var button = document.getElementById("myBtnToReportABug");
    var buttonState = button.dataset.buttonState;
    var buttonText;
    var buttonState;

    if (buttonState === 'report') {
        buttonText = "Close";
        buttonState = "close";
    } else {
        buttonText = "Report A Problem";
        buttonState = "report"
    }

    button.innerHTML = buttonText;
    button.dataset.buttonState = buttonState;
} 
 <button
    id="myBtnToReportABug"
    onclick="change()"
    type="button"
    class="btn btn-secondary float-right"
    data-toggle="myModal"
    data-target="#myModal"
    data-button-state="report"
>
        Report A Problem
</button> 

При таком подходе у вас может быть несколько состояний, и просто определите, что вы хотите делать с этими состояниями в каждом if утверждении 🙂

Комментарии:

1. @cdln … Это жизнеспособная реализация сценария переключения на стороне клиента. Вы можете считать это принятым ответом.

Ответ №2:

Самое большое преимущество следующего подхода заключается в том, что интернационализация и локализация не зависят от отрисовки JavaScript на стороне клиента.

Поскольку флажок идеально подходит для представления состояния переключения, такой зависящий от состояния текст переключения просто необходимо преобразовать в два data-* атрибута элемента checkbox управления, которые вместе с внешним label элементом имитируют поведение кнопки переключения.

Все, что нужно, — это просто HTML и CSS.

И запуск скрипта на стороне клиента, который отвечает за открытие и закрытие модала, на этом небольшом компоненте вообще не должен быть проблемой …

 [data-modal-checkbox-button] {
  /* appearance: button; */
  display: inline-block;
  position: relative;
  min-width: 1em;
  padding: 4px;
  text-align: center;
  white-space: nowrap;
  background: #ccc;
  border: 2px solid;
  border-radius: 4px;
  border-style: outset;
}
[data-modal-checkbox-button]:active {
  border-style: inset;
}
[data-modal-checkbox-button] > [type="checkbox"]:focus {
  outline-offset: 8px;
  outline-color: darkorange;
}
[data-modal-checkbox-button]:active > [type="checkbox"] {
  left: -1px;
  top: -1px;  
}

[data-modal-checkbox-button] > [type="checkbox"] {
  appearance: none;
  display: inline-block;
  position: relative;
}
[data-modal-checkbox-button] > [type="checkbox"]::after {
  content: attr(data-checked-false);
}
[data-modal-checkbox-button] > [type="checkbox"]:checked::after {
  content: attr(data-checked-true);
} 
 <label data-modal-checkbox-button>
  <input
    name="report-a-bug"

    type="checkbox"
    class="btn btn-secondary"

    data-toggle="myModal"
    data-target="#myModal"

    data-checked-true="Close"
    data-checked-false="Report A Problem"
  />
</label><br/>

<label data-modal-checkbox-button>
  <input
    name="report-a-bug"

    type="checkbox"
    class="btn btn-secondary"

    data-toggle="myModal"
    data-target="#myModal"

    data-checked-true="Schließen"
    data-checked-false="Ein Problem melden"
  />
</label><br/>

<label data-modal-checkbox-button>
  <input
    name="report-a-bug"

    type="checkbox"
    class="btn btn-secondary"

    data-toggle="myModal"
    data-target="#myModal"

    data-checked-true="закрывание"
    data-checked-false="Сообщить о проблеме"
  />
</label> 

В случае, если оператору придется полагаться на подход к написанию сценариев, он может рассмотреть следующее универсальное и независимое от языка решение …

 function toggleModalButtonState({ currentTarget }) {
  const { dataset } = currentTarget;
  const { textClose, textReport } = dataset;

  const state = (dataset.state === 'close')
    ? 'report'
    : 'close';
    
  dataset.state = state;

  currentTarget.textContent = ({
    report: textReport,
    close: textClose,
  })[state];
}
document
  .querySelector('#myBtnToReportABug')
  .addEventListener('click', toggleModalButtonState); 
 <button
  id="myBtnToReportABug"

  type="button"
  class="btn btn-secondary float-right"

  data-toggle="myModal"
  data-target="#myModal"

  data-state="report"
  data-text-close="Close"
  data-text-report="Report A Problem"

>Report A Problem</button> 

Ответ №3:

Просто проверьте текущее значение:

 <button id="myBtnToReportABug" onclick="change()" type="button" class="btn btn-secondary float-right" data-toggle="myModal" data-target="#myModal"> Report A Problem </button>
function change() {
      var theButton = document.getElementById("myBtnToReportABug");
      if (theButton.innerHTML == "Close")
          theButton.innerHTML = "Report A Problem";
      else
          theButton.innerHTML = "Close";
}
 

Комментарии:

1. @cdln … 1/2 … Как это может быть принято/поддержано? Это, безусловно, наихудший из возможных подходов. Почему я делаю такое смелое / не очень вежливое заявление? Этот скрипт проверяет наличие определенного содержимого. Сверху он использует innerHTML для рендеринга a textContent . Действительно? Что произойдет, если в результате процесса рендеринга в этом текстовом содержимом появятся дополнительные начальные или конечные пробелы? Как насчет опечатки из-за человеческой ошибки в CMS. Даже если вы все это контролируете, как только кто-то решит переодеться Report A Problem в Report a problem вас вручную, нужно будет адаптировать сценарий. …

2. @cdln … 2/2 … И я уже упоминал i18n/l10n? Решение для создания сценариев на стороне клиента должно основываться на общем подходе к управлению состоянием переключения. Можно выбрать data-* атрибут или, может быть, даже имя класса (последнее я лично не предпочитаю, так как имена классов тоже могут меняться).

3. Ты прав, это очень грязно. Спасибо вам за комментарий! Это было очень информативно для меня (но есть более вежливые способы сказать мне об этом 😉 )

4. Я критиковал не вас, а ОП за то, что вы приняли этот ответ. Кроме того, это была критика в адрес любого, кто высказался против этого решения без критического мышления. Конечно, это была критика самого подхода. Было достаточно вежливо вообще не упоминать о тебе. Я никогда не нападаю на людей на личном уровне.

5. @PeterSeliger Хотя я ценю и извлек уроки из того, что вы написали, возможно, вам было бы полезно понять, что не все знают о наилучшей практике/способах, которыми нужно заниматься. Поэтому я вижу, что код работает, я принимаю его. Если только вы не считаете, что StackOverflow населен исключительно людьми, которые уже знают лучший ответ на то, что они спрашивают?

Ответ №4:

Я бы использовал атрибут данных для поддержания состояния кнопки.

Вы также должны использовать addEventListener вместо атрибута onclick.

 const report_btn = document.getElementById('myBtnToReportABug');

report_btn.addEventListener('click', function(){
  var btn_state = this.getAttribute('data-state');
  switch(btn_state){
    case "report":
    
      // The button is in the "report" state
      this.innerHTML = "Close";
    
      // Change the button state
      this.setAttribute('data-state', 'close')
      
      // do other stuff here...
      
      break;
    case "close":
    
      // The button is in the "close" state
      this.innerHTML = " Report A Problem ";
    
      // Change the button state
      this.setAttribute('data-state', 'report')
    
      // do other stuff here..
    
      break;
  }
}); 
 <button id="myBtnToReportABug" data-state='report' type="button" class="btn btn-secondary float-right" data-toggle="myModal" data-target="#myModal"> Report A Problem </button> 

Комментарии:

1. @cdln … Это тоже жизнеспособная реализация сценария переключения на стороне клиента.

Ответ №5:

Вам просто нужно добавить в свою функцию условие, которое проверяет, что textContent это такое, и соответствующим образом изменить его.

(Примечание: встроенный JS в наши дни обычно не одобряется, поэтому я использовал addEventListener здесь.)

 // Cache the button element and add a listener to it
const button = document.getElementById('myBtnToReportABug');
button.addEventListener('click', handleClick, false);

function handleClick() {

  // Depending on the textContent of the button
  // switch between the two texts
  if (button.textContent === 'Close') {
    button.textContent = 'Report a problem';
  } else {
    button.textContent = 'Close';
  }
} 
 <button id="myBtnToReportABug">Report A Problem</button> 

Ответ №6:

Вы имеете в виду, что кнопка должна изменить состояние, а не событие! Событие всегда одно и то же… тот самый онклик!

Поэтому вам просто нужно циклически просматривать счетчик переменных при каждом щелчке, вот так…

  if(State==3){State=1;} else {State   ;}
 

И затем…

  if(State==1) {RunFunction1();} else 

  if(State==2) {RunFunction2();} else 

   if(State==3) {RunFunction3();}
 

Изменение текста кнопки будет происходить внутри каждой пронумерованной функции выше, а также всего, что вы намеревались сделать для каждого состояния.