0

我正在寻找一种滚动到元素以触发事件的方法。我注意到很多示例' scrollTo(),scrollBy()等都不起作用(除非通过ascrollByView()调用或使用 classic 滚动)。on:clickbutton<a href="#element"></a>

我在我的文件中用这样简单的东西进行了测试.svelte(结果 -> 什么也没发生,也没有错误),看看滚动是否有效:

<script>
  let y;
</script>

<svelte:window bind:scrollY={y} on:scroll={console.log("SCROLL Y VALUE: " + y)}/>

做了更多的挖掘,我遇到了JavaScript scrollTo 方法什么也没做,之后我再次检查了我的页面,我注意到在 DevTools 中单击某些元素时会出现一个scroll和框。overflow

然后它点击了......当然我不能滚动。没有可滚动的页面。我滚动的只是溢出内容,而window内容的高度在技术上保持不变。

我在这里找到的以下代码确认该<main></main>部分导致溢出(自然)。

document.querySelectorAll('*').forEach(el => {
  if (el.offsetHeight > document.documentElement.offsetHeight) {
      console.log('Found the worst element ever: ', el);
  }
});

(我在我的 Svelte 网站中使用navbar menu for desktop + drawer for mobile来自DaisyUI的。)

页眉.svelte

<div class="rounded-lg shadow bg-base-200 drawer h-52"> <!-- It's 'h-screen' in my case. Though, even without either, I'm still technically scrolling the overflowed content. -->
  <input id="my-drawer-3" type="checkbox" class="drawer-toggle"> 
  <div class="flex flex-col drawer-content">
    <div class="w-full navbar bg-base-300">
      <div class="flex-none lg:hidden">
        <label for="my-drawer-3" class="btn btn-square btn-ghost">
          <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-6 h-6 stroke-current">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
          </svg>
        </label>
      </div> 
      <div class="flex-1 px-2 mx-2">
        <span>
              Change screen size to show/hide menu
            </span>
      </div> 
      <div class="flex-none hidden lg:block">
        <ul class="menu horizontal">
          <li>
            <a class="rounded-btn">Item 1</a>
          </li> 
          <li>
            <a class="rounded-btn">Item 2</a>
          </li>
        </ul>
      </div>
    </div>
  </div> 

  <!-- THIS IS WHERE CONTENT MUST GO IN ORDER FOR THE DRAWER TO APPEAR OVER IT WHEN OPENED -->
  <slot></slot>

  <div class="drawer-side">
    <label for="my-drawer-3" class="drawer-overlay"></label> 
    <ul class="p-4 overflow-y-auto menu w-80 bg-base-100">
      <li>
        <a>Item 1</a>
      </li> 
      <li>
        <a>Item 2</a>
      </li>
    </ul>
  </div>
</div>

__layout.svelte:

<script>
  import Header from "$lib/Header.svelte"
</script>

<Header>
  <main>
    <!-- index.svelte goes here -->
    <slot></slot>
  </main>

<!-- DaisyUI footer -->
<footer class="p-10 footer bg-neutral text-neutral-content">
  <div>
    <svg width="50" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" class="fill-current">
      <path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path>
    </svg> 
    <p>ACME Industries Ltd.
      <br>Providing reliable tech since 1992
    </p>
  </div> 
  <div>
    <span class="footer-title">Social</span> 
    <div class="grid grid-flow-col gap-4">
      <a>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
          <path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path>
        </svg>
      </a> 
      <a>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
          <path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path>
        </svg>
      </a> 
      <a>
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
          <path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path>
        </svg>
      </a>
    </div>
  </div>
</footer>

</Header>

<style>
</style>

index.svelte:

<script>
let y;

function scrolling() {
    console.log("SCROLL Y VALUE: " + y);
}
</script>

<svelte:head>
    <title>Page Title</title>
</svelte:head>

<svelte:window bind:scrollY={y} on:scroll="{scrolling}"/>

<div class="hero min-h-screen bg-base-200">
  <div class="text-center hero-content">
    <div class="max-w-md">
      <h1 class="mb-5 text-5xl font-bold">
            Hello there
          </h1> 
      <p class="mb-5">
            Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem quasi. In deleniti eaque aut repudiandae et a id nisi.
          </p> 
      <button class="btn btn-primary">Get Started</button>
    </div>
  </div>
