限制滚动到内容区域

Limit Scrolling to Content Area

问题:

我无法将滚动限制在典型 Vue 3 SPA 的内容区域(滚动条不应延伸到页眉和页脚区域)。页眉和页脚块与 Bootstrap fixed-topfixed-bottom 类 一起放置。在所附图片中有点难以看到,但当前内容区域延伸到页眉和页脚后面。页眉和页脚是从 Bootstrap 组件库构建的。我可以使用填充修复内容可见性,但这并不能解决溢出(滚动条)问题。

采取的行动

对于类似的问题,我尝试了很多解决方案,但这些解决方案通常适用于早期版本的 Vue 和 Bootstrap,但似乎对我不起作用。我能够在 vanilla html 和 Bootstrap 中生成我想要的布局——似乎是 Vue 3 注入过程让我感到困惑。我已经尝试将布局应用于 index.html 和 App.vue 但没有成功(同时尝试 Bootstrap 类 和香草 css)。 Bootstrap 依赖项似乎工作正常,所以我认为这不是问题所在(Bootstrap 5 而不是 Bootstrap-Vue)。

期望的结果:

限制滚动到内容区域,同时保持页眉和页脚导航栏固定在它们的位置(并且始终可见)。

环境

代码片段用于提高可读性(不会 运行 到位)。以下代码已删除所有(或几乎所有)放置尝试,因为它们不起作用。

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="../public/favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <!--    <script>window.scrollTo(0,1) // this is meant to hide the address bar in mobile Safari on page load.</script>-->
  </head>
  <body>
    <noscript>
      <strong>The <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>

    <div id="app"></div>
    <!-- built files are auto injected here -->
  </body>
</html>

App.vue

<template>
  <div id="wrapper" class="m-1">
    <div id="header_area">
      <Header/>
    </div>
    <div id="content_area">
      <span class="page-title">{{ title }}</span>
      <hr class="border-secondary">
      <span class="page-content">{{ content }}</span>
      <router-view @page-data="updatePageName($event)"/>
    </div>
    <div id="footer_area">
      <Footer/>
    </div>
  </div>
</template>

<script>
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'

export default {
  data() {
    return {
    title: "home",
    content: ""
    }
  },
  components: {
    Header,
    Footer,
  },
  methods: {
    updatePageName: function(event) {
      this.title = event.title;
      this.content = event.content;
    }
  }
};
</script>

<style>
  @import'~bootstrap/dist/css/bootstrap.css';
  @import "./assets/main.css";
</style>

Header.vue(部分)

<template>
  <div>
    <nav class="Header navbar navbar-expand-sm navbar-dark bg-dark border-bottom border-4 fixed-top" aria-label="Header Bar">
      <div class="container-fluid">
        <router-link to="/"><span class="navbar-brand">brand</span>  </router-link>
        <button class="navbar-toggler btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#Navbar" aria-controls="Navbar" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="Navbar">
          <ul class="navbar-nav me-auto mb-2 mb-sm-0">
            <li class="nav-item dropdown">
              <router-link to=""><a class="nav-link dropdown-toggle" id="dropdown01" data-bs-toggle="dropdown" aria-expanded="false">pages</a></router-link>
              <ul class="dropdown-menu bg-dark" aria-labelledby="dropdown01" id="dave">
              
              [snip]

main.css

@charset "utf-8";

@font-face {
    font-family: 'Lato-Light';
    src: local('Lato-Light'), url('Lato-Light.ttf') format("truetype");
}

:root {
    --background: #191919;
    --dark: #000000;
    --grey1: #111111;
    --grey2: #222222;
    --grey3: #333333;
    --grey4: #444444;
    --grey5: #555555;
    --grey6: #666666;
    --grey7: #777777;
    --grey8: #888888;
    --grey9: #999999;
    --light: #FFFFFF;
}


html, body {
    background-color: var(--dark) !important;
    color: var(--light) !important;
}

a {
    color: var(--bs-secondary) !important;
    text-decoration: none;
}

body {
    font-family: Lato-Light, sans-serif;
    font-size: 0.9em;
}

button {
    padding: 1px;
}

input {
    border: solid 1px var(--grey9);
    border-radius: 5px;
    box-sizing: border-box;
    padding: 5px;
}

li {
    float: left;
    margin: 0 5px;
    padding: 0 2px;
    text-align: start;
}

ul {
    list-style-type: none;
    padding: 0;
}

.dropdown-item {
    border: solid 1px var(--bs-dark);
    color: var(--bs-secondary) !Important;
    /*font-size: 0.9rem;*/
    width: 94%;
}

.dropdown-item:hover {
    background-color: var(--bs-dark) !important;
    border: solid 1px var(--bs-secondary);
    border-radius: 5px;
    width: 94%;
}

