欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue實現(xiàn)虛擬滾動的示例詳解

 更新時間:2023年10月25日 08:35:56   作者:通往自由之路  
虛擬滾動或者移動是指禁止原生滾動,之后通過監(jiān)聽瀏覽器的相關(guān)事件實現(xiàn)模擬滾動,下面小編就來和大家詳細介紹一下vue實現(xiàn)虛擬滾動的示例代碼,需要的可以參考下

虛擬滾動或者移動是指禁止原生滾動,之后通過監(jiān)聽瀏覽器的相關(guān)事件實現(xiàn)模擬滾動。所以虛擬滾動包含兩部分內(nèi)容

1.禁止原生滾動:將cssoverfow屬性設置為hidden。這樣即便是內(nèi)容高度或者寬度超過了盒子的寬度或者高度也無法進行滾動了

<div id="vs-container">
  <div id="vs-content">
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
    <p>內(nèi)容</p>
  </div>
</div>
<style>
#vs-container {
  overflow:hidden;
  height:100px;
}
#vs-content {
  height:200px;
}
</style>

2.模擬滾動:通過監(jiān)聽鼠標的wheel事件,調(diào)整內(nèi)容位置,從而形成滾動效果;通過監(jiān)聽onmousedown、onmousemove、onmouseup實現(xiàn)虛擬滾動條的移動

解決什么問題

  • 服務虛擬列表,尤其不定高度內(nèi)容的虛擬列表實現(xiàn);不定高內(nèi)容虛擬列表在滑動過程中由于滾動速度大于渲染速度導致過快滑動時出現(xiàn)白屏現(xiàn)象。如果有虛擬滾動,則可以先進行數(shù)據(jù)渲染待渲染完畢再進行滾動,這樣就徹底解決了白屏問題。
  • 在我工作中遇到使用虛擬列表實現(xiàn)不定高數(shù)據(jù)渲染問題,正好也出現(xiàn)了白屏問題

Dom結(jié)構(gòu)

本文使用vue2實現(xiàn)虛擬滾動,DOM結(jié)構(gòu)以及一些初始化數(shù)據(jù)如下

內(nèi)容和盒子

<template>
  <div id="vs-container" ref="container">
    <div id="vs-content" :style="{ transform: contentTransform }">
      <p :key="num" v-for="num in list">{{ num }}</p>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      list: 1000,
      contentOffset: 0
    }
  },
  computed: {
    contentTransform () {
      return `translate3d(${this.contentOffset}px)`
    }
  }
}
</script>
<style lang="scss" scoped>
#vs-container {
  margin-top: 200px;
  margin-left: 20px;
  height: 200px;
  border: 1px solid #333;
  overflow: hidden;
  width: 500px;
  position: relative;
  box-sizing: border-box;
}
</style>

上述代碼內(nèi)容id為vs-content,盒子id為vs-container,盒子高度200px,并且禁止盒子的原生滾動,設置盒子overflowhidden。contentTransform用來動態(tài)變化滾動位置。給盒子增加ref,標記container為后面開發(fā)使用。

虛擬滾動條

在上述代碼中添加虛擬滾動條,虛擬滾動條包括滑道,其ref設置為slider;還包括手柄,手柄ref為handle

<template>
  <div id="vs-container" ref="container">
    <div id="vs-content" :style="{ transform: contentTransform }">
      <p :key="num" v-for="num in list">{{ num }}</p>
    </div>
    <div id="vs-slider" ref="slider">
      <div
        id="vs-handle"
        :style="{ transform: handleTransformt }"
        ref="handle"
      ></div>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      ...
      handleOffset: 0
    }
  },
  computed: {
    ...
    handleTransform () {
      return `translateY(${this.handleOffset}px)`
    }
  }
}
</script>
<style lang="scss" scoped>
#vs-container {
  ...
  #vs-slider {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 10px;
    height:20px;
    box-sizing: border-box;
    background-color: #6b6b6b;
    #vs-handle {
      background-color: #f1f2f3;
      cursor: pointer;
      border-radius: 10px;
    }
  }
}
</style>

contentTransform用來動態(tài)變化虛擬滾動條的滾動位置,設置滾動條高度20px。到此處整個虛擬滾動示例長這樣

虛擬滾動實現(xiàn)

