Ответы пользователя по тегу Vue.js
  • Что означают три точки в данном случае: ...mapMutations({ (листинг в теле вопроса)?

    @askhat
    Spread Operator это синтаксический сахар для Object.create. В результате использования будет создана копия объекта–операнда, в данном случае объекта возвращённого функцией mapMutations.

    Примеры:

    // Только для примера, в жизни для этой задачи использовать .map
    [1, 2, 3].reduce((acc, el) => [...acc, el ** 2], [])
    
    const o = {
      importantField: “value”,
      some: true,
      random: false,
      stuff: null
    }
    const { importantField, ...someRandomStuff } = o
    
    // Не совсем тоже самое, но спред используется и здесь
    function variadicFn(singleArg, ...arrayWithTheRestOfArgs) {}
    
    const condition = true
    const p = { ...condition && { text: “Contion is truthful” } }
    Ответ написан
    Комментировать
  • Нормально ли использование VUE JS только для работы с формами, придания реактивности и тд?

    @askhat
    Vue примечателен хотя бы тем, с какой легкостью он интегрируется в уже существующие проекты. Набор возможностей этой библиотеки, на мой взгляд лучшая реализация MVVM. Допустим на вашем сайте есть jQuery слайдер–калькулятор, вы добавили плагин для чата с онлайн–консультантом и вам нужно передавать данные в чат. Добавив модель представления, в виде Vue приложения, вы можете легко управлять данными и моделью представления:

    <body>
      <div id="app">
        <p> {{ calculationResult | rub }}</p>
        <!-- Плагин range slider инициализируется через директиву
               В кавычка объект из binding.value из сигнатуры хука -->
        <div v-range-slider="{ min: 0, max: 10 }"></div>
        <!-- Подписка на события осуществляется прямо в html -->
        <button @click="sendToChat">Отправить в чат</button>
        <button @click="toggleChat">Открыть чат</button>
        <button @click="toggleChat">Закрыть чат</button>
        <!-- Чат изолирован от остальной разметки в отдельный компонент -->
        <chat-app v-show="isChatOpen" :result="calculationResult" />
      </div>
    </body>


    Vue.component('chat-app', {
      // Шаблон это HTML + суперспособности vue, например ref
      template: '<div ref="chat"></div>',
      // Аргумненты компонента, позволяет делать
      // - аннотации типов
      // - валидация
      // - дефолтные значения
      props: {
        result: { type: Number }
      },
      mounted() {
        // Здесь нет смысла использовать директиву, инициализируем чат когда компонент окажется в ДОМе
        // Вместо селекта элемента по например id, мы напрямую получаем из ранее созданной рефки
        this.chatInstance = new SomeChatPlugin(this.$refs.chat)
      },
      watch: {
        // При изменении пропа result, в текстовое поле чата будет добавлен текст
        result(newValue) {
          this.chatInstance.fillText(newValue)
        }
      }
    })
    
    new Vue({
      el: '#app',
      filters: {
        // Фильтры это особый способ вызова функции
        // rub(value) === value | rub
        rub(v) {
          const value = Math.round(v)
          switch(value) {
            case 1: return `${value} рубль`
            case 2:
            case 3:
            case 4: return `${value} рубля`
            default: return `${value} рублей`
          }
        }
      },
      directives: {
        rangeSlider: {
          // Директивы имеют свой жизненный цикл
          // Хук inserted это ближайшее к $(document).ready() событие
          /**
            * @param {HTMLElement} el
            * @param {Object} binding https://ru.vuejs.org/v2/guide/custom-directive.html#Аргументы-хуков
            * @param {Vue} context vue instance
            */
          inserted(el, binding, context) {
            $(el).someFancyRangeSlide(binding.value)
              .on('move', newValue => context.updateValue(newValue))
              // События выпускаемые jquery будут обработаны vue
          }
        }
      },
      data() {
        return {
          value: 0,
          calculationResult: 0,
          isChatOpen: false,
        }
      },
      methods: {
        updateValue(newValue) {
          this.value = newValue
        },
        thoggleChat() {
          this.isChatOpen = !this.isChatOpen
        },
        sendToChat() {
          this.calculationResult = this.value
        }
      }
    })


    Пример синтетический и упрощённый. Однако, ярко иллюстрирует как и зачем интегрировать Vue в любое MVC приложение, или даже в статический сайт. В прочем всё это не плохо покрывается jQuery, однако решать вам.
    Ответ написан
    7 комментариев
  • Как лучше сделать на Vue.js?

    @askhat
    1. События change на поле, модифицируют стейт компонента, от которых зависят вычислимые свойства определяющие валидна форма или нет.

    Пример
    <template>
      <form>
        <input v-model="text" />
        <button :disabled="!isValid">Submit</button>
      </form>
    </template>
    <script>
    export default {
      data() {
        return {
          text: ''
        }
      },
      computed: {
        isValid() {
          return validator(this.text)
        }
      }
    }
    </script>



    2. Зависит от того должны ли все поля быть отрендерены безусловно или опционально.

    Разница между v-if и v-show
    v-if не отрендерит разметку никогда, если её биндинг не вернёт true.
    v-show отрендерит разметку, но в зависимости от своего биндинга установит display: hidden на элемент.
    Ответ написан
  • Локальное хранение данных в ElectronJS, что лучше?

    @askhat
    Рекомендую PouchDB

    • Встраиваемая БД с поддержкой различных бекендов (SQLite, LevelDB, IndexedDB, WebSQL, LocalStorage)
    • Мастер–мастер репликация с удалённым CouchDB/PouchDB
    • Версионирование и CRDT
    • Красивенький админ интерефейс
    Ответ написан
    5 комментариев
  • Как при подключении компонентов во Vue избавиться от длинного пути компонента?

    @askhat
    WebPack Alias. Для Vue версии ниже 3, в webpack.config.js, выше 2 соответственно в vue.config.js
    Ответ написан
    Комментировать
  • Как вывести img в массиве?

    @askhat
    <img v-for="item in menu" :src="item.image"/>
    Ответ написан
    Комментировать
  • Как в vue.js работать с компонентами?

    @askhat
    1. В компоненте StoreModalComponent showModal удалить из data и перенести в props:
      export default {
        props: {
          showModal:{ type: Boolean, default: false }
        }
      }


    2. В родительском компоненте создать data свойство showModal и подписать на него только что созданные prop компонента StoreModalComponent:
      <template>
        <store-modal-component :show-modal="showModal" />
      </template>


    Ответ написан
    Комментировать
  • Как Vue.js заставить понимать jQuery, JS при переключении между компонентами?

    @askhat
    Дело в том, что когда selected возвращает ложь, элемент удаляется из древа DOM и, следовательно, перестаёт работать jquery плагин инициализированный на нём. Чтобы это избежать, необходимо научиться понимать жизненный цикл Vue компонента. К тому же следует выделять код работающий с DOM но не являющийся неотъемлемой частью компонента в директивы. Например (для однофайловых компонентов):
    <template>
      <div v-fancy-plugin="{ argumentObjectKey: 'value' }"></div>
    </template>
    <script>
    import $ from 'jquery'
    import fancyPlugin from 'fancy-plugin'
    
    export default {
      directives: {
        fancyPlugin: {
          inserted (element, argumentObject) {
            $(element).fancyPluginInit(argumentObject)
          }
        }
    }
    </script>

    Таким образом jquery код будет инициализирован в момент помещения элемента в DOM древо.
    Ответ написан
    1 комментарий
  • Как изменить переменную в родительском компоненте если в дочернем нет переменной?

    @askhat
    Вы не должны напрямую модифицировать состояние родительского компонента, это противоречит архитектуре однонаправленного потока данных. Вместо этого вы должны воспользоваться одной из следующих опций:

    1. Отправка события
    // parent.vue
    <template>
      <parent>
        <child @toggle-button="toggleButtonHandler"/>
      </parend>
    </template>
    <script>
    export default {
      data: {
        return {
          buttonShow: false
        }
      },
      methods: {
        toggleButtonHandler () {
          this.buttonShow = !this.buttonShow
        }
      }
    }
    </script>

    // child.vue
    <template>
      <button @click="clickHandler">Hide Button</button>
    </template>
    <script>
    export default {
      methods: {
        clickHandler () {
          this.$emit('toggle-button')
        }
      }
    }
    </script>

    Первый аргумент обработчика это объект события, а метод $emit принимает произвольные данные в качестве пейлоада события (второй аргумент обработчика).

    2. Воспользоваться стором
    // store.js
    export default {
      state: {
        buttonShow: false
      },
      mutations: {
        buttonToggle: state => (state.buttonShow = !state.buttonShow)
      }
    }

    Механика работы в компопненте почти такая же, за тем исключением что обработчик клика в дочернем компоненте должен коммитить мутацию:
    clickHandler () {
      this.$store.commit('buttonToggle')
    }

    А родительский компненте, в свою очередь, избаваляется от подписки на @toggle-button и больше не держит собственный стейт, а подписывается на стор:
    computed: {
      buttonShow () {
        return this.$store.state.buttonShow
      }
    }
    Ответ написан
    1 комментарий
  • Как сделать прелоадер в Vue?

    @askhat
    Если операций много и они асинхронны, можно воспользоваться паттерном Locking Pool:

    const store = {
      state: {
        lockingPool: 0
      },
      getters: {
        isUiLocked: state => state.lockingPool > 0
      },
      mutations: {
        lockUi: state => state.lockingPool++,
        unlockUi: state => state.lockingPool--
      },
      actions: {
        async someAction ({ commit }) {
          commit('lockUi')
          const { data } = await http.get('/some-url')
          commit('unlockUi')
        }
      }
    }
    Ответ написан
    9 комментариев
  • Как реализовать frontend часть отправки формы на Vue.js?

    @askhat
    <template>
      <form>
        <p v-if='errorMessage'>{{ errorMessage }}</p>
        <input type='text' v-model='username'/>
        <input type='password' v-model='password'/>
        <button @click='send()'>Log in</button>
      </form>
    </template>
    
    <script>
    import someHttpClient from 'someHttpClient'
    
    export default {
      data: {
        return {
          username: '',
          password: '',
          errorMessage: ''
        }
      },
      methods: {
        send () {
          var username, password, errorMessage = this
          if (username && password) {
            errorMessage = ''
            someHttpClient.sendAndMaybeCipher({ username, password })
          } else {
            errorMessage = 'Form not filled properly'
          }
        }
      }
    }
    </script>


    Примеры запроса:
    Ответ написан
  • Как подключить глобально плагин jquery на vue.js?

    @askhat
    Если не через NPM, то через CDN. Открывайте свой index.html и добавляйте ссылки.

    Но скорее всего вас интересует как заставить это работать. Тут два варианта:

    1. Через хук:
    export default {
      // mounted неплохой вариант, если document должен быть ready
      mounted () {
        const $ = window.$
        $('.main').onepage_scroll()
      }
    }


    2. Или через кастомную директиву:
    export default {
      directives: {
        // Произвольное имя директивы
        onePageScroll: {
          // На этом хуке компонент со всеми дочерними компонентами готов
          componentUpdated (el) {
            const $ = window.$
            // Елемент не нужно «селектить» по классу/ИД т.к. он передан в аргументы директивы
            $(el).onepage_scroll()
          }
        }
      }
    }

    <div>
      <section v-one-page-scroll />
    </div>


    Не уверен, что именно приведённые хуки буду работать хорошо/вообще—попробуйте разные варианты.
    Ответ написан
    Комментировать