feat(cli): switch to postmessage (#8500)

This commit is contained in:
neverland 2021-04-10 17:21:59 +08:00 committed by GitHub
parent 68c86bd637
commit b22cbceed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 50 deletions

View File

@ -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(() => {});
}
});
}

View File

@ -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 };

View File

@ -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;

View File

@ -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;