</div>

<div class="hero min-h-screen bg-base-200">
  <div class="text-center hero-content">
    <div class="max-w-md">
      <h1 class="mb-5 text-5xl font-bold">
            Hello there
          </h1> 
      <p class="mb-5">
            Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem quasi. In deleniti eaque aut repudiandae et a id nisi.
          </p> 
      <button class="btn btn-primary">Get Started</button>
    </div>
  </div>
</div>

如果我按预期将滚动工作放在内部的<slot></slot> 外部,但是and部分不会。<Header></Header>__layout.sveltenavbardrawer

问题:

如何重组我的 Svelte 组件以使抽屉保持在内容上方(即具有更高的z-index),使其高度与屏幕相同并且在不显示时仍然能够滚动(例如在桌面上)?

PS 我发现的抽屉示例似乎总是以与 DaisyUI 相同的方式工作,即将您的内容放入其中。

4

1 回答 1

0

解决方案逻辑

该解决方案背后的想法是将导航栏抽屉分离到不同的组件中,并结合使用storewritable()(组件可以“订阅”以侦听更改并在这种情况下也进行修改的全局变量)class 指令在打开和关闭抽屉时将不同的样式类应用于不同的元素。

[以下解决方案也可以在其他框架中实现,例如 VueJS 甚至使用 vanilla JavaScript。]

工具:

  • Svelte / SvelteKit(在这种情况下)
  • 尾风CSS
  • DaisyUI(需要 TailWindCSS)

常见问题

我尝试了其他一些可能的解决方案(其中一些甚至没有使用overlay元素),但我总是遇到以下问题之一:

  • 关闭时,抽屉组件将位于导航栏后面。
  • 标记为overlay'sopacitybackground-color在关闭时转换时不会触发的元素(由于抽屉容器被隐藏的方式,它只会跳到“0”)。
  • drawer container抽屉和标记为必须的元素在关闭过渡时具有 减少。opacity(最后看起来不错,这是我想出的第一个解决方案,但我想更接近 DaisyUI 的原始视觉过渡。)
  • 有时过渡只适用于“粘性”导航栏或普通导航栏,但不能同时适用于两者。

重要笔记

代码

商店.js:

import { writable } from 'svelte/store';

// Writable variable which gets read and modified by both components.
export const toggleCustomDrawer = writable(false);

index.svelte:

<script>
</script>

<div class="hero min-h-screen bg-base-200">
  <div class="flex-col hero-content lg:flex-row-reverse">
    <img src="https://picsum.photos/id/1005/600/600" class="max-w-sm rounded-lg shadow-2xl" alt="Dude with glasses"> 
    <div>
      <h1 class="mb-5 text-5xl font-bold">
            Hello there
          </h1> 
      <p class="mb-5">
            Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem quasi. In deleniti eaque aut repudiandae et a id nisi.
          </p> 
      <button class="btn btn-primary">Get Started</button>
    </div>
  </div>
</div>

<div class="hero min-h-screen" style="background-image: url(&quot;https://picsum.photos/id/1005/1600/1400&quot;);">
  <div class="hero-overlay bg-opacity-60"></div> 
  <div class="text-center hero-content text-neutral-content">
    <div class="max-w-md">
      <h1 class="mb-5 text-5xl font-bold">
            Hello there
          </h1> 
      <p class="mb-5">
            Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem quasi. In deleniti eaque aut repudiandae et a id nisi.
          </p> 
      <button class="btn btn-primary">Get Started</button>
    </div>
  </div>
</div>

<style>
</style>

CustomHeader.svelte:

<script>
    import { toggleCustomDrawer } from '../stores/stores.js';

    let customDrawerOn;

    // Subscribe to the 'writable()' to listen for changes / be able to change the value.
    toggleCustomDrawer.subscribe(value => {
      customDrawerOn = value;
    });

    // Change the value of the 'writable()'.
    function toggleCustomDrawerOnOff() {
      toggleCustomDrawer.update(value => customDrawerOn ? false : true);
      console.log("[CustomHeader.svelte] toggleDrawerOnOff(): <<< " + customDrawerOn + " >>>");
    }
