Esquema de interacción de asociación de contenido y catálogo (etiqueta)

1. Primer código:

<template>
  <div>
    <h1>页面内容滚动与右侧导航标签互动关联 效果演示 demo</h1>
    <div class="content" id="content">
      <div class="left">
        <section v-for="(item, i) in list" class="text-node" :key="i" :id="'p' + i">
          <div class="title">
            <div class="title-pre"></div>
            <div v-html="item.title"></div>
          </div>
          <div class="text">
            <div v-html="item.text"></div>
          </div>
        </section>
      </div>
      <div class="right">
        <div class="entry-message">
          <div class="title">内容导航</div>
          <div class="content-anchor">
            <div>
              <el-timeline>
                <el-timeline-item
                  v-for="(item, index) in activities"
                  :key="index"
                  :color="active === index ? '#2b6afb' : ''"
                >
                  <div
                    @click="navToPosition(item, index)"
                    :style="{ color: active === index ? '#2b6afb' : '' }"
                  >
                    <span class="cn-pointer" v-html="item.title"></span>
                  </div>
                </el-timeline-item>
              </el-timeline>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
// 示例样本内容,提前声明赋值,方便后面复用
const text =
  "1、能源资源\n" +
  "能源资源包括煤、石油、天然气、水能等,也包括太阳能、风能、生物质能、地热能、海洋能、核能等新能源。纵观社会发展史,人类经历了柴草能源时期、" +
  "煤炭能源时期和石油、天然气能源时期,正向新能源时期过渡,并且无数学者仍在不懈地为社会进步寻找开发更新更安全的能源。但是," +
  "人们能利用的能源仍以煤炭、石油、天然气为主,在世界一次能源消费结构中,这三者的总和约占93%。\n" +
  "在一定历史时期和科学技术水平下,已被人们广泛应用的能源称为常规能源。那些虽古老但需采用新的先进的科学技术才能加以广泛应用的能源称为新能源。" +
  "凡在自然界中可以不断再生并有规律地得到补充的能源,称为可再生能源。经过亿万年形成的,在短期内无法恢复的能源称为非可再生能源。"


