用el-scrollbar写一个可横向滚动的vue组件

组件展示效果图

用el-scrollbar写一个可横向滚动的vue组件_第1张图片
该页面是一个step组件内嵌一个右下角的按钮组件

关键代码

首先,el-scrollbar组件包住一个被内容撑开的横向列

<el-scrollbar ref="scrollbar" class="scrollbar" v-if="list.length !== 0">
  <div class="step">
    <div class="event-item" v-for="item in list" :key="item.id">
      <div class="item-card" @click="detail(item.id)">
        ......
      div>
    div>
  div>
el-scrollbar>

获取el-scrollbar的scrollWidth(元素实际宽度,包括超出隐藏的部分),减去el-scrollbar的scrollLeft(元素距离左边窗口的距离),再减去el-scrollbar的clientWidth(元素包括padding、内容区的宽度,不含边框),得到可以向右移动的最边界位置。点击一次按钮,给scrollLeft或scrollRight赋一次值以更改位置。

// 滚动
handelScroll(action) {
  var scrollbar = this.$refs.scrollbar.wrap;
  // 点击按钮移动一次的步长
  var width = 500;
  // 向右可以移动的距离
  let scrollRight =
    scrollbar.scrollWidth -
    scrollbar.scrollLeft -
    scrollbar.clientWidth;
  if (action == "left") {
    if (scrollbar.scrollLeft > width) { // 判断滚动到最右时
      scrollbar.scrollLeft -= width;
    } else {
      scrollbar.scrollLeft -= scrollbar.scrollLeft;
    }
  } else {
    if (scrollRight > width) { // 判断滚动到最右时
      scrollbar.scrollLeft += width;
    } else {
      scrollbar.scrollLeft += scrollRight;
    }
  }
}

is-horizontal隐藏el-scrollbar自身的滚动条

::v-deep .scrollbar {
  .is-horizontal {
    height: 0;
    left: 0;
  }
}

横向排列宽度由内容撑开需要父元素加入white-space:nowrap,子元素加入display: inline-block;

.step {
	 height: 540px;
	 white-space: nowrap;
	 padding-top: 50px;
	 .event-item {
	   width: 320px;
	   height: 100%;
	   display: inline-block;
	 }
}

step组件代码

<template>
  <div class="base-step">
    <div class="loading" v-if="subLoading">
      <div class="loading-tip">
        <i class="el-icon-loading">i>
        <div class="tip">
          加载中
        div>
      div>
    div>
    <el-scrollbar ref="scrollbar" class="scrollbar" v-if="list.length !== 0">
      <div class="step">
        <div class="event-item" v-for="item in list" :key="item.id">
          <div class="item-card" @click="detail(item.id)">
            <img :src="item.image ? item.image.split(',')[0] : require('@/assets/images/home/lack.png')" class="item-img" />
            <div class="item-content">
              <div class="info-box">
                <div class="info-title">{{ item.name }}div>
                <div class="star-box">
                  <img v-for="star in item.star" :key="star" class="star" src="@/assets/images/heaven/icon_grade.png" />
                div>
                <div class="info-item-box">
                  <div class="info-item">
                    <img class="info-item-icon" src="@/assets/images/heaven/2_icon_date.png" />
                    <div class="info-item-value">
                      {{ item.startTime && item.endTime ? item.startTime + '-' + item.endTime : "暂无信息" }}
                    div>
                  div>
                div>
                <div class="info-item-box">
                  <div class="info-item">
                    <img class="info-item-icon" src="@/assets/images/heaven/2_icon_iphone.png" />
                    <div class="info-item-value">
                      {{ item.phone ? item.phone : "暂无信息" }}
                    div>
                  div>
                div>
                <div class="info-item-box">
                  <div class="info-item">
                    <img class="info-item-icon" src="@/assets/images/heaven/2_icon_map.png" />
                    <div class="info-item-value address">
                      {{ item.adress ? item.adress : "暂无信息" }}
                    div>
                  div>
                div>
              div>
            div>
          div>
        div>
      div>
    el-scrollbar>
    <div class="pagination-scroll" v-if="list.length !== 0">
      <base-pagination direction="horizontal" type="scroll" @pageChange="handelScroll">base-pagination>
    div>
    
    <div class="empty" v-if="list.length === 0 && !subLoading">
      <div class="block">
        <template v-if="onLine">
          <img class="image" src="@/assets/images/home/no_data.png" alt="">
          <div class="tip">
            {{ emptyTip }}
          div>
        template>
        <template v-if="!onLine">
          <img class="image" src="@/assets/images/home/no_net.png" alt="">
          <div class="tip">
            网络未连接,请检查网络配置
          div>
        template>
        <div class="reload" @click="reLoadClick">
          重新加载
        div>
      div>
    div>
  div>