</script>

<!-- Original navbar used -> 'start/center/end' (the last one in the list as of writing this)
     See -> https://daisyui.com/components/navbar
-->
<div class="navigation-bar-container fixed top-0 w-full">
  <div class="navbar mb-2 shadow-lg bg-primary text-neutral-content">
    <div class="px-2 mx-2 navbar-start">
      <button class="flex-none lg:hidden btn btn-square btn-ghost" on:click={toggleCustomDrawerOnOff}>
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-6 h-6 stroke-current">           
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>               
        </svg>
      </button>
      <span class="text-lg font-bold">daisyUI</span>
    </div> 
    <div class="hidden px-2 mx-2 navbar-center lg:flex">
      <div class="flex items-stretch">
        <a class="btn btn-ghost btn-sm rounded-btn" href="asd">Home</a> 
        <a class="btn btn-ghost btn-sm rounded-btn" href="asd">Portfolio</a> 
        <a class="btn btn-ghost btn-sm rounded-btn" href="asd">About</a> 
        <a class="btn btn-ghost btn-sm rounded-btn" href="asd">Contact</a>
      </div>
    </div> 
    <div class="navbar-end">
      <button class="btn btn-square btn-ghost">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-6 h-6 stroke-current">     
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>                     
        </svg>
      </button> 
      <button class="btn btn-square btn-ghost">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-6 h-6 stroke-current">             
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>             
        </svg>
      </button>
    </div>
  </div>
</div>

<style>
  /* If your pages have any 'idicator' items (See -> https://daisyui.com/components/indicator), 
     use 'z-index: 2;', if not, feel free to use 'z-index: 1;'
     
     Whatever the case, make sure your 'z-indexes' in the 'styles.css' I've put are this one + 1 higher.

     E.G. If this is '2', the one in the 'styles.css' must be '3'.
     If this is '1', the one in the 'styles.css' must be '2'.
     If this is '34', the one in the 'styles.css' must be '35'.

     It's just in case, so we can avoid possible overlappings when scrolling.
  */
  .navigation-bar-container {
    z-index: 2;
  }
</style>

CustomDrawer.svelte:

<script>
  import { toggleCustomDrawer } from '../stores/stores.js';

  let customDrawerOn;

  // Subscribe to the 'writable()' to listen for changes / be able to change the value.
  toggleCustomDrawer.subscribe(value => {
    customDrawerOn = value;
  });

  // Change the value of the 'writable()'.
  function toggleCustomDrawerOff() {
    toggleCustomDrawer.update(value => false);
    console.log("[CustomDrawer.svelte] toggleDrawerOff(): <<< " + customDrawerOn + " >>>");
  }

</script>

<!-- The outermost '<div>' container is the drawer container.
     Its first child functions as the "overlay".
     Its second child functions as the "menu".

     Class directive:

     Using a ternary operator we set the classes based on the value of our local variable, but
     because this component has used the '.subscribe()' method on the store 'writable()' and subsequently
     assigned its value to our local variable, whenever said 'writable()' changes, so will our local one.
     
     When it does, the class styles will be updated/changed automatically and so will the DOM elements we see
     in the Browser.
-->
<div class={customDrawerOn ? 'custom-drawer-container drawer-open' : 'custom-drawer-container drawer-close'}>
  <div class="custom-drawer-container-overlay" on:click={toggleCustomDrawerOff}></div>
  <ul class="p-4 w-80 menu bg-base-100">
    <li class="text-red-700" on:click={toggleCustomDrawerOff}>
      <!-- The comment below makes VSCode ignore the missing "href" warning. -->
      <!-- svelte-ignore a11y-missing-attribute -->
      <a class="btn btn-ghost rounded-btn text-red-500">Close Menu</a>
    </li>
    <li>
      <a class="btn btn-ghost rounded-btn" href="asd">Home</a> 
    </li>
    <li>
      <a class="btn btn-ghost rounded-btn" href="asd">Portfolio</a> 
    </li>
    <li>
      <a class="btn btn-ghost rounded-btn" href="asd">About</a> 
    </li>
    <li>
      <a class="btn btn-ghost rounded-btn" href="asd">Contact</a>
    </li>
  </ul>
