Changing body styles in vue router

做~自己de王妃 提交于 2021-01-20 15:27:31

问题


I'm using Vue router with two pages:

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

This works fine, except that each of my components has different body styling:

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>

My goal is to have these two pages have different background styles (eventually with a transition between them). But at the moment when I go to the home route (with the red background), then click the intro route, the background colour stays red (I want it to change to pink).

Edit: 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:


I got it working with the lifecycle hook beforeCreate and a global stylesheet. In global.css:

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

In the <script> section of HomeView.vue:

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

And similar in IntroView.vue.




回答2:


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,
  }
},

Another fairly simple solution, add it to your base App.vue file. The to.name can be replaced with to.meta.class or similar for something more specific. This is a nice do it once and it works forever type solution though.




回答3:


Alternatively you can use this

  • vue-body-class NPM
  • vue-body-class GitHub

It allows to control your page body classes with vue-router. Wrote this when faced the similar issue. It also refers to Add a class to body when component is clicked?




回答4:


If the class is view specific, may be this will help

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');
},

Move the methods section to a mixin and then the code can be DRY.




回答5:


I ran into an issue when I wanted to modify the styles of the html and body tags along with the #app container on specific routes and what I found out is that for various reasons, this can be quite complicated.

After reading through:

  • @Saurabh's answer on another relative question: https://stackoverflow.com/a/42336509/2110294
  • @Mteuahasan's comment above regarding Evan You's suggestion
  • @GluePear's / OP's answer to this question: https://stackoverflow.com/a/44544595/2110294
  • Sass style inclusion headaches: https://github.com/vuejs/vue-loader/issues/110#issuecomment-167376086

In your App.vue (could be considered as the centralised state):

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

So for the route / you get the red style and for all other routes the pink style is applied.

The handleStyles logic could have been dealt with by the beforeCreated hook however in my case, this would only affect the html and body styles but the #app element where the router view is rendered into would only available when the dom has been mounted so I think that it is a slightly more extensible solution.




回答6:


You can also do it directly in the router file using the afterEach hook:

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 hook documentation

to is a route object which contains the route name (if named), path, etc. Documentation for all the props




回答7:


You can use scoped attribute in the style element. Then the style will be limited only to that vue file.

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>


来源:https://stackoverflow.com/questions/44541872/changing-body-styles-in-vue-router

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!