Задать вопрос
  • Как запретить обработку стилей в v-html?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <iframe :srcdoc="mailContent"></iframe>
    Ответ написан
  • На каких языках можно задавать вопросы и писать ответы?

    0xD34F
    @0xD34F
    Есть правила (которые вы, между прочим, уже успели нарушить более десятка раз) - там ясно написано, что вы обязаны

    соблюдать нормы русского языка

    Русского, а не китайского или финского.
    Ответ написан
    Комментировать
  • Стоит ли доверять этому ресурсу в изучении React?

    0xD34F
    @0xD34F Куратор тега React
    на youtube

    Нет конечно. Доверяйте официальной документации.
    Ответ написан
    Комментировать
  • Почему данные не передаются через eventBus (шину событий)?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вы уже используете vuex, вот через него данные и гоняйте.

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

    через Vuex я уже сделал, теперь хочу потренироваться на шине событий

    "Потренироваться"? Вам это не нужно - вы же начинающий, а шина событий к применению давно уже не рекомендуется. Зачем вам учиться с использованием сомнительных и устаревших практик?

    в чём моя ошибка понять не могу

    "Ошибка"? Ошибки - у вас их целый ворох.

    Если говорить о тех, из-за которых наблюдаемое поведение отличается от ожидаемого, то это: во-первых, передача данных до того, как экземпляр компонента (окно добавления события) создаётся; во-вторых, подписка на события в диалоговом окне в обработчике клика по кнопке добавления, а не при создании компонента.

    Но кроме них есть и другие косяки - не удаляете обработчики событий при уничтожении экземпляра компонента; зачем-то передаёте элементы даты раздельно; в календаре подписываетесь на получение данных, отправляемых календарём же.

    В общем, всё очень-очень плохо.
    Ответ написан
  • Правильно ли делать компоненты большими?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Весь текст, как я понимаю, находится в js-файле.

    Не понимаете. Очевидно, вы не слышали про разделение представления и содержания. Никто никакие "таблицы из 50+ позиций", "записи из блогов" и т.д. в компоненты не зашивает. Данные подгружаются отдельно. И размещаются в заранее подготовленных местах.

    То есть, вместо

    <tr>
    <tr>
    ...
    <tr>

    должно быть

    <tr v-for="n in data">

    loadData() {
      fetch(...).then(r => r.json()).then(r => this.data = r);
    },
    Ответ написан
  • Как посчитать сумму вложенных элементов при неизвестной глубине объекта?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Рекурсия есть:

    const sumNested = (data, getVal, key) => Object
      .entries(data instanceof Object ? data : {})
      .reduce((acc, [ k, v ]) => acc + sumNested(v, getVal, k), getVal(key, data));
    
    
    const numItems = sumNested(obj, (k, v) => (k === 'items' && Array.isArray(v)) ? v.length : 0);

    Рекурсии нет:

    function sumNested(data, getVal) {
      let result = 0;
    
      for (const stack = [ [ , data ] ]; stack.length;) {
        const [ k, v ] = stack.pop();
        stack.push(...(v instanceof Object ? Object.entries(v) : []));
        result += getVal(k, v);
      }
    
      return result;
    }
    Ответ написан
    Комментировать
  • Как создать набор блоков для загрузки изображений?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Компонент input-img

    Вырезаете секцию data, ничего этого не надо. Задача компонента - показывать картинку (если она есть), после загрузки отправлять новую картинку родителю, отправлять родителю запрос на удаление картинки:

    methods: {
      onFileChange(e) {
        const file = e.target.files[0];
        if (file) {
          const reader = new FileReader();
          reader.onloadend = () => {
            const image = new Image();
            image.onload = () => {
              this.$emit('uploaded', {
                file,
                src: image.src,
              });
            };
            image.src = reader.result;
          };
          reader.readAsDataURL(file);
        }
      },
    },

    <i
      v-text="img.src ? 'x' : '+'"
      @click="$emit('remove')"
      ...
    />
    <img
      v-if="img.src"
      :src="img.src"
      ...
    >
    <input type="file" accept="image/*" @change="onFileChange">

    Компонент set-imgs

    Добавим поддержку директивы v-model. В props переименовываете images в value, убираете из дефолтного значения объект с пустыми полями. Добавляете images в computed - в качестве значения будет копия value плюс, если длина value меньше максимально допустимой, тот объект с пустыми полями; сеттер - отправляет родителю images, из которого выкинут пустой объект:

    props: {
      value: Array,
      max: {
        type: Number,
        default: 3,
      },
    },
    computed: {
      images: {
        get() {
          const images = [...this.value];
          if (images.length < this.max) {
            images.push({
              file: null,
              src: null,
            });
          }
          return images;
        },
        set(val) {
          this.$emit('input', val.filter(n => n.file));
        },
      },
    },

    Как в этом случае будет выглядеть добавление/изменение картинки - images заменяется на копию, у которой заменён элемент с указанным индексом. А удаление, соответственно, будет выглядеть как фильтрация, тоже по индексу:

    methods: {
      onUpload(index, img) {
        this.images = this.images.map((n, i) => i !== index ? n : img);
      },
      remove(index) {
        this.images = this.images.filter((n, i) => i !== index);
      },
    },

    Собираем всё вместе:

    <input-img
      v-for="(n, i) in images"
      :img="n"
      @uploaded="onUpload(i, $event)"
      @remove="remove(i)"
    />

    Наконец, использование set-imgs

    data: () => ({
      images: [],
    }),

    <set-imgs v-model="images" :max="5" />

    https://jsfiddle.net/7umwaqfd/
    Ответ написан
  • Как сделать треугольник на блоке?

    0xD34F
    @0xD34F Куратор тега CSS
    .text::after {
      content: '';
      position: absolute;
      left: 23px;
      top: -10px;
      width: 16px;
      height: 16px;
      background: #f2fbff;
      border: 1px solid transparent;
      border-top-color: #cfcfcf;
      border-left-color: #cfcfcf;
      transform: rotate(45deg);
    }
    Ответ написан
    Комментировать
  • В чём может быть ошибка в коде?

    0xD34F
    @0xD34F Куратор тега JavaScript
    final_data.reduce((acc1, num1) => acc1.reduce((acc2, num2) => acc2.concat(num1.map(num3 => [].concat(num2, num3))), []))

    Вот это выглядит прям очень нехорошо - acc2.concat следует заменить на acc2.push, нет никакой необходимости в создании нового массива на каждом шаге (и, соответственно, копировании всех его элементов), можно добавлять новые элементы в существующий массив:

    final_data.reduce((acc1, num1) => {
      return acc1.reduce((acc2, num2) => {
        acc2.push(...num1.map(num3 => [...num2, ...num3]));
        return acc2;
      }, [])
    })

    UPD. Да и промежуточные массивы, состоящие из элементов num2 и num3, тоже не нужны, можно сразу строки создавать:

    return final_data.reduce((acc1, num1) =>
      acc1.reduce((acc2, num2) => (
        acc2.push(...num1.map(num3 => num2 + num3)),
        acc2
      ), [])
    ).join(',');
    Ответ написан
    1 комментарий
  • Как отфильтровать массив объектов по нескольким свойствам?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const whatIsInAName = (collection, source) =>
      collection.filter(function(n) {
        return this.every(([ k, v ]) => n[k] === v);
      }, Object.entries(source));

    или

    function whatIsInAName(collection, source) {
      const result = [];
    
    COLLECT:
      for (const n of collection) {
        for (const k in source) {
          if (n[k] !== source[k]) {
            continue COLLECT;
          }
        }
    
        result.push(n);
      }
    
      return result;
    }
    Ответ написан
    1 комментарий
  • Как добавить каждым N элементам общую обёртку?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Где элементы находятся, во что и по сколько надо оборачивать:

    const parentSelector = '.wrap';
    const wrapperTag = 'div';
    const wrapperClass = 'wrap-item';
    const wrapSize = 4;

    Оборачиваем:

    const $items = $(parentSelector).children();
    
    for (let i = 0; i < $items.length; i += wrapSize) {
      $items.slice(i, i + wrapSize).wrapAll(`<${wrapperTag} class="${wrapperClass}">`);
    }

    или

    const parent = document.querySelector(parentSelector);
    
    parent.append(...Array.from(
      { length: Math.ceil(parent.children.length / wrapSize) },
      () => {
        const wrapper = document.createElement(wrapperTag);
        wrapper.classList.add(wrapperClass);
        wrapper.append(...Array.prototype.slice.call(parent.children, 0, wrapSize));
        return wrapper;
      }
    ));
    Ответ написан
    Комментировать
  • Как сделать, чтобы в Air Datepicker, там, где написан месяц, не отображался год?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Свойство navTitles:

    navTitles: {
      days: 'MM',
    },

    https://jsfiddle.net/dkwL24f9/
    Ответ написан
    Комментировать
  • Как заменить в строке символы на теги?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const text = document.querySelector('#area').value;
    const pre = document.querySelector('#pre');
    
    pre.innerHTML = text.replace(/f+/g, '<span>$&</span>');
    Ответ написан
    1 комментарий
  • Как менять отступ в зависимости от прокрутки?

    0xD34F
    @0xD34F Куратор тега JavaScript
    document.addEventListener('scroll', function() {
      document.querySelector('.wrap_portfolio').style.transform = `translateX(${window.scrollY}px)`;
    });
    Ответ написан
  • Как реализовать поиск значения в объекте?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Чей id хотим найти: const color = 'orange';.

    Ищем:

    const { id = null } = Object.values(fruits).find(n => n.color === color) || {};
    
    // или
    
    let id = null;
    for (const k in fruits) {
      if (fruits.hasOwnProperty(k) && fruits[k].color === color) {
        id = fruits[k].id;
        break;
      }
    }

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

    А если у меня несколько оранжевых фруктов, как поступить?

    Ну, доставайте всё, что есть.

    Сразу достаём массив id для какого-то конкретного цвета:

    const ids = Object.values(fruits).reduce((acc, n) => (
      n.color === color && acc.push(n.id),
      acc
    ), []);

    Или, сначала группируем данные, а затем можно извлекать массивы id для различных цветов:

    function group(data, key, val = n => n) {
      const getKey = key instanceof Function ? key : n => n[key];
      const getVal = val instanceof Function ? val : n => n[val];
      const result = {};
    
      for (const n of data) {
        const k = getKey(n);
        (result[k] = result[k] || []).push(getVal(n));
      }
    
      return result;
    }

    const idsByColor = group(Object.values(fruits), 'color', 'id');
    
    const orangeIds = idsByColor.orange || [];
    const greenIds = idsByColor.green || [];
    Ответ написан
    2 комментария
  • Как использовать один контекст canvas для нескольких графиков?

    0xD34F
    @0xD34F
    chart.destroy();
    chart.config= charts[i];
    chart.update();

    Это безумие. Вы уничтожили график, и тут же пытаетесь что-то ещё с ним делать.
    Труп насиловать не надо, создавайте новый график: chart = new Chart('chart', charts[i]);.

    UPD. Например.
    Ответ написан
    Комментировать
  • Как такое можно реализовать на react.js?

    0xD34F
    @0xD34F Куратор тега React
    state = {
      block1: false,
      block2: false,
    }
    
    componentDidMount() {
      setTimeout(() => this.setState({ block1: true }), 3000);
      setTimeout(() => this.setState({ block2: true }), 6000);
    }
    
    render() {
      const { block1, block2 } = this.state;
      return (
        ...
          {block1 && <div class="block-1">Блок 1</div>}
          {block2 && <div class="block-2">Блок 2</div>}
        ...
      );
    }

    UPD. https://jsfiddle.net/jaLgf9w7/
    Ответ написан
    1 комментарий
  • Как избавиться от ошибки про мутацию при передаче значения в поле редактирования компоненты?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Очевидно, сделать pname вместо параметра свойством компонента.

    UPD. Например.

    <div id="app">
      <todo-add @todo-new="addNewTodo"></todo-add>
      <pre>{{ todoJson }}</pre>
    </div>

    Vue.component('todo-add', {
      template: `
    <div>
      <input v-model="name" autofocus></input>
      <button @click="add">Add New Todo</button>
    </div>`,
      data: () => ({
        name: '',
      }),
      methods: {
        add() {
          const name = this.name.trim();
          if (name) {
            this.$emit('todo-new', name);
            this.name = '';
          }
        },
      },
    });
    
    new Vue({
      el: '#app',
      data: {
        todoArr: [
          { id: 1, name: 'hello, world!!' },
        ],
      },
      methods: {
        addNewTodo(name) {
          this.todoArr.push({
            id: 1 + Math.max(0, ...this.todoArr.map(n => n.id)),
            name,
          });
        },
      },
      computed: {
        todoJson() {
          return JSON.stringify(this.todoArr, null, 2);
        },
      },
    });

    Ответ написан
  • Как сократить код?

    0xD34F
    @0xD34F Куратор тега JavaScript
    Заменить id на data-атрибут: id="0" ---> data-index="0".
    Нет необходимости каждый раз создавать картинку, можно перезаписывать src существующей.

    Как добраться до картинки, откуда взять для неё src:

    const imgSelector = '#main__display img';
    const key = 'index';
    const attr = `data-${key}`;
    const buttonSelector = `[${attr}]`;

    Как достать src, имея на руках элемент с индексом:

    const getSrc = el => collect[
      $(el).data(key)
      // или
      $(el).attr(attr)
      // или
      el.dataset[key]
      // или
      el.getAttribute(attr)
      // или
      el.attributes[attr].value
    ];

    Слушаем клики, достаём src, назначаем картинке:

    $(buttonSelector).click(function(e) {
      $(imgSelector).attr('src', getSrc(this));
    });
    
    // или
    
    $(document).on('click', buttonSelector, e => {
      $(imgSelector).prop('src', getSrc(e.currentTarget));
    });
    
    // или
    
    document.querySelectorAll(buttonSelector).forEach(function(n) {
      n.addEventListener('click', this);
    }, function(e) {
      this.setAttribute('src', getSrc(e.currentTarget));
    }.bind(document.querySelector(imgSelector)));
    
    // или
    
    document.addEventListener('click', ({ target: t }) => {
      if (t = t.closest(buttonSelector)) {
        document.querySelector(imgSelector).src = getSrc(t);
      }
    });
    Ответ написан
    Комментировать