实现A-Z滑动检索菜单

写个这小玩意真麻烦

html 复制代码
<template>
  <div id="retrieve-components">
    <el-input v-model="searchVal" @input="search" placeholder="请输入" class="mb-10"></el-input>
    <div class="box flex" id="box">
      <div class="letter">
        <div v-for="(item, index) in letter" :key="index" class="mb-2 item" :class="[{active:selectItem == item}]" :id="`left-key-${item}`" @click="retrieveClick(item)">
          {{ item }}
        </div>
      </div>

      <div class="data-right-box" ref="scrollContainer" @scroll="handleScroll">
        <div v-for="(item, index) in peoArray" :key="index" @click="onSelect(item, index)">
          <p class="data-key" :id="`right-key-${item.key}`">{{ item.key }}</p>
          <p class="data-list" v-for="(ele, e) in item.list" :key="e">{{ ele.name }}</p>
        </div>
      </div>

    </div>
    <el-tree :data="peoArray" :props="defaultProps" show-checkbox node-key="id" default-expand-all :expand-on-click-node="false">
      <span class="custom-tree-node" slot-scope="{ node, data }">{{ node.label }}</span>
    </el-tree>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selectItem: "A",
      letter: [],
      defaultProps: {
        children: 'list',
        label: 'name'
      },
      peoArray: [
        {key: "A", list: [{name: "安吉"}, {name: "安吉"}]},
        {key: "B", list: [{name: "bar饿啊额日"}, {name: "芭比"}]},
        {key: "C", list: [{name: "啛啛喳喳"}, {name: "吃炒菜"}]},
        {key: "D", list: [{name: "滴滴滴"}]},
        {key: "E", list: [{name: "鹅鹅鹅"}]},
        {key: "F", list: [{name: "方慧"}]},
        {key: "G", list: [{name: "哥哥"}]},
        {key: "H", list: [{name: "话说"}]},
        {key: "I", list: [{name: "ID额我热饭v"}]},
        {key: "J", list: [{name: "接化发"}]},
        {key: "K", list: [{name: "KFC"}]},
        {key: "L", list: [{name: "吕布"}]},
        {key: "M", list: [{name: "没读书"}]},
        {key: "N", list: [{name: "牛头人"}]},
        {key: "O", list: [{name: "O泡果奶"}]},
        {key: "P", list: [{name: "判断得我"}]},
        {key: "Q", list: [{name: "秦三儿"}]},
        {key: "R", list: [{name: "如果更方便"}]},
        {key: "S", list: [{name: "塞班"}]},
        {key: "T", list: [{name: "糖糖"}]},
        {key: "U", list: [{name: "U哈哈哈哈"}]},
        {key: "V", list: [{name: "V ME 50"}]},
        {key: "W", list: [{name: "王富贵"}]},
        {key: "X", list: [{name: "喜羊羊"}]},
        {key: "Y", list: [{name: "阳顶天"}]},
        {key: "Z", list: [{name: "自发热"}]}
      ],
      leftClickFlag: false,
      searchVal: "",
    };
  },
  computed: {},
  mounted() {
    this.letter = Array.from({length: 26}, (_, i) => String.fromCharCode(65 + i));
    // this.$refs.scrollContainer.addEventListener('scroll', this.debounce(this.handleScroll, 200));
  },
  methods: {
    search() {

    },
    handleScroll(event) {
      let timeout;
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      timeout = setTimeout(() => {
        // this.leftClickFlag = false;
        const container = document.querySelector('#box');
        const closestElement = this.getClosestElementToTop(container);
        this.selectItem = closestElement;
        // if (!this.leftClickFlag) {
        this.scrollOn(`left-key-${closestElement}`);
        // }
      }, 500);
    },
    debounce(func, wait) {
      let timeout;
      return function (...args) {
        const later = () => {
          clearTimeout(timeout);
          func.apply(this, args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    },
    getClosestElementToTop(container) {
      const elements = document.querySelectorAll(".data-key");
      // console.log("container.getBoundingClientRect().top", container.getBoundingClientRect().top);
      let closestElement = null;
      let closestDistance = Infinity;
      for (let element of elements) {
        const rect = element.getBoundingClientRect();
        const distance = Math.abs(rect.top - container.getBoundingClientRect().top);
        // console.log("rect.top", rect.top, distance, distance < closestDistance);
        if (distance < closestDistance) {
          closestDistance = distance;
          closestElement = element;
        }
      }
      return closestElement.innerText;
    },
    retrieveClick(item) {
      this.leftClickFlag = true;
      this.selectItem = item;
      this.scrollOn(`right-key-${item}`);
    },
    scrollOn(item) {
      let target = document.getElementById(item);
      if (target) {
        target.scrollIntoView({behavior: "smooth" /*smooth || auto*/});
      }
    },
    // 点击通讯录
    onSelect(item, index) {
      console.log(item, index);
    }
  },
  beforeDestroy() {
    // this.$refs.scrollContainer.removeEventListener('scroll', this.debounce(this.handleScroll, 200));
  }
};
</script>

<style lang="scss" scoped>
#retrieve-components {
  padding: 10px;
  width: 400px;
  height: 200px;
  background: #fff;

  .box {
    height: calc(100% - 42px);

    .letter {
      font-size: 12px;
      margin-right: 20px;
      justify-content: space-between;
      overflow-y: auto;

      .item {
        padding: 1px;
        cursor: pointer;
        text-align: center;

        &.active {
          background: pink;
        }
      }
    }

    .data-right-box {
      height: 100%;
      overflow-y: auto;
      flex: 1;
      width: 100%;
      padding: 0 10px;

      .data-key {
        margin: 10px 0;
        font-size: 12px;
        background-color: #f3efef;
      }

      .data-list {
        margin: 20px 0;
      }
    }
  }
}

</style>
相关推荐
出逃日志21 分钟前
JS的DOM操作和事件监听综合练习 (具备三种功能的轮播图案例)
开发语言·前端·javascript
XIE39228 分钟前
如何开发一个脚手架
前端·javascript·git·npm·node.js·github
GISer_Jing1 小时前
React渲染相关内容——渲染流程API、Fragment、渲染相关底层API
javascript·react.js·ecmascript
山猪打不过家猪1 小时前
React(五)——useContecxt/Reducer/useCallback/useRef/React.memo/useMemo
前端·javascript·react.js
前端青山1 小时前
React事件处理机制详解
开发语言·前端·javascript·react.js
对卦卦上心1 小时前
React-useEffect的使用
前端·javascript·react.js
练习两年半的工程师1 小时前
React的基本知识:事件监听器、Props和State的区分、改变state的方法、使用回调函数改变state、使用三元运算符改变state
前端·javascript·react.js
GIS好难学1 小时前
《Vue零基础入门教程》第二课:搭建开发环境
前端·javascript·vue.js·ecmascript·gis·web
蒟蒻的贤3 小时前
vue11.22
开发语言·前端·javascript
三金121383 小时前
VUE 的前置知识
vue