【问题标题】:Changing body styles in vue router在 Vue 路由器中更改正文样式
【发布时间】:2017-11-16 10:25:55
【问题描述】:

我使用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>

【问题讨论】:

  • 您可以使用 $router 对象来为您的主体添加一个类并在全局工作表中设置它的样式?
  • 所有样式将在全球范围内可用。所以你的解决方案就是上面那个
  • 编辑了我的问题以包括我的index.html。当body 在应用程序之外时,我看不到如何向它添加一个类。
  • 我测试了你的代码,这工作正常...你没有错误吗?是否应用了粉红色背景但可能被红色覆盖? (这没有理由发生)
  • Evan You 建议更改身体等级:The easy way is just setting document.body.className in a global beforeEach hook. 这个解决方案已有两年历史,但我猜仍然可以使用来自:forum-archive.vuejs.org/topic/656/…

标签: javascript vue.js vue-router vue-loader


【解决方案1】:

我让它与lifecycle hook beforeCreate 和一个全局样式表一起工作。在global.css:

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

HomeView.vue&lt;script&gt; 部分:

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

IntroView.vue中的类似。

【讨论】:

  • 一旦将类添加到正文,可能在另一个视图中需要删除,我们应该使用destroyed生命周期挂钩吗?
  • 你节省了我的时间!
【解决方案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,
  }
},

另一个相当简单的解决方案,将它添加到您的基础 App.vue 文件中。 to.name 可以替换为 to.meta.class 或类似的更具体的东西。这是一个很好的一次性解决方案,但它永远有效。

【讨论】:

  • 这是一个很好的解决方案,并且似乎比公认的解决方案更快地附加类名。唯一的缺点是它仅在实际通过路由导航时加载类名,即不在初始页面加载时(因此,如果您刷新单个页面或直接访问某个页面,则不会附加类名。)不确定是否有除了将它与所选答案中详述的方法结合起来之外,还有什么方法可以修改它以解决这个问题?
  • 向观察者添加了立即标志,但在这种情况下将没有定义'from'路由,因此可以跳过删除类。
  • 不错(更好)的答案。顺便说一句,您可以使用document.body 来获取body 元素。它永远可用(从 IE4/1997 开始)。
【解决方案3】:

你也可以使用这个

它允许使用 vue-router 控制您的页面正文类。 遇到类似问题时写了这个。 也指Add a class to body when component is clicked?

【讨论】:

    【解决方案4】:

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

    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 部分移动到mixin,然后代码就可以DRY了。

    【讨论】:

      【解决方案5】:

      当我想修改 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 已安装时可用,因此我认为它是一种可扩展性稍强的解决方案。

      【讨论】:

        【解决方案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 hook documentation

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

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            【解决方案8】:

            您可以在样式元素中使用作用域属性。那么样式将仅限于该 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 元素,如 body、html 等
            猜你喜欢
            • 2021-08-01
            • 1970-01-01
            • 2020-05-21
            • 2019-03-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-20
            • 2021-05-01
            相关资源
            最近更新 更多