Продолжение Части 1 этой серии. См. Также Часть 3 этой серии, в которой описывается отложенная загрузка компонентов Vue для повышения производительности.

В своей предыдущей статье я продемонстрировал, как использовать поддержку многостраничного приложения (MPA) Vue для встраивания однофайловых компонентов Vue в шаблон Django, что позволяет разработчикам легко совмещать использование шаблонов Django и Vue в приложении.

В статье реализован очень простой пример. С момента написания статьи я получил несколько вопросов относительно обмена информацией от Django к Vue и между компонентами Vue на одной странице.

В этой статье я объясню, как Vuex можно ввести в Vue MPA, а информацию можно

  • совместно используется несколькими компонентами на одной странице
  • сохраняется в компонентах при загрузке страницы
  • передано из шаблонов Django в свойства Vue

Знакомство с Vuex в проекте Vue / Django

Я представлю два простых компонента счетчика Vue на одной странице приложения Django. Эти компоненты будут извлекать и изменять свое состояние из одного и того же хранилища Vuex. Кроме того, каждый счетчик будет отображать сообщение, предоставленное как свойство Vue из переменной шаблона Django.

Я продолжу с того места, где остановился в части 1: работающее приложение Django, интегрированное с парой компонентов Vue. Если вы следуете вместе с кодом, то отправная точка в репозитории примера по адресу отмечена тегом part_1.

Добавление Vuex

Начнем с добавления в наш проект Vuex и плагина Vuex persistedstate. Из основного каталога проекта

cd vue_frontend
yarn add vuex vuex-persistedstate

Компонент простого счетчика

Взяв за основу учебник Vuex, давайте создадим src/components/HelloWorld.vue с помощью простого компонента счетчика:

Этот компонент имеет единственное свойство msg, которое будет отображаться над показаниями счетчика. Вычисленное count извлекается из хранилища Vuex (которое мы еще не создали) и отображается в окружении кнопок, которые при нажатии вызывают два метода (increment и decrement), которые, в свою очередь, вызывают мутаторы состояния.

Обратите внимание, что здесь может быть более подходящим использовать Vuex Actions, но для простоты я вызываю мутаторы напрямую.

Несколько компонентов на странице

Теперь, когда у нас есть новый компонент, нам нужно включить его в наш шаблон Django. Как и в части 1, мы создадим новую точку входа и проинструктируем Vue, как монтировать наши элементы DOM. Единственная концептуальная разница в том, что на этот раз мы монтируем несколько компонентов. Однако из-за большого количества нюансов в том, как Vue загружается в MVA, есть несколько конкретных способов, которыми мы должны закодировать нашу точку входа, чтобы гарантировать, что свойства могут быть прочитаны, и это состояние может совместно использоваться между компонентами.

Создайте новый файл index.js с содержимым:

Опять же, за исключением импорта и использования Vuex, это концептуально аналогично другим нашим точкам входа. Но есть различия в том, как мы импортируем Vue и как монтируем компоненты. Во-первых, мы импортируем Vue из vue/dist/vue.js, что понадобится позже, когда мы захотим сделать наше хранилище Vuex общим для всех компонентов. Во-вторых, монтирование компонентов с использованием метода el / components вместо _11 _ / _ 12_ позволяет нам захватывать свойства, предоставляемые непосредственно из статического HTML.

Обратите внимание, что мы монтируем один и тот же компонент дважды, но вместо этого мы могли бы смонтировать второй компонент, если бы он был у нас.

Теперь, когда наша конечная точка спроектирована, мы расскажем об этом Vue. Измените vue.config.js и обновите конфигурацию pages, чтобы включить нашу новую конечную точку:

const pages = {
    "index": {
        entry: "./src/index.js",
        chunks: ["chunk-vendors"],
    },
    ...
};

И, наконец, мы обновляем наш шаблон Django index.html, чтобы включить элементы #hello_world_a и #hello_world_b DOM, которые мы указали в нашей точке входа:

{% with msg0="The Left Counter" msg1="The Right Counter" %}
  <div id="hello_world_a" style="width: 49%; display: inline-block">
    <hello-world msg="{{ msg0 }}"></hello-world>
  </div>
  <div id="hello_world_b" style="width: 49%; display: inline-block">
    <hello-world msg="{{ msg1 }}"></hello-world>
  </div>
{% endwith %}

