vue 字母排序索引列表、实现点击滚动效果,可用于通讯录、城市

固定在侧边的字母索引列表,新建一个aIndex.vue组件

<script>
export default {
  name: 'a-index',
  props: {
    //字母列表
    List: {
      type: Array,
      default: () => []
    },
    //当前字母索引
    activeId: {
      type: String,
      default: () => ''
    }
  },

  methods: {
    //点击字母
    go(letter) {
      this.$emit('go', letter)
    },
  }
}
</script>

<template>
  <div class="alphabet">
    <dl
      class="letter-list"
    >
      <dt
        v-for="item in List"
        :key="item.letter"
        @click.capture="go(item.letter)"
        class="letter-item"
        :class="{
          current: activeId == item.letter
        }"
      >
        {{ item.letter }}
      </dt>
    </dl>
  </div>
</template>

<style lang="less" scoped>
.alphabet{
  position: absolute;
  top: 50%;
  right: 7px;
  transform: translateY(-50%);
  z-index: 100;
  .letter-list {
    color: #C2CCD0;
    font-size: 12px;
    .letter-item {
      height: 15px;
      line-height: 15px;
      width: 15px;
      font-size: 12px;
      text-align: center;
      position: relative;
      cursor: pointer;
      &.current {
        color: #4598F0;
        background: #F1F4F9;
        border-radius: 50%;
      }
    }
  }
}
</style>

代码片段

处理要展示的数据,新建一个utils.js,这里需要安装pinyin插件 npm install pinyin-pro --save

export const AlphabetMap = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".split(
  ","
);

//初始化数据,按首字母分离
export function initList(list) {
  let letters = []; // 数据列表
  let listsMap = {}; // 每一个索引指向一个数组,这个数组存储该字母索引的朋友项
  list.forEach(item => {
    let name = item.jobName.trim()
    let firstLetter = ''
    if(name[0]) {
      firstLetter = pinyin(name[0], {toneType: 'none'}).charAt(0).toUpperCase();
    }
    if (!AlphabetMap.includes(firstLetter)) {
      firstLetter = "#";
    }
    listsMap[firstLetter] || (listsMap[firstLetter] = []);
    listsMap[firstLetter].push(item);
  });
  for (let letter in listsMap) {
    letters.push({
      letter: letter,
      children: listsMap[letter]
    });
  }
  // 按首字母排序
  // 因此这里需要通过小于号比较
  letters.sort((a, b) => {
    return a.letter.localeCompare(b.letter);
  });
  // 将#栏放入最后
  if(letters[0].letter == '#') {
    letters.push(letters.shift()); 
  }
  return letters;
}

在页面中使用,引入这两个文件

注意: 实现滚动效果时要记得不能使用display:none;否则会获取不到滚动距离!!!

<script>
import {AIndex} from 'packages/a-index'
import { initList } from './utils'

export default {
  components: {
    AIndex
  },

  data () {
    return {
      activeId: '',
      postsList: [], //需要处理的数据
    }
  },

  mounted() {
    this.postsList = initList(postsList)
    let timeId;
    window.addEventListener('scroll', () => {
      clearTimeout(timeId);
      timeId = setTimeout(() => {
        this.scrollToTop();
      });
    } , true);
  },

  methods: {
    //点击滚动到当前字母
    goTop(letter) {
      this.$el.querySelector('[id="' + letter + '"]').scrollIntoView();
    },
    // 监听页面元素滚动,改变导航栏选中
    scrollToTop() {
      // dom滚动位置
      let scrollTop = document.querySelector("#letterBlocks").scrollTop;

      this.postsList.map((v,i) => {
        // 获取监听元素距离视窗顶部距离
        let offsetTop = document.getElementById(v.letter).offsetTop;
        // 获取监听元素本身高度
        let scrollHeight = document.getElementById(v.letter).scrollHeight;
        // 如果 dom滚动位置 >= 元素距离视窗距离 && dom滚动位置 <= 元素距离视窗距离+元素本身高度
        // 则表示页面已经滚动到可视区了。
        if (scrollTop >= offsetTop && scrollTop<=(offsetTop+scrollHeight)) {
          this.activeId = v.letter;
        }
      })
      //如果滑到顶部,去掉字母悬浮样式
      if(scrollTop <= 40) {
        this.activeId = ''
      }
    },
  },

  destroyed() {
    window.removeEventListener('scroll')
  }
}
</script>

<template>
  <div class="list">
      <div class="list-post" ref="letterBlocks" id="letterBlocks">
        <div v-for="item in postsList" :key="item.letter" :id="item.letter" :class="{top: activeId == item.letter}">
          <div class="letter" :class="{active: activeId == item.letter}">
              {{ item.letter }}
          </div>
          <div v-for="i in item.children" :key="i.id">
              <span>i.jobName</span>
          <div>
        </div>
        <a-index class="a-index" :activeId="activeId" :List="postsList" @go="goTop"></a-index>  
      </div>
   </div>
</template>
    
<style lang="less" scoped>
.list{
  height: 100%;
  position: relative;
  .list-post {
    padding-right: 22px;
    height: 100%;
    overflow-y: overlay;
    .letter {
      padding-left: 16px;
      width: 100%;
      height: 32px;
      line-height: 32px;
      font-size: 14px;
      color: #768893;
    }
    .active {
      background: #fff;
      box-shadow: 0px 3px 4px 0px #0C213F0F;
      position: absolute;
      top: 0;
      z-index: 99;
    }
  }
  .top {
    padding-top: 32px;
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值