1. Введение
Учащиеся, которые занимались проектами электронной коммерции, знают, что оформление магазина является важной функцией системы электронной коммерции. В некоторых сценариях это может быть создание рекламных страниц, создание страниц действий и создание микространиц, но основные функции аналогичны. . Так называемое украшение магазина означает, что пользователи могут создавать мобильные страницы на стороне ПК, и им нужно всего лишь перетаскивать, чтобы реализовать редактирование страницы, что является очень индивидуальной функцией пользователей. Окончательный отредактированный результат можно отображать и продвигать в программах H5 и Mini.
иметь хвалебную кармуЭто система SaaS Saas Industry Industry Industry SaaS, которая предоставляет информационные технологии и интернет-решения для Соединенных Штатов в этой отрасли. Похвала и сама фитинговая индустрия похвалы обеспечивает функцию для облегчения пользователю настроить магазин, отображающий содержимое ниже, является функция скриншота.
Изображение выше — это интерфейс на стороне ПК, а два изображения ниже — окончательный эффект отображения H5 и апплета соответственно. Можно просто увидеть, что сторона ПК в основном выполняет функции редактирования и предварительного просмотра страниц, включая богатые бизнес-компоненты и подробные параметры настройки; H5 и апплеты выполняют функцию окончательного отображения.
Давайте взглянем на текущие технические основы Youzianye: в настоящее время наша сторона ПК основана на стеке технологий React, сторона H5 основана на стеке технологий Vue, а Mini Program — это собственная модель разработки WeChat.
Исходя из этого, если мы хотим заниматься техническим проектированием, мы можем рассматривать со следующих точек зрения:
-
Все уровни просмотра трех терминалов управляются данными Как управлять потоком данных каждого терминала?
-
На трех терминалах три разных стека технологий, но в бизнесе один и тот же контент, есть ли возможность повторного использования кода?
-
Данные, окончательно сгенерированные ПК, должны быть переданы H5 и небольшим программам, а три терминала совместно используют набор данных.Какую форму следует использовать для стандартизации управления данными с трех терминалов?
-
О масштабируемости, как экономически эффективно поддерживать бизнес больше компонентов последующей деятельности, чтобы присоединиться?
2. Схемный дизайн
Поэтому мы разработали решение для решения вышеуказанных проблем в соответствии с техническими основами кармы хвалы.
Сначала выложите архитектурную диаграмму:
2.1 Управление данными
Прежде всего, сосредоточьтесь на компоненте CustomPage, который является главной консолью для всего оформления магазина, он поддерживает три основных компонента, PageLeft, PageView и PageRight, которые соответствуют трем упомянутым выше модулям на стороне ПК.
Чтобы обеспечить совместное использование данных, CustomPage поддерживает «область» через контекст React, предоставляя «источник данных», общий для трех внутренних компонентов. PageLeft , PageRight — это левый компонент и правый компонент редактирования соответственно,context.page
Данные, изменения данных передаются черезcontext.pageChange
передача. Весь процесс примерно выражается в коде следующим образом:
// CustomerPage
class CustomerPage extends React.Component {
static childContextTypes = {
page: PropTypes.object.isRequired,
pageChange: PropTypes.func.isRequired,
activeIndex: PropTypes.number.isRequired,
};
getChildContext() {
const { pageInfo, pageLayout } = this.state;
return {
page: { pageInfo, pageLayout },
pageChange: this.pageChange || (() => void 0),
activeIndex: pageLayout.findIndex(block => block.active),
};
}
render() {
return (
<div>
<PageLeft />
<PageView />
<PageRight />
</div>
);
}
}
// PageLeft
class PageLeft extends Component {
static contextTypes = {
page: PropTypes.object.isRequired,
pageChange: PropTypes.func.isRequired,
activeIndex: PropTypes.number.isRequired,
};
render() {...}
}
// PageRight
class PageRight extends Component {
static contextTypes = {
page: PropTypes.object.isRequired,
pageChange: PropTypes.func.isRequired,
activeIndex: PropTypes.number.isRequired,
};
render() {...}
}
Что касается стороны H5, динамические компоненты Vue можно использовать для завершения динамизации бизнес-компонентов.Этот метод асинхронных компонентов обеспечивает большую гибкость и очень подходит для сценариев оформления магазина.
<div v-for="item in components">
<component :is="item.component" :options="convertOptions(item.options)" :isEdit="true">
</component>
</div>
Поскольку апплет не имеет концепции динамических компонентов, он может передавать толькоif else
Спагетти-код для достижения этой функции. Если мы подумаем о повторном использовании более глубоко, в сообществе есть инструменты с открытым исходным кодом для реализации преобразования между Vue и апплетом, которые могут помочь нам сделать больше, но мы не будем обсуждать это здесь.
Данные, сгенерированные при редактировании на ПК, в конечном итоге будут переданы H5 и апплету, поэтому очень важно согласовать формат данных и значение поля. Чтобы решить эту проблему, мы извлекли пакет npm для управления объединением данных с 3 терминалов. Этот пакет описывает формат поля и значение каждого компонента.При реализации каждой стороне нужно только разработать соответствующий стиль в соответствии с описанием поля, что также решает проблему масштабируемости. Если в будущем вам потребуется добавить новые бизнес-компоненты, вам нужно будет только согласовать и обновить новый пакет npm, чтобы добиться унификации данных с трех сторон.
/**
* 显示位置
*/
export const position = {
LEFT: 0,
CENTER: 1,
RIGHT: 2,
};
export const positionMap = [{
value: position.LEFT,
name: '居左',
}, {
value: position.CENTER,
name: '居中',
}, {
value: position.RIGHT,
name: '居右',
}];
2.2 Межтерминальное мультиплексирование
PageView — это компонент предварительного просмотра, который является сердцем этого дизайна. По самой прямой идее, мы можем использовать React для реализации всех бизнес-компонентов, а затем снова реализовать логику упорядочивания и отображения данных, затем реализовать все компоненты в H5 и апплете, и снова реализовать логику упорядочивания и отображения данных. Но учитывая повторное использование кода, можем ли мы сделать что-то «ленивое»?
Если мы не рассматриваем апплет, мы знаем, что и ПК, и H5 реализованы на основе стиля dom, а логика также является кодом js, Если оба конца реализованы один раз, необходимо выполнить много повторяющейся работы. Итак, чтобы добиться возможности повторного использования стиля и логики, мы придумали способ вложения страниц H5 через iframe и взаимодействия с данными через postmessage, реализуя таким образом использование H5 в качестве компонента предварительного просмотра, затем код ПК и H5. это только один набор. В соответствии с этой идеей реализации компонент PageView может быть реализован следующим образом:
class PageView extends Component {
render() {
const { page = {} } = this.props;
const { pageInfo = {}, pageLayout = [] } = page;
const { loading } = this.state;
return (
<div className={style}>
<iframe
title={pageInfo.title}
src={this.previewUrl}
frameBorder="0"
allowFullScreen="true"
width="100%"
height={601}
ref={(elem) => { this.iframeElem = elem; }}
/>
</div>);
}
}
Код PageView очень прост, он заключается во встраивании iframe, а остальная работа возложена на H5. H5 преобразует полученные данные в соответствующее отображение массива компонентов в соответствии со спецификацией:
<template>
<div>
<component
v-for="(item, index) in components"
:is="item.component"
:options="item.options"
:isEdit="false">
</component>
</div>
</template>
<script>
computed: {
components() {
return mapToComponents(this.list);
},
},
</script>
Из-за iframe нам также необходимо использовать postmessage для кросс-сорсинговой коммуникации.Для удобства использования мы сделали слой инкапсуляции (код см. в Self-Zan Catering):
export default class Messager {
constructor(win, targetOrigin) {
this.win = win;
this.targetOrigin = targetOrigin;
this.actions = {};
window.addEventListener('message', this.handleMessageListener, false);
}
handleMessageListener = (event) => {
// 我们能相信信息的发送者吗? (也许这个发送者和我们最初打开的不是同一个页面).
if (event.origin !== this.targetOrigin) {
console.warn(`${event.origin}不对应源${this.targetOrigin}`);
return;
}
if (!event.data || !event.data.type) {
return;
}
const { type } = event.data;
if (!this.actions[type]) {
console.warn(`${type}: missing listener`);
return;
}
this.actions[type](event.data.value);
};
on = (type, cb) => {
this.actions[type] = cb;
return this;
};
emit = (type, value) => {
this.win.postMessage({
type, value,
}, this.targetOrigin);
return this;
};
destroy() {
window.removeEventListener('message', this.handleMessageListener);
}
}
Исходя из этого, бизнес-сторона должна обращать внимание только на обработку сообщения.Например, компонент H5 может использовать следующее для получения обновлений данных с ПК:
this.messager = new Messager(window.parent, `${window.location.protocol}//mei.youzan.com`);
this.messager.on('pageChangeFromReact', (data) => {
...
});
Таким образом, через события, согласованные с обеих сторон, достаточно обрабатывать бизнес-логику отдельно.
Здесь нужно разобраться с одной деталью, потому что высота предварительного просмотра будет динамически изменяться, а ПК должен контролировать высоту внешнего вида, поэтому должен быть механизм для динамического получения высоты предварительного просмотра. .
// vue script
updated() {
this.$nextTick(() => {
const list = document.querySelectorAll('.preview .drag-box');
let total = 0;
list.forEach((item) => {
total += item.clientHeight;
});
this.messager.emit('vueStyleChange', { height: total });
}
}
// react script
this.messsager.on('vueStyleChange', (value) => {
const { height } = value;
height && (this.iframeElem.style.height = `${height}px`);
});
2.3 Реализация перетаскивания
Функция перетаскивания реализована через API перетаскивания HTML5. В этом требовании основной целью является достижение эффекта динамической сортировки компонентов в процессе перетаскивания. Вот несколько ключевых моментов, реализация которых может потребовать некоторых усилий:
- Вид автоматически прокручивается при перетаскивании вверх и вниз
- Перетащите результаты, чтобы синхронизировать изменения данных
- правильная анимация
В настоящее время в сообществе есть много зрелых библиотек, связанных с перетаскиванием, и мы выбираем vuedraggable. Причина тоже очень проста: с одной стороны, это позволяет избежать повторения создания колес, а с другой стороны, очень хорошо решает проблемы, о которых мы говорили выше.
vuedraggable очень хорошо инкапсулирован и очень прост в использовании.Инкапсулируйте динамические компоненты, о которых мы упоминали ранее, с помощью другого слоя перетаскиваемых компонентов:
<draggable
v-model="list"
:options="sortOptions"
@start="onDragStart"
@end="onDragEnd"
class="preview"
:class="{dragging: dragging}">
<div>
<component
v-for="(item, index) in components"
:is="item.component"
:options="item.options"
:isEdit="false">
</component>
</div>
</draggable>
const sortOptions = {
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
};
// vue script
computed: {
list: {
get() {
return get(this.designData, 'pageLayout') || [];
},
set(value) {
this.designData.pageLayout = value;
this.notifyReact();
},
},
components() {
return mapToComponents(this.list);
},
},
3. Резюме
На данный момент все конструкции готовы. Подводя итог, можно сказать, что совместное использование данных между компонентами на стороне ПК в основном осуществляется через контекст React; H5 и апплет отображаются через соответствующий компонентный массив сопоставления данных; основной задачей является достижение повторного использования логики стиля через iframe; унификация данных спецификации могут быть выполнены через сторонние пакеты npm.
Конечно, в дополнение к базовой архитектуре, есть еще много технических деталей, с которыми нужно разобраться, например, необходимость убедиться, что компонент предварительного просмотра не кликабельный и т. д. С этим нужно разобраться в фактической разработке.