zoukankan      html  css  js  c++  java
  • vue组件--通讯录

    简介

    在移动端开发中,通讯录是个很常见的需求。
    通讯录通常要实现以下功能

    • 首字母导航
    • 滚动到一定位置首字母固定

    在线通讯录demo

    image

    布局

    通讯录是典型的上下两栏布局,上面是header,下面是内容区,我们这里采用flexbox来实现。

    html,body,.page{height: 100%}
    .page{display: flex}
    .page-header{height: 44px}
    .page-content{
      flex: 1;
      overflow: auto;
      -webkit-overflow-scrolling: touch;
    }
    .navs {
      z-index: 2;
      position: fixed;
      right: 10px;
      top: 50px;
      bottom: 30px;
      text-align: center;
      color: #5d9ed3;
      font-size: 10px;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      span {
        cursor: pointer;
      }
    }
    
    <div class='page'>
      <div class='page-header'>通讯录</div>
      <main class='page-content' ref='content'>
        <div class='page-navs' ref='navs'>
          <!--首字母导航区域-->
        </div>
        <div class='page-items' ref='items'>
          <!--通讯录内容-->
          <div class='item' v-for='i in 26' :key='i'>
            <div class='item-head'>A</div>
            <div class='item-list'>
              <div class='item-head'>a链家-张带看</div>
              <div class='item-head'>a天团tony</div>
            </div>
          </div>
        </div>
      </main>
    </div>
    

    OK。上面的代码已经足够定义一个页面的雏形,

    • page-header 高度44,
    • page-content 占据剩余的全局的高度,并做内部的滚动。-webkit-overflow-scrolling: touch 会在容器里面开启高性能滚动。

    设置导航

    页面布局完成之后,可以初始化导航条了,为了方便起见,我们默认通讯录里面包含了从A到Z的全部姓名。

    • 文章默认使用 vue单文件组 件开发,如果您使用其他框架,请自行转换代码
    <template>
      <div class="page-navs">
        <span v-for='(item, index) in navs' :key='item'>{{item}}</span>
      </div>
    </template>
    
    <script>  
      data () {
        return {
          navs: "abcdefghijklmnopqrstuvwxyz".split("").map(i => i.toUpperCase());
        }
      }
    </script>  
    
    

    建立索引

    建立索引实际上是用js操作dom,获取通讯录内容区域内每个首字母出现的位置并存储起来,方便做跳转和滚动监听。

    <script>  
      moutend() {
        // 因为要获取dom属性,所以要在组件render后执行
        this.$nextTick(()=>{
          this.body = this.$refs.content;
          const navsEles = [...this.$refs.navs.querySelectorAll("span")]
          const itemsEles = [...this.$refs.items.querySelectorAll(".item")]
          
          // 获取导航栏字母的高度信息,方便做点击放大功能
          this.navsOffset = navsEles.map(item=>{
            return item.offsetTop || 0
          })
          
          // 获取通讯录内容区的首字母位置,方便做跳转和滚动监听
          this.itemsOffset = itemsEles.map(item=>{
            return item.offsetTop || 0
          })
        })
      },
      data () {
        return {
          body: null,
          itemsOffset: [],
          navsOffset: []
        }
      }
    </script>  
    

    监听跳转

    监听跳转比较简单,在 .page-navs span 标签上绑定click事件即可处理

    <template>
      <div class="page-navs">
        <span v-for='(item, index) in navs' :key='item' @click='jump(index)'>{{item}}</span>
      </div>
    </template>
    
    <script>  
      methods: {
        jump(index) {
          // 因为offsetTop属性是相对整个视口,而scrollTop是相对滚动容器,所以需要减去44px(header的高度)
          const offset = this.itemsOffset[index] - 44;
          this.body.scrollTop = offset;
        }
      },
      data () {
        return {
          navs: "abcdefghijklmnopqrstuvwxyz".split("").map(i => i.toUpperCase());
        }
      }
    </script>  
    
    

    监听滚动

    因为是在page-content元素内部滚动,所以可以通过在该元素上绑定scroll方法监听页面的滚动。局部滚动的好处是组件销毁时事件监听也移除了,不像监听body的滚动还需要在销毁前手动removeEventListenr。

    在执行滚动监听之前,我们还需要做两件事情

    1. itemsOffset 进行分组,划定监听的区间
    2. 在页面顶部创建一个展示 当前联系人首字母 的组件
    // 当前联系人首字母组件
    // 在这个组件里面也创建一个列表,用来做滚动的动画
    <template>
      <div class="first-word">
        <div class="acr-list" :style="'transform: translate3d(0,'+(currentIndex * -40)+'px,0);'">
          <div class="item" v-for='(item, index) in navs' :key='index'>{{item}}</div>
        </div>
      </div>
    </template>
    
    // 对 `itemsOffset` 进行分组,划定监听的区间
    mounted() {
      this.$nextTick(() => {
        let offsetCalc = this.offset.slice();
        offsetCalc.forEach((item, index) => {
          this.offsetList.push([item, offsetCalc[index + 1]]);
        });
      });
    }
    data() {
        return {
            currentIndex: -1,
            offsetList: []
        }
    }
    

    在准备工作做好之后,就开始监听容器的滚动行为,当滚动到通讯录之中的首字母部分时, 联系人首字母组件 也会自动滚动到里面相应的字母位置。

    点击右侧导航,也会触发滚动事件。

    // html模板部分
    <main class='page-content' @scroll='scroll' ref='content'></main>
    
    // js部分
    methods: {
        scroll() {
          this.currentIndex = this.getArea(this.body.scrollTop);
        },
        getArea(scrollTop) {
          // 80是首字母标组件的高度+通讯录首字母的高度
          scrollTop += 80;
          let index = -1;
          for (let i = 0, size = this.offsetList.length; i < size; i++) {
            let [start, end] = this.offsetList[i];
            if (scrollTop >= start && scrollTop < (end || 999999)) {
              index = i;
              break;
            }
          }
          return index
        },
    }
    

    更多

    点击右侧导航,有时候还要求在附近显示一个放大的字母,用于提醒点击了那个字母,通过前面获取的 navsOffset ,可以很方便的实现这个需求。至此,整个通讯录功能就基本完成了。

  • 相关阅读:
    mybatis 基于xml 配置的映射器
    【☆】素数打表--重要
    HDU--1084 What Is Your Grade?
    Bear and Three Balls
    【水题】HDU--1280 前m大的数
    HDU--1234 开门人和关门人
    HDU--1862 EXCEL排序
    HDU--1872 稳定排序
    聪明人的游戏,初中版 之目录
    SzNOI语法百题之1-10
  • 原文地址:https://www.cnblogs.com/small-coder/p/9146541.html
Copyright © 2011-2022 走看看