Задать вопрос
  • Как скрыть блок при повторном нажатии на javascript?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Как заставить работать по-быстрому:
    function navFunction(id) {
      for (const n of document.querySelectorAll('.dropdown2-content')) {
        n.classList[n.id === id ? 'toggle' : 'remove']('show');
      }
    }

    Но вообще, тут многое можно изменить:

    Разметка - вырезать инлайновые обработчики клика и атрибуты id.

    Стили - будем плясать от корневых элементов (так удобнее; кроме того, если в будущем захотите стилизовать в "открытом" дропдауне что-то кроме контента, то не будет необходимости добавлять этим элементам классы, и, соответственно, не придётся переписывать код):

    .dropdown2 .dropdown2-content {
      display: none;
    }
    
    .dropdown2.show .dropdown2-content {
      display: block;
    }

    Код - вместо id будет смотреть на взаимное расположение элементов (переключаем класс у предка нажатой кнопки, у остальных удаляем):

    const containerSelector = '.dropdown2';
    const buttonSelector = `${containerSelector} .dropbtn2`;
    const activeClass = 'show';
    
    
    // делегирование, назначаем обработчик клика один раз для всех кнопок
    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        document.querySelectorAll(containerSelector).forEach(function(n) {
          n.classList[n === this ? 'toggle' : 'remove'](activeClass);
        }, button.closest(containerSelector));
      }
    });
    
    // или, назначаем обработчик клика каждой кнопке индивидуально
    const onClick = function({ currentTarget: t }) {
      this.forEach((n, i) => n.classList[n.contains(t) ? 'toggle' : 'remove'](activeClass));
    }.bind(document.querySelectorAll(containerSelector));
    
    document.querySelectorAll(buttonSelector).forEach(n => {
      n.addEventListener('click', onClick);
    });
    Ответ написан
    Комментировать
  • Как создать группу радио кнопок?

    0xD34F
    @0xD34F Куратор тега React
    const RadioGroup = props => (
      <div>
        {props.items.map(n => (
          <label className={`radio ${n.val == props.value ? 'selected' : ''}`}>
            <input 
              type="radio"
              name={props.name}
              value={n.val}
              checked={n.val === props.value}
              onChange={props.onChange}
            />
            <img src={n.img} />
          </label>
        ))}
      </div>
    );

    https://jsfiddle.net/jt2ybfrq/
    Ответ написан
  • Почему на другой странице снова хочет пароль?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Потому что в sessionStorage хранятся строки. Т.е., реально сравниваются "true" и true.
    Ответ написан
    1 комментарий
  • Как сократить код используя цикл?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const inputSelector = '#icons_care';
    const checkboxSelector = '.check_care';
    const checkboxCheckedSelector = `${checkboxSelector}:checked`;
    const dataAttr = 'icon';
    const separator = ', ';

    $(document).on('change', checkboxSelector, () => {
      $(inputSelector).val($(checkboxCheckedSelector)
        .get()
        .map(n => $(n).data(dataAttr))
        .join(separator)
      );
    });
    
    // или
    
    document.addEventListener('change', e => {
      if (e.target.matches(checkboxSelector)) {
        const input = document.querySelector(inputSelector);
        const cb = document.querySelectorAll(checkboxCheckedSelector);
        input.value = Array.from(cb, n => n.dataset[dataAttr]).join(separator);
      }
    });
    Ответ написан
    3 комментария
  • Как исправить "You are using the runtime-only build of Vue where the template compiler is not available"?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Читаем документацию внимательнее.
    Ответ написан
    Комментировать
  • Как отображать дополнительный контент только в одном из экземпляров вложенного компонента?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Делаете у компонента параметр, отвечающий за раскрытость списка. При необходимости список открыть делаете emit. В родителе по событию устанавливаете индекс открытого компонента (он же и используется при передаче параметра открытости списка - проверяете, что равен индексу текущего экземпляра). Всё.
    Ответ написан
    Комментировать
  • Как удалить один маркер с карты?

    0xD34F
    @0xD34F Куратор тега Vue.js
    У вас маркеры дублируются - вы их добавляете по событию places_changed и повторно при построении polyline. Так что один вы удалили, а другой в том же месте (другие - дублируются многократно) остался.

    Что конкретно следует предпринять:

    1. Сделайте infowindow свойством компонента. Инициализируйте его там же где и саму карту.
    2. Перенесите назначение обработчика клика маркера из updateMap в обработчик places_changed, туда, где маркер создаётся впервые. Должно получится как-то так:

      const marker = new google.maps.Marker({
        map: this.map,
        title: place.name,
        position: place.geometry.location,
      });
      google.maps.event.addListener(marker, 'click', () => {
        this.infowindow.setContent(marker.title);
        this.infowindow.open(this.map, marker);
      });
      this.markers.push(marker);

    3. Сам метод updateMap должен сильно сократиться в размерах (да и имя ему сменить не помешает - на updatePolyline, например):

      updateMap() {
        if (this.polyline) {
          this.polyline.setMap(null);
        }
      
        this.polyline = new google.maps.Polyline({
          path: this.markers.map(n => n.getPosition()),
          geodesic: true,
          strokeColor: '#FF0000',
          strokeOpacity: 1.0,
          strokeWeight: 2,
          map: this.map,
        });
      },

    4. Что касается работы с элементами DOM-дерева:

      document.getElementById('map')
      <...>
      document.getElementById('inputPlace')

      Так дела не делаются. Стоит переписать с использованием ref.
    Ответ написан
    1 комментарий
  • Как разделить строку на php?

    0xD34F
    @0xD34F
    $str = implode('+', str_split($str, strlen($str) / 4));
    Ответ написан
    Комментировать
  • Не кажется ли вам, что пора вводить тег "Устарело"?

    0xD34F
    @0xD34F
    Наверное, для вас это прозвучит неожиданно, но: Тостер вовсе не является техподдержкой Хабра. Не туда пишите свои гениальные мысли.
    Ответ написан
    2 комментария
  • Где скачать бесплатные книги по Vue.js на русском языке?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Хотелось бы почитать русскоязычной литературы по этому фреймворку

    Документация. На русском есть. Бесплатно.
    Ответ написан
    Комментировать
  • Как оптимальнее при клике на кнопки изменять состояния связанных с ними блоков?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const buttonSelector = '.button';
    const blockSelector = '.div';
    const activeClass = 'red';
    const toggleBlock = (blocks, buttons, button) =>
      buttons.forEach((n, i) => {
        blocks[i].classList[n === button ? 'toggle' : 'remove'](activeClass);
      });

    // обработчик клика делегированный, назначается один раз
    document.addEventListener('click', e => {
      const button = e.target.closest(buttonSelector);
      if (button) {
        const blocks = document.querySelectorAll(blockSelector);
        const buttons = document.querySelectorAll(buttonSelector);
        toggleBlock(blocks, buttons, button);
      }
    });
    
    // или, назначаем обработчик клика каждой кнопке индивидуально
    const buttons = document.querySelectorAll(buttonSelector);
    const blocks = document.querySelectorAll(blockSelector);
    const onClick = e => toggleBlock(blocks, buttons, e.currentTarget);
    buttons.forEach(n => n.addEventListener('click', onClick));
    Ответ написан
    6 комментариев
  • Как построить ромб при помощи пробелов и звёздочек в ruby?

    0xD34F
    @0xD34F
    (1..height_result - 1).each do |n|
      space_count = (height.to_i - n).abs
      asterisk_count = height_result - space_count * 2 - 1
      print " " * space_count + "*" * asterisk_count + "\n"
    end
    Ответ написан
    2 комментария
  • Не могу сортиронуть в PHP?

    0xD34F
    @0xD34F
    На основе этого значения надо менять результат внутри callback-функции передаваемой вторым параметром usort()

    Умножайте результат на +/- 1, в зависимости от переданного значения:

    function array_sort(array &$arr, $key, $sort = 'asc') {
      $sort = $sort === 'asc' ? 1 : -1;
      usort($arr, function($a, $b) use($sort, $key) {
        $a = $a[$key];
        $b = $b[$key];
        return $sort * ($a === $b ? 0 : $a > $b ? 1 : -1);
      });
    }
    Ответ написан
    7 комментариев
  • Как сделать "вертушку" загрузки?

    0xD34F
    @0xD34F
    Можно сделать через CSS.

    <div class="spinner"><div>

    .spinner {
      color: black;
      font-size: 5rem;
    }
    .spinner::before {
      display: inline-block;
      text-align: center;
      font-family: monospace;
      width: 5rem;
      content: "";
      animation: spinner .8s infinite steps(4);
    }
    @keyframes spinner {
      0%, 100% { content: "\2014"; }
           25% { content:    "\\"; }
           50% { content:     "|"; }
           75% { content:     "/"; }
    }


    Или через JS.

    <div class="spinner"><div>

    .spinner {
      color: black;
      font-size: 5rem;
      font-family: monospace;
    }

    const block = document.querySelector('.spinner');
    const text = [ '\u2014', '\\', '|', '/' ];
    let index = -1;
    
    setInterval(() => {
      index = (index + 1) % text.length;
      block.textContent = text[index];
    }, 200);


    SVG - тоже вариант.
    <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
      <g font-size="60" font-family="monospace" fill="black" visibility="hidden">
        <text x="30" y="60">
          —
          <animate attributeName="visibility" from="hidden" to="visible" begin="0.2s; hide4.begin" dur="0.2s" id="show1" />
          <animate attributeName="visibility" from="visible" to="hidden" begin="show1.begin + 0.2s" dur="0.2s" id="hide1" />
        </text>
        <text x="30" y="60">
          \
          <animate attributeName="visibility" from="hidden" to="visible" begin="hide1.begin" dur="0.2s" id="show2" />
          <animate attributeName="visibility" from="visible" to="hidden" begin="hide1.begin + 0.2s" dur="0.2s" id="hide2" />
        </text>
        <text x="30" y="60">
          |
          <animate attributeName="visibility" from="hidden" to="visible" begin="hide2.begin" dur="0.2s"  id="show3" />
          <animate attributeName="visibility" from="visible" to="hidden" begin="hide2.begin + 0.2s" dur="0.2s" id="hide3" />
        </text>
        <text x="30" y="60">
          /
          <animate attributeName="visibility" from="hidden" to="visible" begin="hide3.begin" dur="0.2s"  id="show4" />
          <animate attributeName="visibility" from="visible" to="hidden" begin="hide3.begin + 0.2s" dur="0.2s" id="hide4" />
        </text>
      </g>
    </svg>
    Ответ написан
    Комментировать
  • Обработчик клика кнопки для открытия tooltip vue.js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Компонент отдельный сделайте:

    Vue.component('v-tooltip', {
      template: `
    <div class="wrp">
      <div class="btn" @click="visible = !visible">{{ label }}</div>
      <div class="tooltip" :class="{ visible }">{{ message }}</div>
    </div>`,
      props: {
        label: {
          type: String,
          default: 'click me',
        },
        message: {
          type: String,
          default: 'hello, world!!',
        },
      },
      data: () => ({
        visible: false,
      }),
    });

    И создавайте столько экземпляров, сколько надо.
    Ответ написан
    Комментировать
  • Какие способы решения проблемы со стилями и роутингом в Vue.js?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Ответ написан
    Комментировать
  • Как получить THIS элемента в цикле и передать в функцию?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вместо того, чтобы внятно объяснить, что именно вам нужно, решили продублировать вопрос? Ну-ну. Могу повторить то, что сказал вам в прошлый раз: ставите ref на инпут, обходите полученный массив.

    UPD. Вынесено из комментариев:

    Не используя ref.

    Можно сделать директиву. Ссылка на элемент приходит в хуки первым параметром, а чтобы добраться до методов нужен экземпляр компонента - доступен как свойство context третьего параметра. Например.
    Ответ написан
  • Как запретить ввод отрицательных чисел?

    0xD34F
    @0xD34F Куратор тега Vue.js
    @input="onInput($event, product)"

    methods: {
      onInput(e, product) {
        product.quantity = Math.max(0, parseInt(e.target.value) || 0);
      },
    },

    или

    watch: {
      products: {
        deep: true,
        handler() {
          this.products.forEach(n => n.quantity = Math.max(0, parseInt(n.quantity) || 0));
        },
      },
    },
    Ответ написан
    Комментировать
  • Как добавить кнопки переключения по годам jquery ui datepicker?

    0xD34F
    @0xD34F Куратор тега JavaScript
    А что, если надо было бы сделать 10 кнопок - вы бы под каждую написали отдельную функцию? Нет, так дела не делаются. Уберите id, добавьте кнопкам атрибут, который будет обозначать соответствующий год:

    <input class="date">
    <input class="date">
    <input class="date">

    const yearButton = year => `
      <button
        data-year="${year}"
        class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all"
      >${year}</button>
    `;
    
    $('.date').datepicker({
      showButtonPanel: true,
    }).each(function(i) {
      $(this).datepicker(
        'option',
        'currentText',
        `Today ${yearButton(2015 + i * 2)}${yearButton(2015 + i * 2 + 1)}`
      );
    });
    
    $(document).on('click', '[data-year]', function() {
      $.datepicker._curInst.input.datepicker('setDate', `01/01/${$(this).data('year')}`);
    });
    Ответ написан
    1 комментарий
  • Как объединить значения внутри массива?

    0xD34F
    @0xD34F
    $result = array_map(function($n) {
      return implode(', ', array_column($n, 'value'));
    }, $arr);
    Ответ написан
    1 комментарий