diff --git a/packages/vant-cli/site/common/iframe-router.js b/packages/vant-cli/site/common/iframe-router.js index 703beec2b..6e49bf636 100644 --- a/packages/vant-cli/site/common/iframe-router.js +++ b/packages/vant-cli/site/common/iframe-router.js @@ -2,28 +2,69 @@ * 同步父窗口和 iframe 的 vue-router 状态 */ -import { iframeReady, isMobile } from '.'; +let queue = []; +let isIframeReady = false; -window.syncPath = function() { - const router = window.vueRouter; - const isInIframe = window !== window.top; - const currentDir = router.history.current.path; +function iframeReady(callback) { + if (isIframeReady) { + callback(); + } else { + queue.push(callback); + } +} - if (isInIframe) { - window.top.replacePath(currentDir); - } else if (!isMobile) { - const iframe = document.querySelector('iframe'); - if (iframe) { - iframeReady(iframe, () => { - iframe.contentWindow.replacePath(currentDir); - }); +if (window.top === window) { + window.addEventListener('message', (event) => { + if (event.data.type === 'iframeReady') { + isIframeReady = true; + queue.forEach((callback) => callback()); + queue = []; } - } -}; + }); +} else { + window.top.postMessage({ type: 'iframeReady' }, '*'); +} -window.replacePath = function(path = '') { - // should preserve hash for anchor - if (window.vueRouter.currentRoute.path !== path) { - window.vueRouter.replace(path).catch(() => {}); +function getCurrentDir() { + const router = window.vueRouter; + return router.history.current.path; +} + +export function syncPathToParent() { + window.top.postMessage( + { + type: 'replacePath', + value: getCurrentDir(), + }, + '*' + ); +} + +export function syncPathToChild() { + const iframe = document.querySelector('iframe'); + if (iframe) { + iframeReady(() => { + iframe.contentWindow.postMessage( + { + type: 'replacePath', + value: getCurrentDir(), + }, + '*' + ); + }); } -}; +} + +export function listenToSyncPath(router) { + window.addEventListener('message', (event) => { + if (event.data?.type !== 'replacePath') { + return; + } + + const path = event.data?.value || ''; + // should preserve hash for anchor + if (router.currentRoute.path !== path) { + router.replace(path).catch(() => {}); + } + }); +} diff --git a/packages/vant-cli/site/common/index.js b/packages/vant-cli/site/common/index.js index 38d345ea8..0da499ee8 100644 --- a/packages/vant-cli/site/common/index.js +++ b/packages/vant-cli/site/common/index.js @@ -1,22 +1,3 @@ -function iframeReady(iframe, callback) { - const doc = iframe.contentDocument || iframe.contentWindow.document; - const interval = () => { - if (iframe.contentWindow.replacePath) { - callback(); - } else { - setTimeout(() => { - interval(); - }, 50); - } - }; - - if (doc.readyState === 'complete') { - interval(); - } else { - iframe.onload = interval; - } -} - const ua = navigator.userAgent.toLowerCase(); const isMobile = /ios|iphone|ipod|ipad|android/.test(ua); @@ -27,4 +8,4 @@ export function decamelize(str, sep = '-') { .toLowerCase(); } -export { isMobile, iframeReady }; +export { isMobile }; diff --git a/packages/vant-cli/site/desktop/router.js b/packages/vant-cli/site/desktop/router.js index a55e60a9a..38d3e5885 100644 --- a/packages/vant-cli/site/desktop/router.js +++ b/packages/vant-cli/site/desktop/router.js @@ -3,7 +3,7 @@ import VueRouter from 'vue-router'; import { isMobile, decamelize } from '../common'; import { config, documents } from 'site-desktop-shared'; import { getLang, setDefaultLang } from '../common/locales'; -import '../common/iframe-router'; +import { listenToSyncPath, syncPathToChild } from '../common/iframe-router'; if (isMobile) { location.replace('mobile.html' + location.hash); @@ -48,7 +48,7 @@ function getRoutes() { if (locales) { routes.push({ path: '*', - redirect: route => `/${getLangFromRoute(route)}/`, + redirect: (route) => `/${getLangFromRoute(route)}/`, }); } else { routes.push({ @@ -66,7 +66,7 @@ function getRoutes() { }); } - names.forEach(name => { + names.forEach((name) => { const { component, lang } = parseName(name); if (component === 'home') { @@ -113,7 +113,9 @@ export const router = new VueRouter({ }); router.afterEach(() => { - Vue.nextTick(() => window.syncPath()); + Vue.nextTick(syncPathToChild); }); +listenToSyncPath(router); + window.vueRouter = router; diff --git a/packages/vant-cli/site/mobile/router.js b/packages/vant-cli/site/mobile/router.js index c3f1d9fa0..3433e87f8 100644 --- a/packages/vant-cli/site/mobile/router.js +++ b/packages/vant-cli/site/mobile/router.js @@ -4,7 +4,7 @@ import DemoHome from './components/DemoHome'; import { decamelize } from '../common'; import { demos, config } from 'site-mobile-shared'; import { getLang, setDefaultLang } from '../common/locales'; -import '../common/iframe-router'; +import { listenToSyncPath, syncPathToParent } from '../common/iframe-router'; const { locales, defaultLang } = config.site; @@ -29,10 +29,10 @@ function getRoutes() { if (langs.length) { routes.push({ path: '*', - redirect: route => `/${getLangFromRoute(route)}/`, + redirect: (route) => `/${getLangFromRoute(route)}/`, }); - langs.forEach(lang => { + langs.forEach((lang) => { routes.push({ path: `/${lang}`, component: DemoHome, @@ -51,11 +51,11 @@ function getRoutes() { }); } - names.forEach(name => { + names.forEach((name) => { const component = decamelize(name); if (langs.length) { - langs.forEach(lang => { + langs.forEach((lang) => { routes.push({ name: `${lang}/${component}`, path: `/${lang}/${component}`, @@ -91,8 +91,10 @@ export const router = new VueRouter({ router.afterEach(() => { if (!router.currentRoute.redirectedFrom) { - Vue.nextTick(window.syncPath); + syncPathToParent(); } }); +listenToSyncPath(router); + window.vueRouter = router;