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.

Youzan Coder
Youzan Coder
Youzan Coder
How to Build a Cross‑Platform Shop Builder with React, Vue, and Iframe Communication

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

PageView

renders 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ReactVueDrag-and-DropiframepostMessageshop builder
Youzan Coder
Written by

Youzan Coder

Official Youzan tech channel, delivering technical insights and occasional daily updates from the Youzan tech team.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.