跳转到内容

元素不定大小隐藏做溢出隐藏

刀刀
0字
0分钟
2026/8/16

学习目标

  1. 需求效果的实现
  2. JavaScript能力锻炼
  3. IntersectionObserver 的使用

思路分析

一图流

效果实现思路主要是找到最后一个显示在容器内的DOM元素,计算它后面的个数,加上它自己本身,然后隐藏后面的元素并显示 +nn 为隐藏的元素个数 + 最后一个元素)。

假设总数为 6,最后一个显示的元素是 3,那么容器就展示 2 个元素,最后一项显示 6-3+1 ,即显示 +4。

流程

壳子搭建

流程壳子

页面首次加载时,由于无法确定哪个元素是最后一个显示的,因此先显示所有数据。声明变量数组存储展示数据和全部数据,循环生成高度不固定的元素。最外层容器高度使用随机数生成,模拟不固定高度需求。

js
const height = Math.floor(Math.random() * 400 + 50) + 'px'
const itemArr = reactive([]) // 最终在容器内展示的数据
const itemAll = reactive([]) // 全部的数据
for (let i = 0; i < 20; i++) {
  let item = {
    test: 'item' + i,
    height: Math.floor(Math.random() * 30 + 30) + 'px',
  }
  itemAll.push(item)
  itemArr.push(item)
}
vue
<template>
  <div
    id="father"
    class="father"
    :style="{
    width: '600px'
    height: height + 'px'
  }"
  >
    <div id="div1">
      <div
        v-for="item in itemArr"
        class="item"
        :style="{
          height: item.height,
        }"
      >
        {{ item.text }}
      </div>
    </div>
  </div>

  <div>总览: {{ itemAll.height }}</div>
</template>
css
.father {
  border: 1px solid red;
  overflow: hidden;
}
.item {
  border: 1px solid blue;
  margin-bottom: 10px;
  text-align: center;
  color: #fff;
}

判断最后一个元素

找到最后一个显示在容器内的 DOM 元素,关键 APIIntersectionObserver。它是构造函数,接受两个参数:回调函数和配置对象。

API 可监听一个或多个元素,获取元素可见性等属性。可见性改变时会再次触发,并拿到改变的元素。

onMounted 生命周期钩子中调用该 API,需要两个参数:回调函数会收到所有被观察元素的信息;

获取所有元素,循环为它们绑定 IntersectionObserver,通过 isIntersecting 属性判断当前元素是否可见;通过 intersectionRate 属性获取可见比例,比例为 1 表示完全可见,0.5 表示一半内容可见。

将溢出部分和最后一项从数组截断,计算不显示内容的数量,最后渲染。

observer.js
js
const initObserver = () => {
  let lastIndex = 0 // 最后一个显示的元素索引
  const observer = new IntersectionObserver((entries) => {
    console.log(entries) // 拿到所有观测的元素信息

    entries.forEach((entry, index) => {
      if (entry.isIntersecting) {
        lastIndex = index
      }
    })

    // 最后一个元素是否百分百显示
    if (entries[lastIndex]?.intersectionRate === 1) {
      lastIndex -= 1
    }

    // 判断是否溢出
    if (lastIndex < itemArr.length - 1) {
      // 可显示的内容
      const _arr = itemAll.slice(0, lastIndex)
      // 计算不显示的内容的数量
      const n = itemAll.length - lastIndex
      _arr.push({
        text: '+' + n,
        height: '40px',
      })
      itemArr = reactive(_arr)
    }
  })
  const itemList = document.querySelectorAll('.item')
  // 这里不能用 forEach,因为 document.querySelectorAll 拿到的是类数组,没有 forEach 方法
  for (let i = 0; i < itemList.length; i++) {
    // 观察列表每一项
    observer.observe(itemList[i])
  }
}
onMounted(() => {
  initObserver()
})

export default initObserver

添加新元素

新增元素后需重新调用 initObserver 方法重新计算,否则不会自动重新计算。

js
import initObserver from ' observer.js'
const addOne = () => {
  const addItem = {
    text: 'new item',
    height: Math.floor(Math.random() * 30 + 30) + 'px',
  }
  itemAll.unshift(addItem)
  itemArr.unshift(addItem)
  initObserver()
}

贡献者

The avatar of contributor named as v_duyilin v_duyilin
The avatar of contributor named as duyidao duyidao
The avatar of contributor named as 刀刀 刀刀

页面历史

刀刀博客累计访客 人;文档累计访问量共