vue JS实现类似通讯录的字母索引

本文通过示例展示了如何使用 Vue.js 编写一个类似于通讯录的字母索引功能,直接提供代码帮助理解实现过程。

vue JS实现类似通讯录的字母索引

示例

点击侧边栏

话不多说直接上代码

<template>
  <div class="brand-f-s">
    <el-input
      placeholder="请选择内容"
      v-model="input"
      clearable
      @focus="focus"
      @blur="blur">
    </el-input>
    <div class="brand" id="brand" v-show="show" @click="brand">
      <div class="left" id="left">
        <div class="left-item" id="left-item" v-for="(item,index) in letters" :key="index" :class="cur_letter==item?'active':''" 
          @click="selectLetter(item, index)">
          <div v-if="cur_letter==item" class="yuan"></div>
          {{ item }}
        </div>
      </div>
      <div class="right" id="right" >
        <div ref="aTop" class="right-item" v-for="(item1,index) in letters" :key="index">
          <a class="title default" href="javascript:void(0);">{{ fixedTitle }}</a>
          <a class="title" href="javascript:void(0);">{{ item1 }}</a>
          <div v-for="(item2,index) in dataList" :key="index"  
            @click="selectBrand(item2)">
            <div class="right-item" v-if="item1 == item2.groupName">{{ item2.makeName }}</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      input: '',
      cur_letter: 'A',
      letters: [],// 字母列表
      dataList: [],// 数据
      listHeight: [],
      // diff: -1,
      currentIndex: 0,
      fixedTitle: 'A',
      flag: true,
      flag2: true,
      show: false,
      ispageshow: true
    }
  },
  props: {
    data: {}
  },
  mounted(){
    this.dataList = [
        {
            "groupName": "A",
            "makeName": "文案A",
        },
        {
            "groupName": "A",
            "makeName": "文案",
        },
        {
            "groupName": "A",
            "makeName": "文案A",
        },
        {
            "groupName": "A",
            "makeName": "文案A",
        },
        {
            "groupName": "A",
            "makeName": "文案A",
        },
        {
            "groupName": "B",
            "makeName": "文案B",
        },
        {
            "groupName": "B",
            "makeName": "文案B",
        },
        {
            "groupName": "B",
            "makeName": "文案B",
        },
        {
            "groupName": "C",
            "makeName": "文案C",
        },
        {
            "groupName": "C",
            "makeName": "文案C",
        },
    ]
    this.getletters()
    document.getElementById('right').onscroll = this.onscroll
    document.body.addEventListener("click",()=> {
      if(!this.flag2){//点击 brand 不隐藏
        this.show = false
        this.flag2 = true
      }else{
        this.show = true
        setTimeout(()=>{
          this.flag2 = false
        })
      }
    })
    
  },
  updated(){
  },
  methods:{
    getletters(){
      for(let i = 0;i < this.dataList.length;i++){
        let ele = this.dataList[i]
        // console.log(this.letters.indexOf(ele.groupName) )
        if(this.letters.indexOf(ele.groupName) == -1){
          this.letters.push(ele.groupName)
        }
      }
    },
    focus(){
      this.show = true
      if(this.ispageshow){
        this.ispageshow = false
        setTimeout(()=>{
          this.getHeight()
        })        
      }

    },
    brand(){
      this.show = true
    },
    selectLetter(item,index){
      console.log(item)
      let distance = 0
      this.flag2 = true
      for(let i = 0;i < this.$refs.aTop.length;i++){
        let ele = this.$refs.aTop[i]
        if(index > i){
          distance = ele.offsetHeight + distance
        }else{
          break
        }
      }
      let left = document.getElementById('left');
      let leftItem = document.getElementById('left-item');
      // 侧边栏字母位置
      for (let i = 0; i < this.letters.length - 1; i++) {
        if(this.cur_letter != 'A' && this.cur_letter != 'B' && this.cur_letter != 'C'){
          if (this.letters[i] == this.cur_letter) { 
          // 侧边栏字母位置
            left.scrollTo(0,(leftItem.offsetHeight*index)-(leftItem.offsetHeight*3))
            break
          }
        }
      }  
      document.getElementById('right').scrollTo(0,distance)
      this.cur_letter = item
      this.fixedTitle = item
      this.flag = false
      setTimeout(()=>{
        this.flag = true
      })
    },
    selectBrand(item){
      console.log(item)
      this.input = item.makeName
      setTimeout(()=>{
        this.show = false
      })
      
    },
    getHeight(){
      let distance = 0;
      this.listHeight.push(distance)
      if(!this.$refs.aTop) return
      for(let i = 0;i < this.$refs.aTop.length;i++){
        let ele = this.$refs.aTop[i]
        distance = ele.offsetHeight + distance
        this.listHeight.push(distance)
      }
    },
    onscroll(){
      if(!this.flag) {
        return
      }
      let right = document.getElementById('right')
      let newY = document.getElementById('right').scrollTop;
      let left = document.getElementById('left');
      let leftItem = document.getElementById('left-item');
      right.height = '100%'
      // 当滚动到顶部时, newY<=0
      if (newY <= 0) {
        this.currentIndex = 0
        return
      }
      // 中间部分滚动
      for (let i = 0; i < this.listHeight.length - 1; i++) {
        var height1 = this.listHeight[i]
        var height2 = this.listHeight[i + 1]
        if (!height2 || (newY >= height1 && newY < height2)) {
          this.currentIndex = i
          this.cur_letter = this.letters[i] 
          this.fixedTitle = this.letters[i] 
          // 侧边栏字母位置
          if(this.cur_letter != 'A' && this.cur_letter != 'B' && this.cur_letter != 'C'){
            left.scrollTo(0,(leftItem.offsetHeight*i)-(leftItem.offsetHeight*3))
          }
          return
        }
      }  
      // 滚动到底部且newY大于最后一个元素的上限
      this.currentIndex = this.listHeight.length - 1
      this.cur_letter = this.letters[this.listHeight.length - 1]
       this.fixedTitle = this.letters[this.listHeight.length - 1]
    },
  }
}
</script>

