乐趣区

关于vue.js:基于vue20的相册组件

因为需要做了一个相册的业务组件,我感觉还挺难看的,分享给大家看一下,能够本人提取,6 点几了,上班先!

<template>
  <div class="img-wrapper">
    <el-button
      icon="h-icon-angle_left"
      plain
      class="left to"
      :disabled="disabledPrev"
      @click="toRight"
    ></el-button>
    <div ref="imagesWrapper" class="images">
      <div v-if="noData" class="empty-text">
        <slot name="empty"> 暂无数据 </slot>
      </div>
      <div v-show="!noData" class="items" :style="itemsStyle">
        <div
          v-for="(item, index) in data"
          :key="index"
          class="item-img"
          :style="imgSize"
          :class="{'is-active': index === currentIndex}"@click="selected(index)"
        >
          <img :title="item[props.title]" :src="item[props.url]" />
          <p v-if="item[props.title]" v-ellipsis class="item-date">
            {{item[props.title] }}
          </p>
        </div>
      </div>
    </div>
    <el-button
      icon="h-icon-angle_right"
      :disabled="disabledNext"
      plain
      class="right to"
      @click="Left"
    ></el-button>
  </div>
</template>

<script>
export default {
  name: 'ImagesGroup',
  props: {
    imgSize: {
      type: Object,
      default: () => {
        return {
          width: '120px',
          height: '120px'
        };
      }
    },
    value: {
      type: Number,
      default: null
    },
    data: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      props: {
        title: 'title',
        url: 'url',
        key: 'key',
        type: 'type'
      },
      currentIndex: '',
      translateX: 0,
      pageSize: 0 // 一页展现的图片数
    };
  },
  computed: {
    // 偏移度数
    itemsStyle() {
      return {transform: `translateX(${-this.translateX}px)`
      };
    },
    // 每一项宽度
    itemWidth() {return parseInt(this.imgSize.width.replace('px', '')) + 8;
    },
    disabledPrev() {
      // 禁用前一页按钮
      return this.translateX <= 0;
    },
    disabledNext() {
      // 禁用后一页按钮
      return (this.translateX >= (this.data.length - this.pageSize) * this.itemWidth
      );
    },
    noData() {return this.data.length === 0;},
    dataLength() {return this.data.length;}
  },
  watch: {
    value: {
      immediate: true,
      handler(val) {this.currentIndex = val;}
    }
  },
  mounted() {this.pageSize = this.wrapperWidth() / this.itemWidth;
  },
  methods: {toRight() {if (this.translateX < this.pageSize * this.itemWidth) {this.translateX = 0;} else {this.translateX = this.translateX - this.pageSize * this.itemWidth;}
    },
    Left() {
      this.translateX = this.translateX + this.pageSize * this.itemWidth;
      const maxTrans = this.itemWidth * (this.dataLength - this.pageSize);
      if (this.translateX > maxTrans) {this.translateX = maxTrans;}
    },
    selected(index) {
      const center = this.pageSize >> 1;
      // 最初一页的两头地位
      const lastCenter = this.dataLength - center;
      if (index > center && index < lastCenter) {
        // 与相册两头相差的图片数量
        const step = index - center;
        // 将点击图片挪动到两头
        this.translateX = this.itemWidth * step;
      } else {const maxTrans = this.itemWidth * (this.dataLength - this.pageSize);
        this.translateX = index <= center ? 0 : maxTrans;
      }
      if (this.currentIndex !== index) {
        this.currentIndex = index;
        this.$emit('input', index);
      }
    },
    wrapperWidth() {if (this.$refs.imagesWrapper) {return this.$refs.imagesWrapper.offsetWidth;}
      return 0;
    }
  }
};
</script>

<style lang="less" scoped>
.img-wrapper {
  display: flex;
  position: relative;
  margin: 20px;
  height: 120px;
  .to {
    width: 32px;
    height: 100%;
    padding: 0;
  }
  .images::before {
    position: absolute;
    z-index: 5;
    top: 0;
    height: 100%;
    width: 84px;
    content: '';
    pointer-events: none;
    background: -webkit-gradient(
      linear,
      left top,
      right top,
      from(#fff),
      color-stop(50%, rgba(0, 0, 0, 0))
    );
    background: -o-linear-gradient(left, #fff, rgba(0, 0, 0, 0) 50%);
    background: linear-gradient(90deg, #fff, rgba(0, 0, 0, 0) 50%);
  }
  .images::after {
    position: absolute;
    z-index: 5;
    top: 0;
    height: 100%;
    right: 0;
    width: 84px;
    content: '';
    pointer-events: none;
    background: -webkit-gradient(
      linear,
      right top,
      left top,
      from(#fff),
      color-stop(50%, rgba(0, 0, 0, 0))
    );
    background: -o-linear-gradient(right, #fff, rgba(0, 0, 0, 0) 50%);
    background: linear-gradient(270deg, #fff, rgba(0, 0, 0, 0) 50%);
  }
  .images {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    margin: 0 2px;
    .empty-text {color: rgb(158, 158, 158);
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .items {
      position: absolute;
      top: 0;
      left: 0;
      display: flex;
      // width: 6000px;
      height: 100%;
      align-items: center;
      transition: transform 0.25s ease;
      .item-img {
        display: inline-block;
        box-sizing: border-box;
        position: relative;
        margin-right: 8px;
        border: 2px solid rgba(0, 0, 0, 0);
        cursor: pointer;
        .item-date {
          bottom: 0px;
          position: absolute;
          width: 100%;
          height: 24px;
          background: rgba(0, 0, 0, 0.2);
          text-align: center;
          line-height: 24px;
          color: white;
        }
        img {
          width: 100%;
          height: 100%;
        }
      }
      .item-img:hover::after {
        // border-color: #409EFF;
        opacity: 0;
      }
      .item-img::after {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        content: '';
        opacity: 0.2;
        pointer-events: none;
        -webkit-transition: opacity 0.3s ease;
        -o-transition: opacity 0.3s ease;
        transition: opacity 0.3s ease;
        background-color: #fff;
      }
      .is-active {border-color: #409eff;}
      .is-active:after {opacity: 0;}
    }
  }
}
</style>

退出移动版