接上一章的内容继续讲,本次的主题是用vue实现列表有间隔的平滑滚动。

        那么按照惯例,我们还是先来分析问题。还是以向上滚动举例,每隔三秒列表滚动一行。先不考虑平滑的问题,如果只是让列表每隔三秒向上滚动一行,这其实很简单,各位也猜到了,按我的习惯,还是用定时器来解决。

        设置定时器,每三秒,让列表向上移动一行的高度,然后当最后一条数据出现时,在下一个三秒后,恢复到初始状态。

        下面是上面描述的代码实现:

    tableTimerFun() {
      var count = 0;  //每滚动一次,count加1
      //tableList是列表的数据对象,maxCanSee代表可视范围内的最大完整数据条数
      if (this.tableList.length > this.maxCanSee) {  
        this.tableTimer = setInterval(() => {
          //如果还没滚动到最后一条数据,则列表向上移动以上的高度
          if (count < this.tableList.length - this.maxCanSee) { 
            this.tableTop -= this.tableLineHeight;   //tableLineHeight代表列表中一行的高度
            count++;   //每滚动一次,count加1
          } else {   //如果滚动到最后一条,则恢复初始状态
            count = 0;
            this.tableTop = 0;
          }
        }, 3000);
      }
    },

        上面的内容已经实现了列表间隔一段时间滚动,接下来就是解决平滑的问题。这次我们不像上一章一样让列表每隔0.1s向上滚动1个像素,用高频位移创造平滑移动的视觉效果。这次我们直接用css来处理。

        css中有个非常好用的动态样式写法 transition,它可以让其渲染的对象在位置、尺寸等发生变化时,平滑的变化。所以我们直接让列表的容器获得以下样式:

transition: all 0.5s;

        偷懒可以直接写all,如果你有特定的需求或者只让某种样式平滑变化,还是去看官方文档,这里我不多说明。0.5s就是变化的时间。

        至此,用vue实现列表有间隔的平滑滚动其实已经实现了,但还有瑕疵,就是当最后一条数据出现,然后重置初始状态时,列表会快速滚动到列表头部。其实也不难理解,按上面的写法,正常情况都是向上移动一行的高度,而最后一条重置到初始状态时却移动了接近整个列表的高度。所以这个过程中会看到列表快速滚动。说是瑕疵但也不是瑕疵,看具体需求。有解决方案,这个放到下一篇文章讲。

        剩下的其实就是做数据大屏的开发要考虑数据不足的情况,举个例子,可视范围内列表最多现实6条,但调接口只显示了3条,这时候列表其实时不需要滚动的,这个放到以后讲,但是下面的完整代码中有,有兴趣的可以提前了解一下。

        下面是完整代码,还是那句话:下面的代码直接粘贴运行不会运行成功,因为下面的完整代码涉及接口调用,但所有功能已经一步到位,希望在看的你能通过注释更多地去理解,而不是简单地复制粘贴。希望能对你有所帮助。