<style lang="scss" scoped>

.default{
  position: absolute;
  display: block;
  background-color: #fff;
  width: 100%;
  padding-top: .5rem;
  top: 0;
}
.brand-f-s{
  padding-left: 1rem;
  position: relative;
  flex: 1;
}
.active{
  color: #409eff;
}
.yuan{
  width: 5px;
  height: 5px;
  border-radius: 50%;
  border: 1px solid #409eff;
}
.brand{
  display: flex;
  height: 12.5rem;
  position: absolute;
  background-color: #fff;
  width: 100%;
  box-sizing: border-box;
}
.left{
   cursor:pointer;
   height: 100%;
   overflow-y: scroll;
   border-left: 1px solid #DCDFE6;
   border-right: 1px solid #DCDFE6;
   padding-left: .5rem;
   .left-item{
     padding: .3125rem .3125rem .3125rem 1rem;
     position: relative;
     border-left: 1px solid #DCDFE6;
     div{
       position: absolute;
       left: 0;
       z-index: 999;
       top: 50%;
       transform: translate(-50%,-50%);
     }
   }
}
.right{
  background: #fff;
  flex: 1;
  // height: 100%;
  overflow-y: scroll;
  padding-left: .5rem;
}
.right-item{
  padding: .3125rem;
   cursor:pointer;
}
.left::-webkit-scrollbar,.right::-webkit-scrollbar {
  display: none; /* Chrome Safari */
} 
.title{
	text-decoration: none; /* 去除默认的下划线 */
	outline: none;	/* 去除旧版浏览器的点击后的外虚线框 */
	color: #000;	/* 去除默认的颜色和点击后变化的颜色 */
  font-weight: 700;
}
/*包含以下四种的链接*/
a {
    text-decoration: none;
}
/*正常的未被访问过的链接*/
a:link {
    text-decoration: none;
}
/*已经访问过的链接*/
a:visited {
    text-decoration: none;
}
/*鼠标划过(停留)的链接*/
a:hover {
    text-decoration: none;
}
/* 正在点击的链接*/
a:active {
    text-decoration: none;
}
</style>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值