обновить исходный URL-адрес маршрутизатора при запуске внутри тегов iframe / object - PullRequest
6 голосов
/ 15 октября 2019

В настоящее время я визуализирую приложения Vue внутри тегов объектов (также может работать iframe) приложения Vue контейнера / мастера. Сначала я настраиваю файловый сервер, обслуживающий этот контейнер или запрошенное вспомогательное приложение для рендеринга внутри div.

Для простоты я покажу только требуемую маршрутизацию моего сервера Node / Express

// serve the sub-app on demand
router.get('/subApps/:appName', function(req, res) {
    res.sendFile(path.resolve(__dirname, `../apps/${req.params.appName}/index.html`);
});

// always render the app container if no sub-app was requested
router.get('*', function(req, res) {
    res.sendFile(path.resolve(__dirname, '../base/index.html'));
});

Контейнер моего приложения / мастер-приложение Vue находится внутри файла представления, отображаемого на /apps/:appName, запрашивает это суб-приложение и упаковывает его в теги объектов

  document.getElementById("customAppContainer").innerHTML = `<object style="width: 100%; height:100%;" data="http://localhost:3000/subApps/${appKey}"></object>`;

Этот подход работает хорошо, но визуализированный суб-приложениеПриложение использует URL-адрес запуска http://localhost:3000/subApps/app-one, хотя должно использовать URL-адрес http://localhost:3000/apps/app-one. Когда подпрограмма загружает экземпляр маршрутизатора, я должен изменить начальный URL-адрес с URL-адреса iframe на URL-адрес браузера (родительский).

Я думал о том, чтобы исправить это с помощью history.replaceState

const router = new Router({ ... });

router.afterEach((to, from) => {
    localStorage.subAppRouteUpdate = to.path;
});

if (window.location !== window.parent.location) {
    const browserUrl = top.location.href;
    history.replaceState(null, null, browserUrl);
}

export default router;

Почему я хочу это сделать? App.vue в главном приложении должно добавить маршрут к вспомогательному приложению в URL браузера. При таком подходе можно обновлять URL-адрес браузера во время навигации внутри подпрограммы. Я достигаю этого, сохраняя URL-адрес суб-приложения в локальном хранилище и слушая изменения локального хранилища на стороне главного приложения. Поэтому файл App.vue использует этот код

<script>
export default {
  created() {
    window.addEventListener("storage", () => {
      const fullRoute = this.$router.currentRoute.fullPath;
      const routeSegments = fullRoute.split("/");
      const appsIndex = routeSegments.indexOf("apps");
      const newBaseUrlSegments = routeSegments.slice(0, appsIndex + 2);
      const newBaseUrl = newBaseUrlSegments.join("/");
      const subAppRoute = localStorage.subAppRouteUpdate;
      const updatedUrl = newBaseUrl.concat(subAppRoute);
      history.replaceState(null, null, updatedUrl);
    });
  }
};
</script>

, чтобы включить маршрутизацию при использовании IFrames. Это почти работает, вот что я получаю

enter image description here

К сожалению, бывает так, что при вызове / подпрограммы URL браузера обновляется до

http://localhost:3000/apps/app-one/apps/app-one

хотя я ожидаю

http://localhost:3000/apps/app-one/


Воспроизведение:

Я создал репозиторий для воспроизведения / тестирования. Кто-нибудь знает, что может быть не так или как исправить это обновление URL-адреса?


Обновление:

Я думаю, что ошибка происходит, потому что в маршрутизаторе .js из подпапки Я запускаю этот код

if (window.location !== window.parent.location) {
    const browserUrl = top.location.href;
    history.replaceState(null, null, browserUrl);
}

router.afterEach((to, from) => {
    console.log({ urlToAppend: to.path });
    localStorage.subAppRouteUpdate = to.path;
});

Функция replaceState обновит URL IFrame с /subApps/app-one до правильного URL браузера /apps/app-one. К сожалению, это вызовет событие afterEach и to.path приведет к /apps/app-one, хотя должно быть /.

Если URL будет /apps/app-one/users/create, то после каждого события должно срабатывать, конечно, /users/create.

Но я так и не понял, как исправить это первое запущенное событие.

1 Ответ

2 голосов
/ 18 октября 2019

Это может быть немного хакерское решение, но оно работает для меня. Просто убедитесь, что текущий путь URL не равен to.path в случае, если событие вызвано дважды

router.afterEach((to, from) => {
    console.log({ urlToAppend: to.path });
    if (router.currentRoute.path !== to.path) {
        localStorage.subAppRouteUpdate = to.path;
    }
});

ОБНОВЛЕНИЕ

В base/src/App.vue вПриемник событий хранилища перед конкатенацией суб-маршрута к базовому маршруту, вы не проверяете возможные дубликаты. Это исправление должно помочь

window.addEventListener("storage", () => {
      const fullRoute = this.$router.currentRoute.fullPath;
      const routeSegments = fullRoute.split("/");
      const appsIndex = routeSegments.indexOf("apps");
      const newBaseUrlSegments = routeSegments.slice(0, appsIndex + 2);
      const newBaseUrl = newBaseUrlSegments.join("/");
      const subAppRoute = localStorage.subAppRouteUpdate;
      if (subAppRoute.startsWith(newBaseUrl)) {
        history.replaceState(null, null, newBaseUrl);
      } else {
        const updatedUrl = newBaseUrl.concat(subAppRoute);
        history.replaceState(null, null, updatedUrl);
      }
    });

И router.afterEach должен выглядеть следующим образом для перехода к subRoutes, которые определены в маршрутизаторе app-one:

router.afterEach((to, from) => {
        const newPath = '/' + to.path.split('/').pop();
        const matchingRoutes = router.options.routes.filter(r => r.path === newPath);
        const isPathInRoutes = matchingRoutes.length > 0;
        if (router.currentRoute.path !== newPath && isPathInRoutes) {
            router.push(newPath);
            localStorage.subAppRouteUpdate = newPath;
        } else {
            localStorage.subAppRouteUpdate = to.path;
        }
});

Если вы хотите, чтобы первая страница былаотображается по умолчанию, когда пользователь переходит на http://localhost:3000/apps/app-one, вы можете проверить, равна ли последняя часть введенного URL базовому маршруту подпрограммы (/app-one) и действительно ли он переходит к маршруту страницы по умолчанию (/):

router.afterEach((to, from) => {
    let newPath = '/' + to.path.split('/').pop();
    const matchingRoutes = router.options.routes.filter(r => r.path === newPath);
    const isPathInRoutes = matchingRoutes.length > 0;
    if (newPath === router.history.base || !isPathInRoutes) {
        newPath = '/';
    }
    if (router.currentRoute.path !== newPath) {
            router.push(newPath);
            localStorage.subAppRouteUpdate = newPath;
    } else {
            localStorage.subAppRouteUpdate = to.path;
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...