{% render_bundle 'chunk-vendors' %}
{% render_bundle 'index' %}

Оба элемента включены на страницу, и мы передаем каждому свойство msg, которое берется из переменной шаблона Django. Здесь переменные представляют собой статические строки, но они легко могут быть контекстными переменными или выходными данными тега шаблона.

Если мы попытаемся запустить приложение сейчас, мы получим несколько ошибок о том, что state не определено, потому что мы еще не создали наш магазин.

Создание магазина Vuex

Наш компонент HelloWorld зависит от хранилища Vuex, так что давайте это добавим.

Создайте новую папку vuex внутри src. Я считаю полезным организовать свой магазин по модулям, поэтому начните с создания файла src/vuex/vuex_module_counter.js с состоянием и мутаторами, которые нужны нашему компоненту HelloWorld:

export default {
    state: {
        count: 0
    },
    mutations: {
        increment: state => state.count++,
        decrement: state => state.count--
    },
}

Затем нам нужно создать экземпляр магазина Vuex. Хотя обычно это довольно просто, поскольку мы хотим разделять состояние между компонентами на одной странице, нам нужно обойти тот факт, что Vue будет создавать отдельные экземпляры хранилища для каждого компонента в нашем MVA. К счастью, я заметил, что пользователь GitHub sumobrian разветвил мое репо и включил очень умный способ сделать это, используя технику, впервые описанную (как мне кажется) в этом сообщении в блоге Christo Crampton.

Создайте новый файл vuex/vuex_store_as_plugin.js с содержимым:

Настройка магазина очень похожа на описанную в руководствах по Vuex. Однако отмечу несколько отличий.

Во-первых, мы используем плагин createPersistedState, сообщая этому плагину, что мы хотим, чтобы состояние count сохранялось на протяжении всего сеанса посетителя. Плагин позаботится обо всех деталях за нас. Обратите внимание, что если бы у нас было более сложное приложение со многими переменными состояния, здесь мы могли бы выбрать, какие из них мы хотели бы сохранить.

Затем мы создаем магазин Vuex, используя созданный ранее модуль счетчика. Мы могли бы легко включить сюда любое количество дополнительных модулей.

Наконец, согласно методике Кристо, мы экспортируем плагин Vue, который выполняет единственную задачу, а именно заменяет стандартный объект $store нашим общим хранилищем. Это гарантирует, что все наши компоненты на одной странице будут использовать один и тот же экземпляр магазина.

Теперь, когда мы создали наш Vuex-Store-As-Plugin, давайте проинструктируем нашу точку входа index.js использовать его, добавив пару строк:

Обратите внимание, что мы не включаем никаких ссылок на хранилище в конструкторы Vue, потому что вместо этого мы используем наш магазин через плагин.

Вот и все! Пришло время…

Полюбуйтесь нашей работой

Запустите свой сервер Django dev,

./manage.py runserver

запустить интерфейс Vue,

cd vue_frontend
yarn serve

и укажите в браузере URL-адрес, о котором вам сообщили (вероятно, http://localhost:8080).

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

Увеличьте счетчики несколько раз и перезагрузите страницу, и плагин persistedstate обеспечит восстановление последнего состояния.

Вывод

Введя несколько компонентов Vue, управляемых общим состоянием Vuex, на одну страницу Django, можно легко объединить две технологии внешнего интерфейса, используя каждую из них там, где она будет наиболее подходящей, без ущерба для сильных сторон любой из них.

См. также Часть 3 этой серии, в которой описывается отложенная загрузка компонентов Vue для повышения производительности.

Благодарности

Как отмечалось выше, я впервые узнал о технике Vuex-Store-As-Plugin от пользователя GitHub sumobrian в его форке моего репо. Метод, который он реализовал, был впервые описан (я полагаю) Christo Crampton в его статье блога Сделайте свой магазин vuex глобально доступным, зарегистрировав его как плагин. Спасибо обоим!

Источник

См. Сопутствующий исходный код django-vue-mpa. Если вы хотите быстро запустить собственный проект, используя методы, описанные в этой статье, посмотрите Vue + Django cookiecutter.