在 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。
当我想修改 html
和 body
标签的样式以及特定路由上的 #app
容器时,我 运行 遇到了问题发现由于各种原因,这可能相当复杂。
看完后:
- @Saurabh 对另一个相关问题的回答:
- @Mteuahasan 上面关于 Evan You 的建议的评论
- @GluePear/OP 对这个问题的回答:
- Sass 样式包含问题:https://github.com/vuejs/vue-loader/issues/110#issuecomment-167376086
在你的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 后才可用,所以我认为这是一个稍微更可扩展的解决方案。
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);
}
});
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 时设置样式。所以你可以在刷新页面时获得正确的样式
我正在使用 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。
当我想修改 html
和 body
标签的样式以及特定路由上的 #app
容器时,我 运行 遇到了问题发现由于各种原因,这可能相当复杂。
看完后:
- @Saurabh 对另一个相关问题的回答:
- @Mteuahasan 上面关于 Evan You 的建议的评论
- @GluePear/OP 对这个问题的回答:
- Sass 样式包含问题:https://github.com/vuejs/vue-loader/issues/110#issuecomment-167376086
在你的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 后才可用,所以我认为这是一个稍微更可扩展的解决方案。
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);
}
});
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 时设置样式。所以你可以在刷新页面时获得正确的样式