實現(xiàn)虛擬滾動,開頭說了模擬滾動原理:通過監(jiān)聽鼠標的wheel事件,調(diào)整內(nèi)容位置,從而形成滾動效果;通過監(jiān)聽onmousedownonmousemove、onmouseup實現(xiàn)虛擬滾動條的移動。

本文使用translateY值的變化實現(xiàn)內(nèi)容區(qū)或虛擬滾動條的滾動。本文只實現(xiàn)垂直方向上的滾動,水平方向上的滾動原理基本一致。

監(jiān)聽鼠標滾輪或觸屏版實現(xiàn)內(nèi)容區(qū)滾動

使用上文中ref獲取相應的dom元素,然后給內(nèi)容區(qū)盒子container綁定wheel事件。

監(jiān)聽wheel事件獲取事件對象的wheelDeltaY,其含義為

返回一個整型數(shù),表示垂直滾動量。

在谷歌瀏覽器下,如果是觸屏版滑動返回0、1、2、3……或者0、-1、-2、-3……,如果是鼠標滾輪滾動返回150或-150。具體實現(xiàn)內(nèi)容區(qū)滾動

<template>
  <div id="vs-container" ref="container">
    <div id="vs-content" :style="{ transform: contentTransform }">
      <p :key="num" v-for="num in list">{{ num }}</p>
    </div>
    <div id="vs-slider" ref="slider">
      <div
        id="vs-handle"
        :style="{ transform: handleTransform, height: handleStyleHeight }"
        ref="handle"
      ></div>
    </div>
  </div>
</template>
<script>
export default {
  methods: {
    bindContainerEvent () {
      const { $container } = this.$element
      const contentSpace = $container.scrollHeight - $container.offsetHeight
      const bindContainerOffset = (event) => {
        event.preventDefault()
        this.contentOffset += event.wheelDeltaY
        if (this.contentOffset < 0) {
          this.contentOffset = Math.max(this.contentOffset, -contentSpace)
        } else {
          this.contentOffset = 0
        }
      }
      $container.addEventListener('wheel', bindContainerOffset)
      this.unbindContainerEvent = () => {
        $container.removeEventListener('wheel', bindContainerOffset)
      }
    },
     // 獲取dom元素
    saveHtmlElementById () {
      const { container, slider, handle } = this.$refs
      this.$element = {
        $container: container,
        $slider: slider,
        $handle: handle
      }
      this.bindContainerEvent()
    }
  },
  created () {
    this.$nextTick(() => {
      this.saveHtmlElementById()
    })
  },
  beforeDestroy () {
    this.unbindContainerEvent()
  }
}
</script>

event.wheelDeltaY值為負值,表示內(nèi)容區(qū)向上滾動,反之內(nèi)容區(qū)向下滾動。之后需要限制滾動區(qū)間

if (this.contentOffset < 0) {
   this.contentOffset = Math.max(this.contentOffset, -contentSpace)
} else {
   this.contentOffset = 0
}

內(nèi)容區(qū)向上移動的最大距離為contentSpace,向下滾動的最大距離為0。

監(jiān)聽虛擬滾動條事件實現(xiàn)內(nèi)容區(qū)滾動

監(jiān)聽虛擬滾動條的onmousedown事件,之后使用手柄偏移量handleOffset以及計算屬性handleTransform實現(xiàn)手柄的上下滑動

export default {
  data () {
    return {
      ...
      handleOffset: 0,
    }
  },
  computed: {
    handleTransform () {
      return `translateY(${this.handleOffset}px)`
    }
  },
  methods: {
    bindHandleEvent () {
      const { $slider, $handle } = this.$element
      const handleSpace = $slider.offsetHeight - this.handleHeight
      $handle.onmousedown = (e) => {
        const startY = e.clientY
        const startTop = this.handleOffset
        window.onmousemove = (e) => {
          const deltaX = e.clientY - startY
          this.handleOffset =
            startTop + deltaX < 0
              ? 0
              : Math.min(startTop + deltaX, handleSpace)
        }

        window.onmouseup = function () {
          window.onmousemove = null
          window.onmouseup = null
        }
      }
    },
    saveHtmlElementById () {
      ...
      this.bindHandleEvent()
    }
  },
  created () {
    this.$nextTick(() => {
      this.saveHtmlElementById()
    })
  }
}

基本實現(xiàn)邏輯:在鼠標按下時記錄當前位置,鼠標移動則將移動值通過一定的轉(zhuǎn)換邏輯賦給手柄偏移量,同時限制手柄移動上下邊界