export default {
    
    
  name: "ScrollIntoView",
  data() {
    
    
    return {
    
    
      list: [
        {
    
    title: "能源开发与利用1", text: text},
        {
    
    title: "能源开发与利用2", text: text},
        {
    
    title: "能源开发与利用3", text: text},
        {
    
    title: "能源开发与利用4", text: text},
        {
    
    title: "能源开发与利用5", text: text},
        {
    
    title: "能源开发与利用6", text: text},
      ],
      active: 0,
      timeout: null,
      activities: [],
    };
  },
  mounted() {
    
    
    console.dir(document.getElementById("p1").getBoundingClientRect())
    this.init()
  },
  methods: {
    
    
    init() {
    
    
      const that = this
      // 从内容数据list中,获取段落标题作为导航标题。并为导航节点增加href,以段落的id值作为href的值
      this.list.map((item, i) => {
    
    
        this.activities.push({
    
    title: item.title, act: false, href: "#p" + i});
      });

      // 监听滚动条
      window.addEventListener("scroll", function (e) {
    
    
        // 防抖动处理
        clearTimeout(that.timeout)
        this.timeout = setTimeout(() => {
    
    
          that.activeNavNode(e)
        }, 100)
      });
    },
    // dom中定位导航
    navToPosition(item, index) {
    
    
      // 激活相应的导航节点,变色
      this.active = index;
      // 根据导航节点的href信息即id信息,获取对应的元素节点,通过 scrollIntoView 滚动该元素到可视区顶部
      document.querySelector(item.href).scrollIntoView(true);
    },
    // 激活左侧对应的导航条
    activeNavNode(e) {
    
    
      const nodes = document.getElementsByTagName("section")
      for (let i = 0; i < nodes.length; i++) {
    
    
        let node = nodes[i];
        // 获取该元素此时相对于视口的顶部的距离,即是元素顶部距离视口屏幕上边的距离
        let nodeY = node.getBoundingClientRect().y
        // 当元素距离视口顶部的距离在 [0,200] 之间,设置激活该元素对应左侧的导航标题,
        // 这个数字可以按需定义
        // 这里关联内容和导航标签,是巧妙利用了内容在元素集合中的索引序号和导航标签中的一致
        // 即是 list 和 activities 和 nodes 中下标相等的元素,具有对应关联的关系
        if (nodeY <= 200 && nodeY >= 0) {
    
    
          this.active = Number(i)
          return
        }
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.cn-pointer {
    
    
  cursor: pointer;
}

.content {
    
    
  display: flex;
  padding: 20px 0 100px 0;
  width: 1100px;
  min-width: 1100px;
  max-width: 1100px;
  align-content: center;
  margin: 0 auto;

  .left {
    
    
    flex-grow: 1;
    margin: 0 20px 500px 0;
    padding: 0 40px 40px;
    background: #ffffff;
    box-shadow: 0 2px 20px -6px rgba(30, 135, 240, 0.1);
    border-radius: 4px;
  }


  section {
    
    
    padding: 30px 0;

    .title {
    
    
      height: 25px;
      display: flex;
      align-items: center;
      margin-bottom: 20px;
      font-size: 18px;
      color: #262626;
      font-weight: bold;
      margin-top: 20px;

      .title-pre {
    
    
        width: 9px;
        height: 18px;
        margin-right: 10px;
        background: #1e87f0;
      }
    }

    .text {
    
    
      font-size: 14px;
      color: #262626;
      line-height: 44px;
      font-weight: 400;
      text-align: left;

      span {
    
    
        display: block;
        margin-bottom: 20px;
      }
    }
  }

  .right {
    
    
    min-width: 300px
  }

  .entry-message {
    
    
    box-sizing: content-box;
    padding: 26px 30px;
    background: #ffffff;
    box-shadow: 0 2px 20px -6px rgba(30, 135, 240, 0.1);
    border-radius: 4px;
    position: fixed;
    top: 105px;

    .title {
    
    
      margin-bottom: 24px;
      font-size: 18px;
      color: #262626;
      font-weight: 600;
    }

    .content-anchor {
    
    
      display: flex;
      flex-direction: row;
      align-items: center;
    }
  }
}
</style>

Efecto:
inserte la descripción de la imagen aquí

Puntos de conocimiento que deben reservarse 1:

Punto técnico 1: Element.scrollIntoView().

El método scrollIntoView() de la interfaz Element desplaza el contenedor principal del elemento, haciendo que el elemento en el que se llama scrollIntoView() sea visible para el usuario.

> 语法
> 
element.scrollIntoView(); // 等同于element.scrollIntoView(true)
element.scrollIntoView(alignToTop); // Boolean型参数
element.scrollIntoView(scrollIntoViewOptions); // Object型参数

Punto técnico 2: Element.getBoundingClientRect()
El método Element.getBoundingClientRect() devuelve el tamaño del elemento y su posición relativa a la ventana gráfica. El valor devuelto es un objeto DOMRect, que es una colección de rectángulos devueltos por el método getClientRects() del elemento, que es el tamaño del borde CSS del elemento. El resultado devuelto es el rectángulo más pequeño que contiene el elemento completo y tiene propiedades de solo lectura en píxeles para izquierda, arriba, derecha, abajo, x, y, ancho y alto que describen todo el borde. Las propiedades distintas del ancho y la altura se calculan en relación con la esquina superior izquierda de la ventana de visualización.
getBoundingClientRectmdnAddress

La dificultad de implementación es que el contenido ha cambiado ¿Cómo activar el directorio de la derecha?

  1. Obtenga la distancia del elemento en relación con la parte superior de la ventana gráfica en este momento, es decir, la distancia desde la parte superior del elemento hasta la parte superior de la pantalla de la ventana gráfica.
  2. Inteligentemente hace uso de la consistencia del número de índice del contenido en la colección de elementos y la etiqueta de navegación .

Supongo que te gusta

Origin blog.csdn.net/qq_42931285/article/details/124367633
Recomendado
Clasificación