<template>
  <div class="orderProcess">
    <div class="loading_div" v-show="!showFlag">
      <!-- Loading样式自己写,不需要,直接删除即可 -->
      <div>Loading...</div>
    </div>
    <div class="success_info_body" v-show="showFlag">
      <div class="table_head">
        <div class="tr1 tr">订单号</div>
        <div class="tr2 tr">项目名称</div>
        <div class="tr3 tr">需求方量</div>
        <div class="tr4 tr">预交付日期</div>
        <div class="tr5 tr">进度</div>
      </div>
      <div class="table_body">
        <!-- tableTop随时间推移不对增减,即列表不断往上 -->
        <div class="table_list" :style="{top: tableTop + 'px'}"> 
          <div
            class="tr_div"
            v-for="(item,index) in tableList"
            :key="index"
            :class="{'exception_style_tr':item.overDays>6 && item.process < 100}"
          >
            <div
              class="tr1 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
            >{{item.orderNo}}</div>
            <div
              class="tr2 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
            >{{item.projectName}}</div>
            <div
              class="tr3 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
              v-if="item.needVol!='-'&&item.needVol!='无法计算'"
            >{{Number(item.needVol).toFixed(3)}} m³</div>
            <div
              class="tr3 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
              v-else
            >-</div>
            <div
              class="tr4 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
            >{{item.completeDate}}</div>
            <div
              class="tr5 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
              v-if="item.process!='-'"
            >{{Number(item.process).toFixed(2)}} %</div>
            <div
              class="tr5 tr"
              :class="{'exception_style':item.overDays>6 && item.process < 100, 'notice_style':item.overDays>0 && item.overDays<7 && item.process < 100}"
              v-else
            >-</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tableTimer: null,
      tableTop: 0,  //列表向上移动的像素
      tableList: [], //tableList是列表的数据对象
      showFlag: false,
      componentTimer: null,
      maxCanSee: 6, //maxCanSee代表可视范围内的最大完整数据条数
      tableLineHeight: 45   //tableLineHeight代表列表中一行的高度
    };
  },
  props: ["activeFactoryId"],
  watch: {
    activeFactoryId(val, oldVal) {
      clearInterval(this.componentTimer);
      this.bsGetOrderProcessList();
      this.componentTimerFun();
    }
  },
  beforeDestroy() {
    clearInterval(this.componentTimer);
    clearInterval(this.tableTimer);
  },
  mounted() {
  },
  methods: {
    bsGetOrderProcessList() {
      clearInterval(this.tableTimer);
      this.tableTop = 0;
      if (this.activeFactoryId != "") {
        this.showFlag = false;
        this.$ajax({
          method: "get",
          url: ``  //接口地址,不公开
        })
          .then(res => {
            this.tableList = res.data.data;
            this.showFlag = true;
            this.actionFun();
          })
          .catch(function(err) {
            console.log("bsGetOrderProcessList error!");
          });
      }
    },
    actionFun() {
      if (this.tableList.length > 6) {
        this.tableTimerFun();
      } else {
        this.fillTableList();
      }
      this.showFlag = true;
    },
    fillTableList() {
      var addLength = this.maxCanSee - this.tableList.length;
      for (var i = 0; i < addLength; i++) {
        this.tableList.push({
          orderNo: "-",
          projectName: "-",
          needVol: "-",
          completeDate: "-",
          process: "-"
        });
      }
    },
    tableTimerFun() {
      var count = 0;  //每滚动一次,count加1
      if (this.tableList.length > this.maxCanSee) {  //tableList是列表的数据对象,maxCanSee代表可视范围内的最大完整数据条数
        this.tableTimer = setInterval(() => {
          if (count < this.tableList.length - this.maxCanSee) { //如果还没滚动到最后一条数据,则列表向上移动以上的高度
            this.tableTop -= this.tableLineHeight;   //tableLineHeight代表列表中一行的高度
            count++;   //每滚动一次,count加1
          } else {   //如果滚动到最后一条,则恢复初始状态
            count = 0;
            this.tableTop = 0;
          }
        }, 3000);
      }
    },
    componentTimerFun() {
      this.componentTimer = setInterval(() => {
        this.bsGetOrderProcessList();
      }, 3600000);
    }
  }
};
</script>
<style scoped>
.orderProcess {
  width: 600px;
  height: 313px;
}
.loading_div {
  color: #eee;
  padding-top: 100px;
}
.table_head {
  width: 100%;
  height: 30px;
  line-height: 30px;
  background: rgba(90, 127, 200, 0.5);
  display: flex;
  color: #eee;
  text-align: center;
  font-size: 15px;
}
.tr1 {
  width: 25%;
}
.tr2 {
  width: 25%;
}
.tr3 {
  width: 18%;
}
.tr4 {
  width: 18%;
}
.tr5 {
  flex: 1;
}
.tr {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  box-sizing: border-box;
  padding: 0 5px;
  text-align: center;
  font-size: 14px;
}
.table_body {
  width: 100%;
  height: 270px;
  overflow: hidden;
  position: relative;
}
.table_list {
  width: 100%;
  position: absolute;
  transition: all 0.5s;
}
.tr_div {
  width: 100%;
  display: flex;
  color: #eee;
  text-align: center;
  line-height: 45px;
  font-size: 13px;
}
.exception_style_tr {
  animation: exception_style_tr 0.8s linear;
  -moz-animation: exception_style_tr 0.8s linear;
  -webkit-animation: exception_style_tr 0.8s linear;
  -o-animation: exception_style_tr 0.8s linear;
  animation-iteration-count: infinite;
  -webkit-animation-iteration-count: infinite;
}
@keyframes exception_style_tr {
  0% {
    background: rgba(3, 145, 167, 0.1);
  }
  50% {
    background: rgba(250, 4, 4, 0.15);
  }
  100% {
    background: rgba(3, 145, 167, 0.1);
  }
}
@-moz-keyframes exception_style_tr {
  0% {
    background: rgba(3, 145, 167, 0.1);
  }
  50% {
    background: rgba(250, 4, 4, 0.15);
  }
  100% {
    background: rgba(3, 145, 167, 0.1);
  }
}
@-webkit-keyframes exception_style_tr {
  0% {
    background: rgba(3, 145, 167, 0.1);
  }
  50% {
    background: rgba(250, 4, 4, 0.15);
  }
  100% {
    background: rgba(3, 145, 167, 0.1);
  }
}
@-o-keyframes exception_style_tr {
  0% {
    background: rgba(3, 145, 167, 0.1);
  }
  50% {
    background: rgba(250, 4, 4, 0.15);
  }
  100% {
    background: rgba(3, 145, 167, 0.1);
  }
}
.exception_style {
  font-weight: bold;
  animation: exception_style 0.8s linear;
  -moz-animation: exception_style 0.8s linear;
  -webkit-animation: exception_style 0.8s linear;
  -o-animation: exception_style 0.8s linear;
  animation-iteration-count: infinite;
  -webkit-animation-iteration-count: infinite;
}
@keyframes exception_style {
  0% {
    color: #eee;
  }
  50% {
    color: #fa0404;
  }
  100% {
    color: #eee;
  }
}
@-moz-keyframes exception_style {
  0% {
    color: #eee;
  }
  50% {
    color: #fa0404;
  }
  100% {
    color: #eee;
  }
}
@-webkit-keyframes exception_style {
  0% {
    color: #eee;
  }
  50% {
    color: #fa0404;
  }
  100% {
    color: #eee;
  }
}
@-o-keyframes exception_style {
  0% {
    color: #eee;
  }
  50% {
    color: #fa0404;
  }
  100% {
    color: #eee;
  }
}
.notice_style {
  font-weight: bold;
  color: #d1ce02;
}
</style>

        最后是效果视频:

发表回复