How to Build a Cross‑Platform Shop Builder with React, Vue, and Iframe Communication
This article presents a technical design for a multi‑platform shop‑decoration system that shares data via React context, reuses Vue‑based preview components through an iframe, synchronizes updates with a postMessage wrapper, and implements drag‑and‑drop using vuedraggable, providing a scalable solution for PC, H5, and mini‑programs.
Background
Shop decoration is a core feature for e‑commerce platforms, allowing merchants to design pages via drag‑and‑drop and publish them to PC, H5 and mini‑programs. In Youzan Meiye the PC editor is built with React, the H5 preview with Vue, and the mini‑program with native WeChat development.
Design challenges
How to manage data flow across three data‑driven view layers?
How to reuse business components written in three different tech stacks?
How to keep a unified data format for PC, H5 and mini‑program?
How to add new components with low cost?
Solution overview
We adopt a data‑driven architecture that shares a single context on the PC side, extracts a common npm package that defines component schemas, and reuses the H5 rendering logic through an iframe‑based preview component. Communication between the iframe and the parent page is handled by a lightweight postMessage wrapper.
React context for PC
The CustomPage component creates a React context containing page and pageChange. Child components PageLeft, PageView and PageRight consume the context to read and update the shared page data.
class CustomPage 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>
);
}
}Cross‑platform preview via iframe
PageViewrenders an iframe that loads the H5 page. The iframe receives the page data through the context and sends size updates back to the PC editor.
class PageView extends Component {
render() {
const { page = {} } = this.props;
const { pageInfo = {}, pageLayout = [] } = page;
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>
);
}
}Message wrapper
The Messager class registers a message listener, validates the origin, and dispatches events to registered callbacks. It provides on and emit methods for both sides.
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} does not match ${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);
}
}Drag‑and‑drop in Vue
The vuedraggable component binds the component list to v-model and updates the shared layout through a computed getter/setter.
<draggable v-model="list" :options="sortOptions"
@start="onDragStart" @end="onDragEnd"
class="preview" :class="{dragging: dragging}">
<component v-for="(item, index) in components"
:is="item.component"
:options="item.options"
:isEdit="false"></component>
</draggable>
const sortOptions = {
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
};Shared npm package for data schema
A dedicated npm package defines the unified component schema (e.g., position constants) that is consumed by PC, H5 and mini‑program implementations. Adding a new component only requires updating this package.
export const position = {
LEFT: 0,
CENTER: 1,
RIGHT: 2,
};
export const positionMap = [
{ value: position.LEFT, name: '居左' },
{ value: position.CENTER, name: '居中' },
{ value: position.RIGHT, name: '居右' },
];Result
The final architecture consists of:
React context on PC for shared page data.
A shared npm package that describes component fields and their meanings.
An iframe‑based preview that reuses the Vue H5 rendering logic.
The Messager wrapper for synchronized updates between PC and H5.
Vue vuedraggable for drag‑and‑drop sorting.
This design enables low‑cost extension of new business components while keeping data format consistent across PC, H5 and mini‑programs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Youzan Coder
Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
