Просмотров: 4209
Дата последнего изменения: 12.08.2020
Сложность урока:
4 уровень - сложно, требуется сосредоточится, внимание деталям и точному следованию инструкции.
5
Недоступно в редакциях:
Ограничений нет
Новый из старого
Создание нового компонента на основе существующего. Бывает, что компонент подходит, но за исключением одного действия (например, нужно, чтобы при выборе смайла он вставлялся не как :smile:
, а как [smile]
) или же не подходит шаблон компонента по умолчанию. При этом остальная работа компонента устраивает (например, выборка данных из базы, действия, события).
В таком случае проще всего клонировать компонент и изменить в нем только то, что нужно.
Важно! Клонируя компонент, вы наследуете поведение этого компонента. Хотя мы и стараемся соблюдать обратную совместимость везде, где это возможно, вам необходимо проверять свои мутации после обновлений продукта (чтобы убедиться, что ваш компонент работает именно так, как вы предполагали).
Модернизация
Как модернизировать компонент (мутация)
Схема похожа на схему
создания нового компонента.
Глобальные компоненты располагаются в модуле ui в директории /modules/ui/install/js/ui/vue/components/
. Компоненты, которые относятся к вашему модулю, вы можете располагать в любой директории /modules/<module>/install/js/
.
Все компоненты должны быть в виде расширений СoreJS в новом формате.
Подробнее...
Клон компонента необходимо расположить в директории своего модуля /modules/<module>/install/js/<some_path>
.
Клон должен быть в виде расширения СoreJS
в новом формате. В общих чертах клон будет выглядеть следующим образом:
/some-component/config.php
/some-component/lang/<...>/config.php
/some-component/module-name.extension-path.some-component.js
Cодержимое файла config.php:
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true)
{
die();
}
return array(
'js' => Array(
'/bitrix/js/module-name/extension-path/some-component/module-name.extension-path.some-component.js',
),
'rel' => array('module.source.component'),
'skip_core' => true,
'bundle_js' => 'your-bundle-name'
);
В зависимостях нужно указать существующий компонент, чтобы он был подгружен перед клонированием.
Содержимое файла module-name.extension-path.some-component.js:
(function(window)
{
"use strict";
/**
* Module name
* Some Component Vue component
* Clone of module.source.component
*
* @package bitrix
* @subpackage moduleName
* @copyright 2001-2019 Bitrix
*/
const BX = window.BX;
BX.Vue.cloneComponent('bx-moduleName-someComponent', 'bx-source-component-name',
{
template: `
<div class="some-component">
{{ result }}
</div>
`
});
})(window);
Синтаксис метода: BX.Vue.cloneComponent(id, sourceId, mutations)
, где:
- id - идентификатор нового компонента
- sourceId - идентификатор компонента, с которого будет снята копия
- mutations - параметры, которые будут заменены в оригинальном компоненте
Подробнее о мутациях
Параметры этого массива полностью совпадают с массивом params
в момент создания компонента, все ключи описаны в документации Vue
Основы компонентов
Основы компонентов
Компоненты — это переиспользуемые экземпляры Vue со своим именем. В примере выше это <button-counter>
. Его можно использовать как пользовательский тег внутри корневого экземпляра Vue, созданного с помощью new Vue
.
Подробнее...
и
Продвинутые компоненты.
Регистрация компонентов
При регистрации компонента у него всегда будет имя. Именем компонента будет первый аргумент.
Имя, которое даётся компоненту, может зависеть от того, где планируется его использовать.
При использовании компонента непосредственно в DOM (в отличие от строковых
шаблонов или однофайловых компонентов), настоятельно рекомендуем следовать правилам W3C
для именования пользовательских тегов (все символы в нижнем регистре, должен содержаться
дефис). Это позволит избежать конфликтов с текущими и будущими HTML-элементами.
Подробнее...
В массиве mutations нужно указать только те ключи, которые требуется изменить.
Рассмотрим пример: пусть нужно заменить метод sendText
в оригинальном компоненте. Тогда объект mutations
будет выглядеть так:
{
methods:
{
sendText()
{
...
}
}
}
Все остальные функции останутся на местах и они не будут затронуты. Если нужно добавить новый метод, это делается так же, как и замена существующего.
Правила мутации применяются ко всему дереву параметров, таким как methods
, params
, template
.
Мутация строковых значений
Строковые значения могут быть заменены на новые с возможностью вставить предыдущий текст в текст нового. Для этого в новом тексте нужно указать название этого параметра со знаками номера по обе стороны от переменной. Например, это применимо для параметра template
: чтобы в новом компоненте можно было использовать шаблон старого, добавьте в новый текст #PARENT_TEMPLATE#
.
Представим, что шаблон ранее имел вид:
{
template: "<span>123</span>"
}
Допустим, вы хотите использовать старый шаблон в своем новом шаблоне:
{
template: "<div>#PARENT_TEMPLATE#</div>"
}
Итоговой версткой после отрисовки компонента будет:
<div><span>123</span></div>
Мутация объектов
Объекты (такие как params
, methods
, computed
) могут быть расширены или заменены новыми значениями.
Кроме того, при замене уже существующих параметров в объектах есть возможность получить доступ к предыдущему значению, написав слово parent
у названия ключа. При этом первую букву ключа нужно будет перевести в верхний регистр. Например, если было вычисляемое свойство dateText
, то после его изменения к предыдущему значению можно обратиться, используя parentDateText
.
Рассмотрим пример замены метода. Допустим, есть метод sendText
, который отправляет текст вышестоящему компоненту:
{
methods:
{
sendText(text)
{
this.emit('send', text);
}
}
}
Вас устраивает работа метода, но вы хотите модифицировать текст перед отправкой:
{
methods:
{
sendText(text)
{
// модифицируем текст
text = '['+text+']';
// вызываем родительский метод но уже с другим текстом
this.parentSendText(text);
}
}
}
Рассмотрим пример замены вычисляемого свойства на примере локализаций.
Вот вычисляемое свойство, которое формирует данные локализаций в оригинальном компоненте:
{
computed:
{
localize()
{
return BX.Vue.getFilteredPhrases('IM_MESSENGER_MESSAGE_');
},
},
}
Вам нужно добавить свои, не потеряв при этом оригинальные:
{
computed:
{
localize()
{
return Object.assign({},
this.parentLocalize,
BX.Vue.getFilteredPhrases('IMOL_MESSAGE_')
);
},
},
}
Важно! Этот метод отработает корректно, даже если в оригинальном компоненте не было локализаций, т.к. Object.assign
пропустит объединение с undefined свойством.
Примечание: Все остальные значения будут заменены полностью на новые.
Пример клонирования
|
Пусть есть компонент, которые выводит значения от 1 до 10 в обратном порядке,в виде черного текста.
Клонируем его несколько раз.
Первый клон будет выводить цифры в цвете, для четных будет красный цвет, а нечетных зеленый.
Второй клон будет выводить цифры в цвете, в случайном порядке.
BX.Vue.component('bx-digits', {
data()
{
return {
digits: [1,2,3,4,5,6,7,8,9,10]
}
},
computed:
{
preparedDigits()
{
return this.digits.reverse();
}
},
template: `
<div>
<span v-for="digit in preparedDigits" style="padding: 0 5px;">{{digit}}</span>
</div>
`
});
BX.Vue.cloneComponent('bx-digits-color', 'bx-digits', {
template: `
<div>
<template v-for="digit in preparedDigits">
<span v-if="digit % 2" style="color: green; padding: 0 5px;">{{digit}}</span>
<span v-else style="color: red; padding: 0 5px;">{{digit}}</span>
</template>
</div>
`
});
BX.Vue.cloneComponent('bx-digits-color-order', 'bx-digits', {
computed:
{
preparedDigits()
{
return this.shuffleArray(this.digits)
}
},
methods:
{
shuffleArray(array)
{
for (let i = array.length - 1; i > 0; i--)
{
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
},
template: `
<div>
<template v-for="digit in preparedDigits">
<span v-if="digit % 2" style="color: green; padding: 0 5px;">{{digit}}</span>
<span v-else style="color: red; padding: 0 5px;">{{digit}}</span>
</template>
</div>
`
});
BX.Vue.create({
el: '#vue-application',
template: `
<div>
<div>Оригинальный компонент</div>
<bx-digits/>
<br/>
<div>Клонированный компонент - цвета</div>
<bx-digits-color/>
<br/>
<div>Клонированный компонент - цвета и порядок</div>
<bx-digits-color-order/>
</div>
`
});
Оригинальный компонент
10 9 8 7 6 5 4 3 2 1
Клонированный компонент - цвета
10 9 8 7 6 5 4 3 2 1
Клонированный компонент - цвета и порядок
4 1 3 2 10 5 6 9 8 7
|
Пример использования предыдущих значений при клонировании
|
Базовый компонент выводит числа от 1 до 10 в обратном порядке, при клике на цифру она окрашивается сначала в зеленый, потом в красный цвет.
Клонированный компонент наследует поведение предыдущего и вносит следующие коррективы:
- шаблон вывода обрамляется красной рамкой
- при клике помимо изменения цвета и шрифта добавляется цвет для заднего фона
BX.Vue.component('bx-digits',
{
data()
{
return {
digits: [1,2,3,4,5,6,7,8,9,10]
}
},
computed:
{
preparedDigits()
{
return this.digits.reverse();
}
},
methods:
{
changeColor(event)
{
if (event.target.style.color == "green")
{
event.target.style.color = "red";
}
else
{
event.target.style.color = "green";
}
}
},
template: `
<div>
<span v-for="digit in preparedDigits" @click="changeColor" style="padding: 0 5px; cursor: pointer">
{{digit}}
</span>
</div>
`
});
BX.Vue.cloneComponent('bx-digits-parent', 'bx-digits', {
computed:
{
// заменяем существующие в оригинале вычисляемое свойство
preparedDigits()
{
// получаем доступ к предыдущему состоянию свойства через this.parent<НазваниеСвойства>
let reverseDigit = [].concat(
this.parentPreparedDigits
);
// добавляем к отсортированным значениям цифру ноль в конец.
reverseDigit.push(0);
return reverseDigit;
}
},
methods:
{
// заменяем существующие в оригинале функцию
changeColor(event)
{
// оставляем предыдущее поведение
this.parentChangeColor(event);
// добавляем новое
if (event.target.style.color == "green")
{
event.target.style.backgroundColor = "red";
}
else
{
event.target.style.backgroundColor = "green";
}
}
},
template: `
<div style="border: 1px solid red">
#PARENT_TEMPLATE#
</div>
`
});
BX.Vue.create({
el: '#vue-application',
template: `
<div>
<div>Оригинальный компонент</div>
<bx-digits/>
<br/>
<div>Добавляем новое поведение компоненту</div>
<bx-digits-parent/>
</div>
`
});
|