【Vue】随机点名组件的实现

904 阅读1分钟

需求

将一份名单渲染到页面上,页面中有一个按钮,点击按钮随机从名单中抽取一个人,要有动态效果。

点名.gif

实现

完整代码

<template>
  <div>
    <div class="name-list">
      <div
        class="name"
        :class="index === selectedIndex ? 'selected' : ''"
        v-for="(name, index) in list"
        :key="index"
      >
        {{ name }}
      </div>
    </div>
    <div class="select-btn">
      <button @click="startSelect">点击进行抽取</button>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    list: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      selectedIndex: 0, //被抽中的人在数组中的下标
      timeID: "", //当前定时器的ID
    };
  },
  methods: {
    //开始抽取
    startSelect() {
      //要使用节流阀
      if (this.timeID) return; //保持只有一个定时器在运作
      //定时器
    //   this.selectedIndex = 0; //从第一个人开始抽取
      const MIN = this.list.length; //生成随机数的左区间
      const MAX = this.list.length * 3; //生成随机数的右区间
      let end = Math.floor(MIN + Math.random() * (MAX - MIN)); //终止抽取
      console.log(end);
      let count = 0; //计数器
      this.timeID = setInterval(() => {
        //先判断,再执行
        if (end === count) {
          clearInterval(this.timeID); //清除定时器
          this.timeID = ""; //置空,不然只能抽取一次
        }
        if (this.selectedIndex === this.list.length - 1) {
          this.selectedIndex = 0; //置零,不然下标溢出了
        } else {
          //置零和自加是互斥的,不然的话刚置零又被自加成1了
          this.selectedIndex++;
        }
        count++;
      }, 100);
    },
  },
};
</script>

<style scoped>
.name-list {
  width: 600px;
  /* height: 300px; */
  margin: 0 auto;
  /* border: 1px black solid; */

  display: flex;
  /* 项目排列方向 默认row 左到右*/
  flex-direction: row;
  /* 项目换行 默认nowrap不换行 wrap第一行在上*/
  flex-wrap: wrap;
  /* 项目在主轴的对齐方式 水平分隔*/
  justify-content: space-between;
  /* 项目在交叉轴的对齐方式 垂直居中*/
  align-items: center;
  /* 多根轴线的对齐方式 */
  align-content: flex-start;
}
.name {
  min-width: 10%;
  margin: 1px;

  padding: 5px;
  border: 1px solid black;
  text-align: center;
}
.selected {
  background-color: rgb(30, 216, 230);
  font-weight: bold;
}
.select-btn {
  text-align: center;
  margin-top: 30px;
}
</style>

代码分析

props: {
    list: {
      type: Array,
      required: true,
    },
},

组件的属性,list是一个数组,接收父组件传进来的名单,然后渲染在页面上。

本来打算给组件多添加几个属性的,比如控制方向的direction,控制抽取结果的result,控制光圈移动次数的movetimes等等,后面再加吧。

//开始抽取
startSelect() {
  //要使用节流阀
  if (this.timeID) return; //保持只有一个定时器在运作
  //定时器
//   this.selectedIndex = 0; //从第一个人开始抽取
  const MIN = this.list.length; //生成随机数的左区间
  const MAX = this.list.length * 3; //生成随机数的右区间
  let end = Math.floor(MIN + Math.random() * (MAX - MIN)); //终止抽取
  console.log(end);
  let count = 0; //计数器
  this.timeID = setInterval(() => {
    //先判断,再执行
    if (end === count) {
      clearInterval(this.timeID); //清除定时器
      this.timeID = ""; //置空,不然只能抽取一次
    }
    if (this.selectedIndex === this.list.length - 1) {
      this.selectedIndex = 0; //置零,不然下标溢出了
    } else {
      //置零和自加是互斥的,不然的话刚置零又被自加成1了
      this.selectedIndex++;
    }
    count++;
  }, 100);
},

一开始先判断timeID的值是否为空,不为空说明已经有一个定时器在运作了,直接退出方法。

然后是一些配置参数吧,比如通过随机生成end,来控制光标移动多少次后停下来。count是计数器,从0开始自加,当count等于end的时候就停止抽取了。

selectedIndex则是当前被抽取到的名字在数组中的下标,通过控制它的初始值和自增还是自减可以实现控制光标移动的方向。