template>
<script>
export default {
  name: "baseStep",
  data() {
    return {
      onLine: navigator.onLine,
      subLoading: true
    };
  },
  watch: {
    loading(val) {
      this.subLoading = val;
    }
  },
  props: {
    list: {
      type: Array,
      default: () => {
        return []
      }
    },
    detailRoute: {
      type: String,
      default: () => {
        return ''
      }
    },
    emptyTip: {
      type: String,
      default: '暂无数据'
    },
    loading: {
      type: Boolean,
      default: true
    },
    // 重载函数
    reLoad: {
      type: Function,
      default: () => {}
    }
  },
  mounted() {
    window.addEventListener('online',  this.updateOnlineStatus);// 网络由异常到正常时触发
	window.addEventListener('offline', this.updateOnlineStatus);// 网络由正常常到异常时触发
  },
  methods: {
    detail(id) {
      if (this.detailRoute) {
        this.$router.push(this.detailRoute + '?id=' + id)
      }
    },
    // 滚动
    handelScroll(action) {
      var scrollbar = this.$refs.scrollbar.wrap;
      var width = 500;
      let scrollRight =
        scrollbar.scrollWidth -
        scrollbar.scrollLeft -
        scrollbar.clientWidth;
      if (action == "left") {
        if (scrollbar.scrollLeft > width) { // 判断滚动到最右时
          scrollbar.scrollLeft -= width;
        } else {
          scrollbar.scrollLeft -= scrollbar.scrollLeft;
        }
      } else {
        if (scrollRight > width) { // 判断滚动到最右时
          scrollbar.scrollLeft += width;
        } else {
          scrollbar.scrollLeft += scrollRight;
        }
      }
    },
    reLoadClick() {
      this.reLoad();
    },
    updateOnlineStatus(e) {
      const { type } = e;
      this.onLine = type === 'online';
    },
    beforeDestroy(){
      window.removeEventListener('online',  this.updateOnlineStatus);
      window.removeEventListener('offline', this.updateOnlineStatus);
    }
  },
};
</script>

按钮组件代码

<template>
  <div class="base-pagination">
    
    <div class="vertical" v-if="direction == 'vertical'">
      <div @click="prevPage">
        <img class="image" src="../../assets/images/home/btn_up.png" alt="" />
      div>
      <div class="pager" v-if="type == 'pagination'">
        {{ currPage }} / {{ totalPages }}
      div>
      <div @click="nextPage">
        <img class="image" src="../../assets/images/home/btn_down.png" alt="" />
      div>
    div>
    
    <div class="horizontal" v-else>
      <div @click="prevPage">
        <img class="image" src="../../assets/images/home/btn_left.png" alt="" />
      div>
      <div class="pager" v-if="type == 'pagination'">
        {{ currPage }} / {{ totalPages }}
      div>
      <div @click="nextPage">
        <img
          class="image"
          src="../../assets/images/home/btn_right.png"
          alt=""
        />
      div>
    div>
  div>
template>

这个按钮组件预留了翻页、纵向的功能

<script>
export default {
  name: "basePagination",
  data() {
    return {
      currPage: 0,
      totalPages: 0, // 总页数
    };
  },
  props: {
    // 方向 垂直vertical | 水平horizontal
    direction: {
      type: String,
      default: "vertical",
    },
    pager: {
      type: Object,
      default: () => {
        return {
          currPage: 0,
          totalPages: 0,
        };
      },
    },
    // 类型 pagination 分页 | scroll 滚动
    type: {
      type: String,
      default: "pagination",
    },
  },
  mounted() {
    if (this.type == "pagination") {
      this.getPager();
    }
  },
  methods: {
    getPager() {
      this.$nextTick(() => {
        this.currPage = parseInt(this.pager.currPage);
        this.totalPages = parseInt(this.pager.totalPages);
      });
    },
    // 上一页
    prevPage() {
      if (this.type == "pagination") {
        if (this.currPage > 1) {
          this.currPage--;
          this.$emit("pageChange", this.currPage);
        }
      } else if (this.type == "scroll") {
        if (this.direction === "vertical") {
          this.$emit("pageChange", "up");
        } else if (this.direction === "horizontal") {
          this.$emit("pageChange", "left");
        }
      }
    },

    // 下一页
    nextPage() {
      if (this.type == "pagination") {
        if (this.currPage < this.totalPages) {
          this.currPage++;
          this.$emit("pageChange", this.currPage);
        }
      } else if (this.type == "scroll") {
        if (this.direction === "vertical") {
          this.$emit("pageChange", "down");
        } else if (this.direction === "horizontal") {
          this.$emit("pageChange", "right");
        }
      }
    },
  },
};
</script>

你可能感兴趣的:(vue2.0,vue.js,javascript,前端,elementui,前端框架)