在 vue 路由器中更改主体样式

Changing body styles in vue router

我正在使用 Vue router 两个页面:

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>

我使用 lifecycle hook beforeCreate 和全局样式表得到了它。在 global.css:

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

HomeView.vue<script> 部分:

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

IntroView.vue 类似。

或者你可以使用这个

它允许使用 vue-router 控制您的页面主体 类。 遇到类似问题时写了这个。 也指

如果 class 是视图特定的,这可能会有所帮助

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 部分移动到混入,然后代码可以是 DRY。

当我想修改 htmlbody 标签的样式以及特定路由上的 #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 挂钩处理,但在我的情况下,这只会影响 htmlbody 样式,但 #app 渲染路由器视图的元素只有在安装了 dom 后才可用,所以我认为这是一个稍微更可扩展的解决方案。

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 或类似内容以获得更具体的内容。这是一次很好的解决方案,但它永远有效。

您也可以使用 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 hook documentation

to 是一个路由对象,其中包含路由名称(如果已命名)、路径等。Documentation for all the props

您可以在 style 元素中使用 scoped 属性。然后样式将仅限于该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>

最佳答案正确,但需要一些优化。
因为当 刷新 该页面时,该答案不起作用。原因是 dom 在设置你想要的样式时没有加载完成。 所以,更好的解决方案是:

beforeCreate() {
  this.$nextTick(() => {
    document.querySelector('body').style.backgroundColor = '#f2f2f2'
  })
},
beforeDestroy() {
  document.querySelector('body').style.backgroundColor = ''
},

通过在 this.$nextTick 中包装样式设置处理程序,将在加载 dom 时设置样式。所以你可以在刷新页面时获得正确的样式