mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-08-08 05:29:45 +08:00
feat(cli): switch to postmessage (#8500)
This commit is contained in:
parent
68c86bd637
commit
b22cbceed0
@ -2,28 +2,69 @@
|
|||||||
* 同步父窗口和 iframe 的 vue-router 状态
|
* 同步父窗口和 iframe 的 vue-router 状态
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { iframeReady, isMobile } from '.';
|
let queue = [];
|
||||||
|
let isIframeReady = false;
|
||||||
|
|
||||||
window.syncPath = function() {
|
function iframeReady(callback) {
|
||||||
const router = window.vueRouter;
|
if (isIframeReady) {
|
||||||
const isInIframe = window !== window.top;
|
callback();
|
||||||
const currentDir = router.history.current.path;
|
} else {
|
||||||
|
queue.push(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isInIframe) {
|
if (window.top === window) {
|
||||||
window.top.replacePath(currentDir);
|
window.addEventListener('message', (event) => {
|
||||||
} else if (!isMobile) {
|
if (event.data.type === 'iframeReady') {
|
||||||
const iframe = document.querySelector('iframe');
|
isIframeReady = true;
|
||||||
if (iframe) {
|
queue.forEach((callback) => callback());
|
||||||
iframeReady(iframe, () => {
|
queue = [];
|
||||||
iframe.contentWindow.replacePath(currentDir);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
} else {
|
||||||
|
window.top.postMessage({ type: 'iframeReady' }, '*');
|
||||||
|
}
|
||||||
|
|
||||||
window.replacePath = function(path = '') {
|
function getCurrentDir() {
|
||||||
// should preserve hash for anchor
|
const router = window.vueRouter;
|
||||||
if (window.vueRouter.currentRoute.path !== path) {
|
return router.history.current.path;
|
||||||
window.vueRouter.replace(path).catch(() => {});
|
}
|
||||||
|
|
||||||
|
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(() => {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -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 ua = navigator.userAgent.toLowerCase();
|
||||||
const isMobile = /ios|iphone|ipod|ipad|android/.test(ua);
|
const isMobile = /ios|iphone|ipod|ipad|android/.test(ua);
|
||||||
|
|
||||||
@ -27,4 +8,4 @@ export function decamelize(str, sep = '-') {
|
|||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export { isMobile, iframeReady };
|
export { isMobile };
|
||||||
|
@ -3,7 +3,7 @@ import VueRouter from 'vue-router';
|
|||||||
import { isMobile, decamelize } from '../common';
|
import { isMobile, decamelize } from '../common';
|
||||||
import { config, documents } from 'site-desktop-shared';
|
import { config, documents } from 'site-desktop-shared';
|
||||||
import { getLang, setDefaultLang } from '../common/locales';
|
import { getLang, setDefaultLang } from '../common/locales';
|
||||||
import '../common/iframe-router';
|
import { listenToSyncPath, syncPathToChild } from '../common/iframe-router';
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
location.replace('mobile.html' + location.hash);
|
location.replace('mobile.html' + location.hash);
|
||||||
@ -48,7 +48,7 @@ function getRoutes() {
|
|||||||
if (locales) {
|
if (locales) {
|
||||||
routes.push({
|
routes.push({
|
||||||
path: '*',
|
path: '*',
|
||||||
redirect: route => `/${getLangFromRoute(route)}/`,
|
redirect: (route) => `/${getLangFromRoute(route)}/`,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
routes.push({
|
routes.push({
|
||||||
@ -66,7 +66,7 @@ function getRoutes() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
names.forEach(name => {
|
names.forEach((name) => {
|
||||||
const { component, lang } = parseName(name);
|
const { component, lang } = parseName(name);
|
||||||
|
|
||||||
if (component === 'home') {
|
if (component === 'home') {
|
||||||
@ -113,7 +113,9 @@ export const router = new VueRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
Vue.nextTick(() => window.syncPath());
|
Vue.nextTick(syncPathToChild);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
listenToSyncPath(router);
|
||||||
|
|
||||||
window.vueRouter = router;
|
window.vueRouter = router;
|
||||||
|
@ -4,7 +4,7 @@ import DemoHome from './components/DemoHome';
|
|||||||
import { decamelize } from '../common';
|
import { decamelize } from '../common';
|
||||||
import { demos, config } from 'site-mobile-shared';
|
import { demos, config } from 'site-mobile-shared';
|
||||||
import { getLang, setDefaultLang } from '../common/locales';
|
import { getLang, setDefaultLang } from '../common/locales';
|
||||||
import '../common/iframe-router';
|
import { listenToSyncPath, syncPathToParent } from '../common/iframe-router';
|
||||||
|
|
||||||
const { locales, defaultLang } = config.site;
|
const { locales, defaultLang } = config.site;
|
||||||
|
|
||||||
@ -29,10 +29,10 @@ function getRoutes() {
|
|||||||
if (langs.length) {
|
if (langs.length) {
|
||||||
routes.push({
|
routes.push({
|
||||||
path: '*',
|
path: '*',
|
||||||
redirect: route => `/${getLangFromRoute(route)}/`,
|
redirect: (route) => `/${getLangFromRoute(route)}/`,
|
||||||
});
|
});
|
||||||
|
|
||||||
langs.forEach(lang => {
|
langs.forEach((lang) => {
|
||||||
routes.push({
|
routes.push({
|
||||||
path: `/${lang}`,
|
path: `/${lang}`,
|
||||||
component: DemoHome,
|
component: DemoHome,
|
||||||
@ -51,11 +51,11 @@ function getRoutes() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
names.forEach(name => {
|
names.forEach((name) => {
|
||||||
const component = decamelize(name);
|
const component = decamelize(name);
|
||||||
|
|
||||||
if (langs.length) {
|
if (langs.length) {
|
||||||
langs.forEach(lang => {
|
langs.forEach((lang) => {
|
||||||
routes.push({
|
routes.push({
|
||||||
name: `${lang}/${component}`,
|
name: `${lang}/${component}`,
|
||||||
path: `/${lang}/${component}`,
|
path: `/${lang}/${component}`,
|
||||||
@ -91,8 +91,10 @@ export const router = new VueRouter({
|
|||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
if (!router.currentRoute.redirectedFrom) {
|
if (!router.currentRoute.redirectedFrom) {
|
||||||
Vue.nextTick(window.syncPath);
|
syncPathToParent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
listenToSyncPath(router);
|
||||||
|
|
||||||
window.vueRouter = router;
|
window.vueRouter = router;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user