user-list.vue 4.64 KB
<template>
  <CubeScroll
    class="main-container"
    ref="scroll"
    :options="scrollOpts"
    :scroll-events="['scroll-end']"
    @scroll-end="fetchList">
    <div class="user-list">
      <div v-for="(item, index) in list" :key="index" class="user-item">
        <WidgetAvatar class="head-ico" :src="item.headIcon" :width="100" :height="100" @click.native="toUserPage(item)"></WidgetAvatar>
        <div class="user-info" @click="toUserPage(item)">
          <p class="name">{{item.nickName}}</p>
          <p v-if="item.articleCount || item.fansCount" class="extra">
            <span v-if="item.publishNum">笔记·{{item.publishNum}}</span>
            <span v-if="item.fansCount">粉丝·{{item.fansCount}}</span>
          </p>
        </div>
        <div class="option-btn" :class="{'follow': item.isAttention}">
          <WidgetFollow class="click-wrap" :author-uid="item.userId" :author-type="item.userType" :follow="item.isAttention" @on-follow="follow => onFollow(follow, index)"></WidgetFollow>
          {{item.isAttention ? '已关注' : followName}}
        </div>
      </div>
    </div>
    <div class="loading">
      <p v-if="noMore" class="load-text">没有更多了</p>
      <Loading v-else class="load-icon" :size="20"></Loading>
    </div>
  </CubeScroll>
</template>

<script>
import {get} from 'lodash';
import {Scroll, Loading} from 'cube-ui';

export default {
  props: {
    followName: {
      type: String,
      default: '关注'
    },
    onFetch: {
      type: Function,
      required: true
    }
  },
  data() {
    return {
      scrollOpts: {
        bounce: false,
      },
      list: [],
      noMore: false
    };
  },
  methods: {
    init() {
      this._page = 1;
      this._totalPage = 1;
      this._lastedTime = '';
      this.list = [];
      this.noMore = false;
      this.fetchList();
    },
    fetchList() {
      let page = this._page || 1;

      if (this._fetching || page > this._totalPage) {
        return;
      }

      this._fetching = true;

      setTimeout(() => {
        this._fetching = false;
      }, 5000);

      this.onFetch({
        page: this._page || 1,
        lastedTime: this._lastedTime
      }).then(res => {
        this._fetching = false;

        if (res.code !== 200) {
          return;
        }

        let list = get(res, 'data.list', []);

        list.forEach(val => {
          val.isAttention = val.hasAttention === 'Y';
        });

        this.list = this.list.concat(list);
        this._totalPage = res.data.totalPage;
        this._lastedTime = res.data.lastedTime;
        this._page = ++page;

        if (page > this._totalPage) {
          this.noMore = true;
        }

        setTimeout(() => {
          this.$refs.scroll.refresh();
        }, 100);
      })
    },
    onFollow(follow, index) {
      this.list[index].isAttention = follow;
    },
    toUserPage(item) {
      this.$router.push({
        name: 'author',
        params: {
          id: item.userId,
          type: item.userType || 1
        }
      });
    },
  },
  components: {
    CubeScroll: Scroll,
    Loading
  }
};
</script>

<style>
.user-list {
  padding-left: 30px;
}

.user-item {
  height: 154px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #e0e0e0;

  .head-ico {
    width: 100px;
    height: 100px;
    margin-right: 20px;
  }

  .user-info {
    flex-grow: 1;
    overflow: hidden;
  }

  .name {
    max-width: 370px;
    font-size: 28px;
    line-height: 1.4;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .extra {
    font-size: 0;
    line-height: 1.4;
    margin-top: 16px;
    color: #b0b0b0;

    > span {
      font-size: 24px;
      display: inline-block;
      padding: 0 12px;
      position: relative;

      &:before {
        width: 2px;
        content: "";
        position: absolute;
        top: 4px;
        bottom: 4px;
        left: -1px;
        background-color: #b0b0b0;
      }

      &:first-child {
        margin-left: -12px;
      }
    }
  }

  .option-btn {
    min-width: 110px;
    line-height: 50px;
    letter-spacing: 3px;
    text-align: center;
    border: 1px solid #444;
    border-radius: 26px;
    padding: 0 18px;
    margin-right: 28px;
    box-sizing: border-box;
    position: relative;
    z-index: 1;

    &.follow {
      color: #b0b0b0;
      border-color: #b0b0b0;
    }

    .click-wrap {
      width: 140%;
      height: 180%;
      position: absolute;
      left: -20%;
      top: -38%;
      z-index: 10;
      background: none;
      font-size: 0;
      opacity: 0;
    }
  }
}

.loading {
  padding: 20px 0;

  .load-icon > span {
    margin: auto;
  }

  .load-text {
    text-align: center;
  }
}
</style>