</div>

<style>
</style>

样式.css:

(将其复制/粘贴到编辑器中,该编辑器读取.css文件以正确突出显示并更易于阅读。)

  @tailwind base;
  @tailwind components;
  @tailwind utilities;

  /*  ***NOTE: PostCSS formatting except for 'z-index: 3;' which was not available 
    as an option with the initial TailWindCSS configuration. 
   
  For the definitions of each, see the following sections at https://tailwindcss.com/docs/installation

    - Position 
    - Top / Right / Bottom / Left
    - Visibility
    - Flex
    - Grid
    - Max Height
    - Transitions
    - Opacity

  For more info on 'bg-neutral-focus', see the "Colors" section of DaisyUI at https://daisyui.com/core/colors */

/* Position of the drawer container. */
.custom-drawer-container {
  @apply fixed;
  @apply inset-0;
  @apply flex;
  
  @apply grid;
  @apply max-h-screen;
  @apply col-start-1;
  @apply row-start-1;
  z-index: 3;           /* 'z-index' of '.navigation-bar-container' + 1 (See -> [CustomHeader.svelte] for more info) */
}

/* All of the children of the container will have these settings regardless of whether the
   '.custom-drawer-container' is in "opened state" or in "closed state". */
.custom-drawer-container > * {
  @apply transition-all;
  @apply duration-300;
  z-index: 3;           /* 'z-index' of '.navigation-bar-container' + 1 (See -> [CustomHeader.svelte] for more info) */
}

/* Drawer overlay */
.custom-drawer-container-overlay {
  @apply opacity-0;
  @apply invisible;
  @apply col-start-1;
  @apply row-start-1;
  @apply bg-neutral-focus;
}

/* Change the index of the container while it's in "opened state" to make sure it's above the rest of the elements. */
.custom-drawer-container.drawer-open {
  z-index: 3;                 /* 'z-index' of '.navigation-bar-container' + 1 (See -> [CustomHeader.svelte] for more info) */
}

/* Makes the '.custom-drawer-container' click-through when in "closed state". 
   
   See -> https://stackoverflow.com/questions/3680429/click-through-div-to-underlying-elements for more info.

   For an explanation as to why it was used, see my post. */
.custom-drawer-container.drawer-close {
  @apply pointer-events-none;
}

/* Original position of the overlay and <ul></ul>.

See -> https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator for more info. */
.custom-drawer-container > .custom-drawer-container-overlay + * {
  @apply col-start-1;
  @apply row-start-1;
  @apply -translate-x-full;
}

/* The overlay's position for the transition when the drawer container is in "opened state". 
  When in "closed state", they'll revert back to the original position. */
.custom-drawer-container.drawer-open > .custom-drawer-container-overlay {
  @apply visible;
  @apply opacity-40;
  @apply cursor-pointer;
}

/* Position for any children that come IMMEDIATELY after the overlay element (i.e. '<ul></ul>') when the drawer
  drawer container is in "opened state". When in "closed state", they'll revert back to the original position.*/
.custom-drawer-container.drawer-open > .custom-drawer-container-overlay + * {
  @apply translate-x-0;
}

__layout.svelte:

<script>
  import '../styles.css';
  import CustomHeader from "$lib/CustomHeader.svelte";
  import CustomDrawer from "$lib/CustomDrawer.svelte";
</script>

<CustomHeader />

<CustomDrawer />

<!-- The 'index.svelte' will go here. -->
<slot></slot>

<!-- You could put a footer here. -->

<style>
</style>

我为什么用pointer-events

没有它,我总是至少在上面描述的一个问题中运行(不管我是否使用了fixed定位)——有了这个,我不仅可以使用fixed定位,这反过来又使使用z-indexes更简单,但它将来不会引起任何问题,因为它应用于仅应充当“容器”的元素(没有实际的用户交互,例如单击/悬停/拖动/等-如果您愿意,例如,将图像拖放到您的页面,您仍然可以这样做,因为拖放将“穿过”容器并进入您处理该事件的元素)。

于 2021-12-28T19:46:06.583 回答