this.handleOffset =
            startTop + deltaX < 0
              ? 0
              : Math.min(startTop + deltaX, handleSpace)

最小為0,最大為handleSpace。

關(guān)聯(lián)手柄移動與內(nèi)容區(qū)移動

到此處已經(jīng)實現(xiàn)了滾動條的移動和內(nèi)容區(qū)的移動。但二者還是各自為戰(zhàn)的,需要關(guān)聯(lián)起來。具體關(guān)聯(lián)邏輯是關(guān)聯(lián)內(nèi)容區(qū)最大滾動距離和虛擬滾動條最大移動距離。二者比例就是移動距離的數(shù)值關(guān)系。

增加關(guān)聯(lián)方法transferOffset

  methods: {
    transferOffset (to = 'handle') {
      const { $container, $slider } = this.$element
      const contentSpace = $container.scrollHeight - $container.offsetHeight
      const handleSpace = $slider.offsetHeight - this.handleHeight
      const assistRatio = handleSpace / contentSpace // 小于1
      const _this = this
      const computedOffset = {
        handle () {
          return -_this.contentOffset * assistRatio
        },
        content () {
          return -_this.handleOffset / assistRatio
        }
      }
      return computedOffset[to]()
    }
  }

contentSpace為內(nèi)容最大滾動距離,handleSpace為手柄最大移動距離。assistRatio為二者比例。轉(zhuǎn)換對象computedOffset包含兩個方法,分別是通過內(nèi)容移動距離轉(zhuǎn)為手柄移動距離和通過手柄移動距離轉(zhuǎn)為內(nèi)容移動距離。使用轉(zhuǎn)換方法

  methods: {
    bindContainerEvent () {
      ...
      const updateHandleOffset = () => {
        // 使用關(guān)聯(lián)方法
        this.handleOffset = this.transferOffset()
      }
      $container.addEventListener('wheel', bindContainerOffset)
      // 給手柄事件在增加一個訂閱方法
      $container.addEventListener('wheel', updateHandleOffset)
      this.unbindContainerEvent = () => {
        $container.removeEventListener('wheel', bindContainerOffset)
        $container.removeEventListener('wheel', updateHandleOffset)
      }
    },
    bindHandleEvent () {
      const { $slider, $handle } = this.$element
      const handleSpace = $slider.offsetHeight - this.handleHeight
      $handle.onmousedown = (e) => {
        const startY = e.clientY
        const startTop = this.handleOffset
        window.onmousemove = (e) => {
          ...
          // 使用關(guān)聯(lián)方法
          this.contentOffset = this.transferOffset('content')
        }

        window.onmouseup = function () {
          window.onmousemove = null
          window.onmouseup = null
        }
      }
    }
  },
  beforeDestroy () {
    this.unbindContainerEvent()
  }

到此虛擬滾動基本實現(xiàn),看下效果

優(yōu)化

動態(tài)設置手柄高度

默認將手柄高度設置為20px,這實際是不符合實際滾動條高度變化規(guī)則的。實際內(nèi)容區(qū)高度和內(nèi)容區(qū)盒子高度相差越大則手柄高度越小反之越大。本文虛擬滾動為了方便操作可以人為限制手柄最小高度。

優(yōu)化手柄的高度邏輯,增加手柄高度屬性,以及計算屬性handleStyleHeight,限制手柄最小尺寸為20px,同時再增加手柄高度的初始化方法initHandleHeight

<template>
  <div id="vs-container" ref="container">
    <div id="vs-content" :style="{ transform: contentTransform }">
      <p :key="num" v-for="num in list">{{ num }}</p>
    </div>
    <div id="vs-slider" ref="slider">
      <div
        id="vs-handle"
        :style="{ transform: handleTransform, height: handleStyleHeight }"
        ref="handle"
      ></div>
    </div>
  </div>
</template>
<script>
const HandleMixHeight = 20
export default {
  data () {
    return {
      ...
      handleHeight: HandleMixHeight
    }
  },
  computed: {
    ...
    handleStyleHeight () {
      return `${this.handleHeight}px`
    }
  },
  methods: {
    ...
    initHandleHeight () {
      const { $container, $slider } = this.$element
      // 根據(jù)比例變化
      this.handleHeight =
        ($slider.offsetHeight * $container.offsetHeight) /
        $container.scrollHeight
      // 最小值為HandleMixHeight
      if (this.handleHeight < HandleMixHeight) {
        this.handleHeight = HandleMixHeight
      }
    }
  },
  created () {
    this.$nextTick(() => {
      this.saveHtmlElementById()
    })
  }
}
</script>

