Изменение стилей кузова в маршрутизаторе vue

Я использую маршрутизатор Vue с двумя страницами:

let routes = [
    {
        path: '/',
        component: require('./components/HomeView.vue')
    },
    {
        path: '/intro',
        component: require('./components/IntroView.vue')
    }
]

Это прекрасно работает, за исключением того, что каждый из моих компонентов имеет разные стили кузова:

HomeView.vue:

<template>
    <p>This is the home page!</p>
</template>

<script>
    export default {

    }
</script>

<style>
    body {
        background: red;
    }
</style>

IntroView.vue:

<template>
    <div>
        <h1>Introduction</h1>
    </div>
</template>

<script>
    export default {

    }
</script>

<style>
    body {
        background: pink;
    }
</style>

Моя цель состоит в том, чтобы эти две страницы имели разные стили фона (в конечном итоге с переходом между ними). Но в тот момент, когда я иду на home маршрут (с red фоном), затем нажимаю на intro маршрут, цвет фона остается red (я хочу, чтобы он изменился на pink).

Изменение: index.html:

  <body>
    <div id="app">
        <router-link to="/" exact>Home</router-link>
        <router-link to="/intro">Introduction</router-link>
        <router-view></router-view>
    </div>
    <script src="/dist/build.js"></script>
  </body>

Ответ 1

Я работал с хуком жизненного цикла beforeCreate и глобальной beforeCreate стилей. В global.css:

body.home {
    background: red;
}
body.intro {
    background: pink;
}

В разделе <script> HomeView.vue:

export default {
    beforeCreate: function() {
        document.body.className = 'home';
    }
}

И похоже на IntroView.vue.

Ответ 3

Я столкнулся с проблемой, когда захотел изменить стили тегов html и body вместе с контейнером #app на определенных маршрутах, и выяснил, что по разным причинам это может быть довольно сложно.

После прочтения:

В вашем App.vue (может рассматриваться как централизованное состояние):

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    name: 'my-app',
    methods: {
      handleStyles () {
        // Red style to the body tag for the home page
        if (['/'].includes(this.$route.path)) document.body.className = 'bg-red'
        // Pink style to the body tag for all other pages
        else if (document.body.classList.contains('bg-red')) document.body.className = 'bg-pink'
      }
    },
    // Handle styles when the app is initially loaded
    mounted () {
      this.handleStyles()
    },
    // Handle styles when the route changes
    watch: {
      '$route' () {
        this.handleStyles()
      }
    }
  }
</script>

<style>
  .bg-red {
    background: red;
  }
  .bg-pink {
    background: pink;
  }
</style>

Таким образом, для маршрута / вы получаете красный стиль, а для всех остальных маршрутов применяется розовый стиль.

Логика handleStyles могла бы обрабатываться beforeCreated однако в моем случае это затронет только стили html и body но элемент #app котором отображается представление маршрутизатора, будет доступен только после монтирования dom, так что я думаю, что это немного более расширяемое решение.

Ответ 4

watch: {
  $route: {
    handler (to, from) {
      const body = document.getElementsByTagName('body')[0];
      if (from !== undefined) {
        body.classList.remove('page--' + from.name.toLowerCase());
      }
      body.classList.add('page--' + to.name.toLowerCase());
    },
    immediate: true,
  }
},

Еще одно довольно простое решение, добавьте его в базовый файл App.vue. To.name может быть заменено to.meta.class или аналогичным для чего-то более конкретного. Это хорошо сделать это один раз, и это работает навсегда.

Ответ 5

Если класс является определенным видом, может быть, это поможет

methods: {
  toggleBodyClass(addRemoveClass, className) {
    const el = document.body;

    if (addRemoveClass === 'addClass') {
      el.classList.add(className);
    } else {
      el.classList.remove(className);
    }
  },
},
mounted() {
  this.toggleBodyClass('addClass', 'mb-0');
},
destroyed() {
  this.toggleBodyClass('removeClass', 'mb-0');
},

Переместите раздел methods в миксин, и тогда код может быть СУХИМ.

Ответ 6

Вы также можете сделать это прямо в файле маршрутизатора, используя хук afterEach:

mainRouter.afterEach((to) => {
    if (["dialogs", "snippets"].includes(to.name)) {
        document.body.style.backgroundColor = "#F7F7F7";
        // or document.body.classList.add(className);
    } else {
        document.body.style.backgroundColor = "#FFFFFF";
        // or document.body.classList.remove(className);
    }
});

afterEach документация о afterEach

to - это объект маршрута, который содержит имя маршрута (если он назван), путь и т.д. Документация для всех реквизитов

Ответ 7

Вы можете использовать атрибут scoped в элементе style. Тогда стиль будет ограничен только этим файлом VUE.

HomeView.vue:

<template>
    <p>This is the home page!</p>
</template>

<script>
    export default {

    }
</script>

<style scoped>
    body {
        background: red;
    }
</style>

IntroView.vue:

<template>
    <div>
        <h1>Introduction</h1>
    </div>
</template>

<script>
    export default {

    }
</script>

<style scoped>
    body {
        background: pink;
    }
</style>