Работа с Vue в Битрикс
Битрикс уже содержит в себе фремворк Vue.js, подключается в виде расширения:
<? Bitrix\Main\UI\Extension::load("ui.vue3"); ?>
В битрикс доступны все версии Vue.js, для подключения разных версий, меняется только цифра ui.vue3
.
vuex
который необходим для организации хранилища, подключается в виде расширения:
<? Bitrix\Main\UI\Extension::load("ui.vue.vuex"); ?>
Режим разработки
Для упрощения кастомизации, необходимо включить режим разработчика, для этого в файле /bitrix/php_interface/init.php
или /local/php_interface/init.php
надо разместить константу:
define('VUEJS_DEBUG', true);
Сделав это, можно в консоли разработчика увидеть все компоненты Vue и их данные, все исходники минифицированы и без этого будет трудно разобраться в коде.
Расширение для браузера
Для того, чтобы в консоли разработчика появилась информация по Vue в соответствующий вкладке, необходимо установить расширение для браузера, я использую Гугл Хром, переходим в магазин и устанавливаем расширение для браузера.
Просмотр доступных компонентов:
Для просмотра состояния компонентов и их данных, используется вкладка Vuex:
Использование Vue по дефолту
Для использования функций Vue в Битрикс, нужно использовать не Vue.xxx
, а BX.Vue.xxx
где xxx
нужная функция:
script.js// экземпляр Vue
const BitrixVue = BX.Vue3.BitrixVue;
// настройки
const app = BitrixVue.createApp({
// хранения данных
data() { },
// свои функции
methods: { },
// вычисляемые свойства
computed: { },
// асинхронные действия
watch: { },
// повторяющийся код
mixins: [ ],
});
// контейнер
app.mount('#app');
В template.php
разметку делаем как будто мы работаем во Vue файле:
template.php<? Bitrix\Main\UI\Extension::load("ui.vue3"); ?>
<div id="app">
{{ counter }}
</div>
Соответственно в style.css
пишем стили для нашего компонента которые так же подтянутся.
Использование Vue с выносом функций из BX.Vue3 в глобальный объект Window
Если на проекте Vue используется везде, значит есть возможность установить его глобально, условно в header.php
сделаем подключение:
header.php<? Bitrix\Main\UI\Extension::load("ui.vue3"); ?>
Теперь наш объект BX.Vue3
есть везде, теперь мы можем подключить другой скрипт глобально:
header.php<script> for (const key in BX.Vue3) window[key] = BX.Vue3[key] </script>
Тут мы просто вынесли функции из BX.Vue3
в window
, после этого нам станет доступен «нативный» синтаксис, теперь мы можем переписать свой script.js
:
script.jsBX.ready(() => {
const application = createApp({
// хранения данных
data() {
return {
name: 'Привет'
}
},
// свои функции
methods: {},
// вычисляемые свойства
computed: {},
// асинхронные действия
watch: {},
// повторяющийся код
mixins: [],
});
application.mount('#root');
})
Рабочий вариант, но все же это плохое решение. Мы засоряем глобальный объект window
. Можно еще по желанию удалить из window
BX.Vue3
, так как все функции мы уже вынесли.
Использование Vue через деструктуризация
Что, если на проекте Vue используется не везде, и нет желания засорять window
, но хочется использовать функции Vue без BX.Vue3
, выход есть, и причем весьма простой, нужно использовать деструктуризацию:
header.php<? Bitrix\Main\UI\Extension::load("ui.vue3"); ?>
<script>const { createApp } = BX.Vue3</script>
script.jsBX.ready(() => {
const application = createApp({
// хранения данных
data() {
return {
name: 'Привет'
}
},
// свои функции
methods: {},
// вычисляемые свойства
computed: {},
// асинхронные действия
watch: {},
// повторяющийся код
mixins: [],
});
application.mount('#root');
})
У нас все так же будет замечательно работать, только теперь данные функции у нас не в объекте window
.
Для получения данных с бэка, есть не самый красивый, но рабочий вариант:
template.php<script>
const arResult = <?=Bitrix\Main\Web\Json::encode($arResult)?>
</script>
Свой компонент с Vue
Создаем с нуля наш компонент.
Создаем template.php
с логикой Vue, в данном примере будет добавление пользователя и удаление пользователя:
template.php<? if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die(); ?>
<ul id="users-list" class="users-list">
<li v-for="(user, key) in arResult.users" class="users-list__item" :key="key">
{{ user }}
<button type="button" @click="deleteUser(user.id)">Удалить пользователя</button>
</li>
<form @submit="addUser" class="form">
<div class="form__field">
<label>Имя пользователя</label>
<input type="text" name="name">
</div>
<button type="submit">Добавить нового пользователя</button>
</form>
</ul>
Немного добавим стилей в style.css
, чтобы все убедились что стили работают:
style.css.users-list {
padding: 12px;
}
.users-list__item {
padding: 12px;
background-color: #e2e2e2;
border-radius: 4px;
margin-bottom: 8px;
}
Напишем логику в class.php
. Тут все просто подключаем наш Vue, далее создаем класс и наследуемся от стандартного CBitrixComponent
и реализуем интерфейс чтобы наш класс был контролируемым и мы могли работать с ним через BX.ajax.runComponentAction
:
class.php<? if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\UI\Extension,
Bitrix\Main\Engine\Contract\Controllerable;
Extension::load("ui.vue3");
class UsersList extends CBitrixComponent implements Controllerable
{
protected static array $users = [
[
'id' => 1,
'name' => 'Alexander',
],
[
'id' => 2,
'name' => 'Ivan',
],
[
'id' => 3,
'name' => 'Sergey',
],
[
'id' => 4,
'name' => 'Smith',
],
[
'id' => 5,
'name' => 'John'
],
];
public function configureActions(): array
{
return [];
}
public function deleteUserAction($id): array
{
foreach (self::$users as $key => $user) {
if ($user['id'] == $id) {
unset(self::$users[$key]);
break;
}
}
return self::$users;
}
public function getUsersAction(): array
{
return self::$users;
}
public function addUserAction(): array
{
$lastUser = end(self::$users);
$newUser = [
'id' => $lastUser['id'] + 1,
'name' => $_POST['name'],
];
self::$users[] = $newUser;
return self::$users;
}
public function executeComponent(): void
{
$this->includeComponentTemplate();
}
}
Далее все просто, берем создаем наше Vue приложение, создаем нужные нам объекты, переменные, функции и работаем с ними. В самом начале создаем реактивный объект arResult
в который будем помещать наши другие массивы, или объекты, данный объект будет отслеживать изменения и менять страницу в соответствии с нашей логикой в template.php
:
script.jsconst { runComponentAction } = BX.ajax;
const { ref, createApp, reactive } = BX.Vue3;
BX.ready(() => {
createApp({
setup() {
function deleteUser(id) {
// нужно правильно указать пространство имен и название компонента
const request = runComponentAction("my_components:test", "deleteUser", {
mode: "class",
data: { id: id },
});
request.then((reponse) => arResult.users = reponse.data);
}
function addUser(e) {
e.preventDefault();
// нужно правильно указать пространство имен и название компонента
const request = runComponentAction("my_components:test", "addUser", {
mode: "class",
data: new FormData(e.target),
});
request.then((reponse) => arResult.users = reponse.data);
};
const arResult = reactive({});
// нужно правильно указать пространство имен и название компонента
const request = runComponentAction("my_components:test", "getUsers", {
mode: "class",
});
request.then((reponse) => (arResult.users = reponse.data));
return {
arResult,
addUser,
deleteUser
};
},
}).mount("#users-list");
});