vue移动端滚动选择器的实现

滚动选择器的实现

前两天在公司用vue开发移动端的项目,遇到一个功能,要求弹出一个选择器,默认选中中间的值,要求选中的值跟着滚动改变,由于没有外网,只能自己开发一个来实现这个需求。第一次写博客,写的不好,勿喷~

代码如下:

<template>
  <div class="picker-main">
    <button @click="showPicker()">选择器</button>
    <span>{{city}}</span>
    <div
      v-if="show"
      class="picker"
    >
      <section class="picker-main">
        <h3>
          <span @click="show = false">取消</span>
          <span>请选择</span>
          <span @click="sure()">确认</span>
        </h3>
        <ul ref="ul">
          <li
            v-for="(item, index) in list"
            :key="index"
            :class="active==item.id?'active':active==item.id-1||active==item.id+1?'active2':null"
            :ref="'li'+item.label"
          >{{item.val}}</li>
        </ul>
      </section>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        { id: -9, city: "", label: "a" },
        { id: -9, city: "", label: "b" },
        {
          id: 0,
          val: "北京",
          label: "bj"
        },
        {
          id: 1,
          val: "上海",
          label: "sh"
        },
        {
          id: 2,
          val: "广州",
          label: "gz"
        },
        {
          id: 3,
          val: "深圳",
          label: "sz"
        },
        {
          id: 4,
          val: "北海",
          label: "bh"
        },
        { id: -9, city: "", label: "c" },
        { id: -9, city: "", label: "d" }
      ],
      show: false,
      active: 0,
      city: "",
      listOffsetTop: [],
      timer: null
    };
  },
  methods: {
    showPicker() {
      this.show = true;
      this.active = 0;
      this.timer = setTimeout(() => {
        clearTimeout(this.timer);
        this.getOffsetTop();
        this.computeActive();
      }, 50);
    },
    sure() {
      this.list.map((item, index) => {
        item.id == this.active ? (this.city = item.val) : null;
      });
      this.show = false;
    },
    getOffsetTop() {
      this.listOffsetTop = [];
      this.list.map((item, index) => {
        let liTop = this.$refs["li" + item.label];
        this.listOffsetTop.push(liTop[0].offsetTop - 41);
      });
    },
    computeActive() {
      let scroll = this.$refs.ul;
      scroll.addEventListener("scroll", () => {
        this.listOffsetTop.map((item, index) => {
          item <= scroll.scrollTop + 100 ? (this.active = index - 2) : null;
        });
      });
    }
  }
};
</script>
<style lang="less" scoped>
.picker {
  background-color: rgba(0, 0, 0, 0.2);
  max-height: 100vh;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  display: flex;
  .picker-main {
    width: 100%;
    position: absolute;
    bottom: 0;
    background-color: #fff;
    h3 {
      padding: 0;
      margin: 0;
      display: flex;
      justify-content: space-around;
      border-bottom: solid 1px #ddd;
      font-size: 20px;
      line-height: 40px;
    }
    ul {
      max-height: 250px;
      padding: 0;
      margin: 0;
      overflow: auto;
      background-color: #fff;
      li {
        list-style: none;
        font-size: 25px;
        line-height: 50px;
        text-align: center;
        opacity: 0.3;
        height: 50px;
        background-color: #fff;
      }
    }
  }
}
.active {
  background-color: #ddd !important;
  color: #333;
  opacity: 1 !important;
}
.active2 {
  color: #333;
  opacity: 0.6 !important;
}
</style>

我简单的提一下思路,首先我们点击按钮弹出选择器,如下图:vue移动端滚动选择器的实现_第1张图片

1.我们在弹出方法的时候设置一个settimeout()方法,目的是为了数据能够挂载到页面上去之后在执行下面的方法,如果没有这个方法,就获取不到指定的ref的值。
2.循环遍历list数组,用数组listOffsetTop来存储每一条数据渲染后的offsetTop。
3.给列表的父容器ul添加一个scroll监听,当父容器的scrollTop发生变化时能够监听到变化。
4.遍历listOffsetTop数组,用父容器的scrollTop和数组listOffsetTop内的值进行比较,通过判断的值进行改变选中的目标值

至此,滚动选择器功能就已经实现了,希望这篇文章对大家有所帮助(第一次写博客,望大家包含,谢谢!)

有疑问的可以和我一起探讨改进!
QQ:981661072

你可能感兴趣的:(前端功能小demo)