.dropdown-menu {
    background-color: var(--bs-dark) !important;
    border: solid 1px var(--bs-dark) !important;
    color: var(--bs-secondary) !Important;
    /*font-size: 0.9rem !important;*/
}

.dropdown-submenu {
    position: relative;
}

.dropdown-submenu .dropdown-menu {
    border: solid 1px var(--bs-dark) !important;
    color: var(--bs-secondary) !Important;
    /*font-size: 0.9rem !important;*/
    left: 100%;
    top: 0;
}

.dropdown-toggle::after {
    display: none;
}

.navbar {
    border-bottom-color: var(--dark) !important;
    border-top-color: var(--dark) !important;
    margin-bottom: 0;
}

.navbar-brand {
    border: solid 1px var(--bs-dark);
    border-radius: 5px;
    color: var(--bs-secondary) !important;
    padding: 5px;
}

.navbar-brand:hover {
    border: solid 1px var(--bs-secondary);
    border-radius: 5px;
}

.nav-link {
    background-color: var(--bs-dark) !important;
    border: solid 1px var(--bs-dark);
    border-radius: 5px;
    color: var(--bs-secondary) !important;
}

.nav-link:hover {
    border: solid 1px var(--bs-secondary);
    border-radius: 5px;
}

.nav-link.dropdown-toggle {
    padding: 8px;
}

.navbar-nav li:hover > ul.dropdown-menu {
    border: solid 1px var(--grey5) !important;
    color: var(--bs-secondary) !Important;
    display: block;
}

.page-title {
    color: var(--grey5);
    font-size: 2rem !important;
    text-align: left !important;
}

.page-content {

}

.selected {
    border-color: lime !important;
}

#app {

}

#header_area {

}

#content_area {

}

#footer_area {

}


#Footer {
     font-size: 0.9em;
}


:focus {
    border-color: var(--dark);
    box-shadow: none;
    outline: none;
}

这就是我如何使 CSS 网格规范起作用的方法。 对于我的情况,在 index.html 中向 <html><body> 添加样式很重要, 但可能不是必需的。可能也不需要将 !Important 分配给网格元素,但这样做是为了保险起见。

现在,由 Vue 路由器注入的任何内容都会出现在 content_area 中,并且 只有 该部分会滚动(根据需要)。

App.vue
<template>
  <div class="app m-1">

    <div id="header_area">
      <Header/>
    </div>

    <div id="content_area">
      <span class="page-title">{{ title }}</span>
      <hr class="border-secondary">
      <span class="page-content">{{ content }}</span>
      <router-view @page-data="updatePageName($event)"/>
    </div>

    <div id="footer_area">
      <Footer/>
    </div>

  </div>
</template>

<script>
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'

export default {
  data() {
    return {
    title: "home",
    content: ""
    }
  },
  components: {
    Header,
    Footer,
  },
  methods: {
    updatePageName: function(event) {
      this.title = event.title;
      this.content = event.content;
    }
  }
};
</script>

<style>
  @import'~bootstrap/dist/css/bootstrap.css';
  @import "./assets/navbar.css";
  @import "./assets/main.css";
</style>
index.html
<!DOCTYPE html>
<html lang="en" style="margin: 0;">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="../public/favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body style="margin: 0; overflow: hidden;">
    <noscript>
      <strong>The <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>

    <div id="app"></div>
    <!-- built files are auto-injected here -->
  </body>
</html>
main.css
.app {
    height: 100vh !important;
    display: grid !important;
    grid-gap: 5px !important;
    grid-template-columns: 1fr !important;
    grid-template-rows: 65px 1fr 40px !important;
    grid-template-areas: "header" "content" "footer" !important;
}

#header_area {
    grid-area: header !important;
}

#content_area {
    grid-area: content !important;
    overflow: auto !important;
}

#footer_area {
    grid-area: footer !important;
}

普通HTML示例

body {
  background-color: red;
  margin: 0;
}

.container {
  height: 100vh;
  display: grid;
  grid-gap: 5px;
  grid-template-columns: 1fr;
  grid-template-rows: 70px 1fr 40px;
  grid-template-areas: "header" "content" "footer";
}

.H {
  grid-area: header;
  background-color: blue;
  color: white;
}

.C {
  grid-area: content;
  background-color: darkgreen;
  color: white;
  padding: 15px 5px 10px 5px;
  overflow: auto;
}

.F {
  grid-area: footer;
  background-color: blue;
  color: white;
}
<!DOCTYPE html>

<html>

<head>
</head>

<body>
  <div class="container">
    <div class="H">header</div>
    <div class="C">
      content
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br> .
      <br>
    </div>
    <div class="F">footer</div>
  </div>
</body>

</html>