禁止選中文本

在上文中的效果圖中也可以看出,當鼠標拖動滾動條時,內(nèi)容區(qū)文本被選中了。這樣體驗很不好,對手柄和滑道添加禁止選中,使用css實現(xiàn)

<style lang="scss" scoped>
#vs-container {
  ...
  #vs-slider {
    ...
    -webkit-user-select: none; /* Safari/Chrome */
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* Internet Explorer/Edge */
    user-select: none; /* Standard */
    #vs-handle {
      ...
      -webkit-user-select: none; /* Safari/Chrome */
      -moz-user-select: none; /* Firefox */
      -ms-user-select: none; /* Internet Explorer/Edge */
      user-select: none; /* Standard */
    }
  }
}
</style>

總結(jié)

本文是對虛擬滾動的一種實現(xiàn)。具體是通過對wheel事件的監(jiān)聽模擬內(nèi)容的移動;通過對onmousedown、onmousemove、onmouseup的監(jiān)聽實現(xiàn)虛擬滾動條的移動。當然不管是內(nèi)容的移動還是虛擬滾動條的移動都需要在一個閉區(qū)間內(nèi)。

本文有2個沒有處理的點

  • 不需要滾動條的情況
  • 滾動條手柄的上下部分

感興趣可以進一步完善。本文的重點是垂直方向虛擬滾動的基本實現(xiàn),是為后面不定高虛擬列表服務。

以上就是vue實現(xiàn)虛擬滾動的示例詳解的詳細內(nèi)容,更多關(guān)于vue虛擬滾動的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue.js修改el-popover組件顯示位置

    vue.js修改el-popover組件顯示位置

    el-popover是一個基于element-ui框架設計的,用于浮動展示提示或菜單的UI組件,下面這篇文章主要給大家介紹了關(guān)于vue.js修改el-popover組件顯示位置的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • 項目開發(fā)中husky的使用詳解

    項目開發(fā)中husky的使用詳解

    這篇文章主要為大家介紹了項目開發(fā)中husky的使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Vue-router 中hash模式和history模式的區(qū)別

    Vue-router 中hash模式和history模式的區(qū)別

    這篇文章主要介紹了Vue-router 中hash模式和history模式的區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Vue中$nextTick實現(xiàn)源碼解析

    Vue中$nextTick實現(xiàn)源碼解析

    這篇文章主要為大家介紹了Vue中$nextTick實現(xiàn)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 詳解vue-Resource(與后端數(shù)據(jù)交互)

    詳解vue-Resource(與后端數(shù)據(jù)交互)

    本篇文章主要介紹了vue-Resource(與后端數(shù)據(jù)交互),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • vue實現(xiàn)接口封裝的實現(xiàn)示例

    vue實現(xiàn)接口封裝的實現(xiàn)示例

    本文主要介紹了vue實現(xiàn)接口封裝的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-11-11
  • 基于Vue3和Element Plus實現(xiàn)自動導入功能

    基于Vue3和Element Plus實現(xiàn)自動導入功能

    在 Vue 3 項目中,結(jié)合  Element Plus  實現(xiàn)自動導入可以顯著減少代碼量,提升開發(fā)效率,Element Plus 提供了官方的自動導入插件  unplugin-vue-components  和  unplugin-auto-import,以下是如何配置和使用的詳細步驟,需要的朋友可以參考下
    2025-03-03
  • vue中添加與刪除關(guān)鍵字搜索功能

    vue中添加與刪除關(guān)鍵字搜索功能

    這篇文章主要介紹了vue中添加與刪除,關(guān)鍵字搜索功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • Vue使用vue-pdf實現(xiàn)PDF文件預覽

    Vue使用vue-pdf實現(xiàn)PDF文件預覽

    這篇文章主要為大家詳細介紹了Vue如何使用vue-pdf實現(xiàn)PDF文件預覽的功能,文中的示例代碼講解詳細,具有一定的參考價值,感興趣的可以了解一下
    2023-03-03
  • 基于Vue3制作簡單的消消樂游戲

    基于Vue3制作簡單的消消樂游戲

    這篇文章主要為大家介紹了如何利用Vue3制作簡單的消消樂游戲,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起動手試一試
    2022-05-05

最新評論