v3-waterfall

repository·master·Indexed 41 days ago

https://github.com/gk-shi/v3-waterfall

A responsive waterfall layout component for Vue 3 featuring image preloading for automatic height calculation, virtual list support for large datasets, and custom scrolling container integration. Version 2.0.1 introduces functional configurations for colWidth and gap to support responsive layouts and removes deprecated props like mobileGap and srcKey.

Tokens
5.3K
Snippets
16
Records
20
Agent score
99%

What's inside v3-waterfall

  1. Enable virtual list for large datasets

    master

    To improve performance with large amounts of data, you can enable virtual list support using virtualTime and virtualLength:

    • virtualTime: The interval (in ms) after a scroll event to trigger virtual list calculations. Set this to 400 or higher for optimal use. A value of 0 disables the virtual list.
    • virtualLength: The distance (in px) an element can move outside the viewport (above or below) before it is hidden.

    Note: Because the component requires pre-rendering for layout calculations, the virtual list behavior may differ slightly from standard implementations.

  2. Enable virtual list support

    master

    To handle large datasets efficiently, enable virtual list support by setting virtualTime.

    • virtualTime: The interval (in ms) after a scroll event to trigger virtual list calculations. Set this to 0 to disable. A value of 400 or higher is recommended.
    • virtualLength: The distance (in px) an element can move outside the viewport before it is hidden.
  3. Migrate from v1 to v2: Deprecated props and field changes

    master

    The following changes are required when upgrading from v1 to v2:

    • mobileGap: Deprecated. This field has been removed. Use the functional approach for gap to handle mobile spacing instead.
    • srcKey: Deprecated. This field (used to specify the image URL field in the list) has been removed.

    New requirement for images: Since srcKey is removed, you must now add a data-key attribute to every <img> tag within your card slot that dynamically affects the card's height. Refer to the main README for specific implementation details on using data-key.

  4. Install and register v3-waterfall

    master

    To use v3-waterfall in your Vue 3 project, install it via npm and register it as a plugin in your main entry file. You must also import the component's CSS file to ensure correct layout and styling.

    npm i v3-waterfall
    // main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import V3waterfall from 'v3-waterfall'
    import 'v3-waterfall/dist/style.css'
    
    createApp(App)
      .use(V3waterfall)
      .mount('#app')
  5. Configure scrolling for parent elements

    master

    By default, the component listens to the window scroll event. If your waterfall is inside a specific container with overflow-y: scroll, you must use scrollBodySelector and isMounted together.

    Because the child component's mounted hook runs before the parent's, you must use a ref to track when the parent component has finished mounting and pass that to :isMounted.

    <div class="father-box">
      <v3-waterfall scrollBodySelector=".father-box" :isMounted="isMounted"></v3-waterfall>
    </div>
    
    <script setup>
    import { ref, onMounted } from 'vue'
    const isMounted = ref(false)
    
    onMounted(() => {
      isMounted.value = true
    })
    </script>
    
    <style>
    .father-box {
      height: 300px;
      overflow-y: scroll;
    }
    </style>
  6. Install and setup v3-waterfall

    master

    To use v3-waterfall in your Vue 3 project, install it via pnpm and register it as a plugin in your main entry file. You must also import the component's CSS file for correct styling.

    pnpm add v3-waterfall
    // main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import V3waterfall from 'v3-waterfall'
    import 'v3-waterfall/dist/style.css'
    
    createApp(App).use(V3waterfall).mount('#app')
  7. Migrate from v1 to v2: Update width and gap configurations

    master

    In v2, the component no longer includes built-in logic for detecting mobile devices. To support responsive layouts (different widths/gaps for mobile vs. PC), you must change the colWidth, gap, and bottomGap properties from static number values to a function type: number | () => number.

    Use the returned value of the function to define the specific pixel value based on your own device detection logic.

    // Example of implementing responsive width using a function
    const getColWidth = () => {
      const device = /(Android|iPhone|iPod|iOS|SymbianOS|Windows Phone)/gi.test(userAgent)
        ? 'mobile'
        : /iPad/gi.test(userAgent)
          ? 'ipad'
          : 'pc'
    
      const widthMap = {
        mobile: 200,
        ipad: 250,
        pc: 250
      }
      return widthMap[device]
    }
    
    // Apply to component props
    // <v3-waterfall :col-width="getColWidth" ... />
  8. Configure scrolling for a specific parent element

    master

    By default, the component listens to the window scroll event. If your waterfall is inside a container with its own scrollbar (e.g., a div with overflow-y: scroll), you must use scrollBodySelector and isMounted together.

    Because the component's mounted lifecycle executes before the parent component's mounted lifecycle, you must use a reactive variable (like isMounted) to notify the waterfall component when the parent is ready to attach scroll listeners. The parent container must have a defined height and overflow-y: scroll.

    <div class="father-box">
      <v3-waterfall scrollBodySelector=".father-box" :isMounted="isMounted"></v3-waterfall>
    </div>
    
    <script setup>
    import { ref, onMounted } from 'vue'
    
    const isMounted = ref(false)
    
    onMounted(() => {
      isMounted.value = true
    })
    </script>
    
    <style>
    .father-box {
      height: 300px; /* Parent must have height */
      overflow-y: scroll; /* Parent must have overflow scroll */
    }
    </style>
  9. Install v3-waterfall as a Vue plugin

    master

    To use v3-waterfall in your Vue application, you can install it as a global plugin. This registers the V3waterfall component globally, allowing you to use it in any template within your app without manual imports.

    import { createApp } from 'vue'
    import V3waterfall from 'v3-waterfall'
    
    const app = createApp(App)
    
    // Install the plugin
    app.use(V3waterfall)
    
    app.mount('#app')
  10. Use the v3-waterfall component

    master

    The <v3-waterfall> component renders a responsive masonry layout. It requires a list of data and a srcKey to identify the image URL field in your data objects. You can customize the layout using props like gap, colWidth, and distanceToScroll.

    Important Data Handling Note: When appending new items to your list, use list.value = list.value.concat(addedList) instead of push(). The component performs incremental loading internally, and using push may trigger multiple redundant updates because the component's internal watchers ignore push operations.

    <v3-waterfall 
      class="waterfall" 
      :list="list" 
      srcKey="cover" 
      :gap="12" 
      :colWidth="280"
      :distanceToScroll="200" 
      :isLoading="loading" 
      :isOver="over" 
      @scrollReachBottom="getNext"
    >
      <template v-slot:default="slotProp">
        <div class="list-item">
          <a :href="'https://gkshi.com/blog/' + slotProp.item._id">
            <div class="cover-wrapper">
              <img v-if="slotProp.item.cover" :src="slotProp.item.cover" class="cover" />
            </div>
            <div class="brief">
              <!-- slotProp.raw provides access to the original reactive data object -->
              <h3>{{ slotProp.item.title }}</h3>
              <p>{{ slotProp.item.outline }}</p>
            </div>
          </a>
        </div>
      </template>
    </v3-waterfall>
  11. Use heightHook for custom height calculation

    master

    By default, the component preloads images to calculate element heights. To improve performance and avoid white flashes (especially if you already have image dimensions from your API), use the heightHook prop. This hook allows you to provide a custom function that returns a Promise<number> representing the calculated height.

    /**
     * @param slots Internal slots
     * @param item The data item for this block
     * @param width The width of the element block
     * @param errorImgSrc The provided error image source
     * @returns Promise<number> The total height of the card
     */
    const heightHook = (slots, item, width, errorImgSrc) => {
      // Example logic: 
      // 1. Create a hidden div with the target width
      // 2. Render the slot content into the div
      // 3. Calculate height of non-image elements
      // 4. Calculate image height based on aspect ratio: (width / item.cover_width) * item.cover_height
      // 5. Return total height
    }
  12. Use component methods via ref (reRender and insertBefore)

    master

    You can access the following methods via a component ref to handle specific UI updates:

    • reRender(): Recalculates heights for all currently loaded cards. Use this when card content changes (e.g., toggling visibility of titles).
    • insertBefore(insertList): Inserts a new list of items at the beginning of the current list. This is ideal for 'pull-to-refresh' scenarios. It does not recalculate heights for existing cards.
    <script setup lang="ts">
    import { ref } from 'vue'
    import type { V3WaterfallExpose } from 'v3-waterfall'
    
    const v3WaterfallRef = ref<V3WaterfallExpose | null>(null)
    
    const handleRefresh = async () => {
      const newData = [/* ... */]
      await v3WaterfallRef.value?.insertBefore(newData)
    }
    
    const handleContentChange = () => {
      v3WaterfallRef.value?.reRender()
    }
    </script>
    
    <template>
      <v3-waterfall ref="v3WaterfallRef" :list="list" />
    </template>