<template>
  <div class="tabs"
       :class="{page,fixed}"
       ref="tabs">
    <template v-if="page">
      <i class="btn btn--left"
         @click="tapPre">&lt;</i>
      <i class="btn btn--right"
         @click="tapNext">&gt;</i>
    </template>
    <div class="tabs__wrapper"
         ref="tabsWrapper">
      <!-- <ul class="tabs__list"
          ref="tabsList"
          :style="listStyle"> -->
      <ul class="tabs__list"
          ref="tabsList">
        <li class="tabs__item"
            :class="{selected:item.selected}"
            v-for="(item,$index) in tabs"
            :key="$index"
            @click="tapItem(item,$index)">
          <div>{{item.text}}</div>
        </li>
      </ul>
      <!-- 底部滚动 -->
      <div class="tabs__line"
           :class="lineCls"
           ref="tabsLine"></div>
    </div>
  </div>

</template>
<script>
import elementResizeDetectorMaker from 'element-resize-detector';
import throttle from 'lodash/throttle';
import { raf } from '../utils/raf';
const SCROLL_DIST = 100;
export default {
  name: 'Tabs',
  model: {
    prop: 'value',
    event: 'my-change'
  },
  props: {
    list: {
      type: Array,
      default() {
        return [];
      }
    },
    value: {
      type: [String, Number],
      default: ''
    },
    fixed: {
      type: Boolean,
      default: false
    },
    duration: {
      type: Number,
      default: 0.3
    }
  },
  data() {
    return {
      tabs: [],
      index: 0,
      isFirst: true,
      page: false,
      listStyle: { transform: '' },
      lineOffset: 0
    };
  },
  computed: {
    lineCls() {
      return [!this.isFirst ? 'ani' : ''];
    }
  },

  watch: {
    list: {
      handler(val, oldVal) {
        const { value } = this;
        this.tabs = JSON.parse(JSON.stringify(val.map(item => { item.selected = false; return item; })));
        const index = this.getIndexByValue(this.tabs, value);
        this.tabs[index].selected = true;
        // 横线移动
        this.$nextTick(() => {
          // 修改为滚动条移动，注释下面三行
          // const $tabsWrapper = this.$refs.tabsWrapper;
          // const $tabsList = this.$refs.tabsList;
          // this.page = $tabsList.scrollWidth > $tabsWrapper.offsetWidth;
          this.$nextTick(() => {
            this.slideTo(index);
          });
        });
      },
      immediate: true
    },
    /**
     * @desc 监听value改变
     */
    value(val, oldVal) {
      if (this.tabs.length > 0) {
        this.slideTo(this.getIndexByValue(this.tabs, val), true);
      }
    }
  },
  mounted() {
    this.observer = elementResizeDetectorMaker();
    this.observer.listenTo(this.$refs.tabs, this.handleResize);
  },
  methods: {
    slideTo(index, emit = false) {
      this.index = index;
      // 没有数据不操作
      if (!this.tabs.length) return;
      // 300为动画时长
      this.isFirst && setTimeout(() => {
        this.isFirst = false;
      }, 300);
      this.tabs.forEach((item, i) => { item.selected = i === index; });
      const currItem = this.tabs.find((item, i) => i === index);
      const $tabsList = this.$refs.tabsList;
      const $tabsItems = $tabsList.querySelectorAll('.tabs__item');
      const $tabsLine = this.$refs.tabsLine;
      const $tabsWrapper = this.$refs.tabsWrapper;

      const $item = $tabsItems[index];
      let offsetLeft = parseFloat(this.getCss($item).marginLeft);
      const width = parseFloat($item.offsetWidth);
      const lineWidth = parseFloat($tabsLine.offsetWidth);
      for (let i = 0; i < index; i++) {
        offsetLeft += parseFloat($tabsItems[i].offsetWidth) + parseFloat(this.getCss($tabsItems[i]).marginLeft);
      }

      // 计算每个点击的item都会自动居中
      // let diff = offsetLeft - ($tabsWrapper.offsetWidth - width) / 2;
      let diff = offsetLeft - ($tabsWrapper.offsetWidth - width) / 2;

      this.setScrollOffset(diff);

      // 底部线段的滚动
      diff = Math.min($tabsList.offsetWidth - $tabsWrapper.offsetWidth, diff);
      diff = diff < 0 ? 0 : diff;

      // const lineOffset = (offsetLeft - diff) + (width - lineWidth) / 2;
      // 修改为滚动条移动
      const lineOffset = (offsetLeft) + (width - lineWidth) / 2;

      this.setLineOffset(lineOffset);

      emit && this.$emit('on-change', currItem);
      this.$emit('my-change', currItem.value);
    },
    tapItem(item, index) {
      this.$emit('my-change', item.value);
    },
    getCss(ele) {
      /* 利用判断是否支持currentStyle（是否为ie） */
      return ele.currentStyle ? ele.currentStyle : document.defaultView.getComputedStyle(ele, null);
    },
    tapPre() {
      this.move('pre');
    },
    tapNext() {
      this.move('next');
    },
    move(operate = 'next') {
      const curr = this.getCurrentScrollOffset();
      const num = this.setScrollOffset(curr + (operate === 'next' ? SCROLL_DIST : -SCROLL_DIST));
      this.setLineOffset(this.lineOffset - (num - curr));
    },
    setScrollOffset(num, fn = false) {
      // const $tabsList = this.$refs.tabsList;
      const $tabsWrapper = this.$refs.tabsWrapper;
      // num = Math.min($tabsList.offsetWidth - $tabsWrapper.offsetWidth, num);

      // num = num < 0 ? 0 : num;
      // this.listStyle.transform = num === 0 ? '' : `translateX(${-num}px)`;
      // $tabsWrapper.scrollLeft = num;

      // 修改为滚动条移动
      // $tabsWrapper.scrollLeft = num === 0 ? 0 : num;
      const { scrollLeft } = $tabsWrapper;
      this.scrollTo($tabsWrapper, scrollLeft, num, this.isFirst, fn);
      return num;
    },

    /**
     * @desc 元素 scrollLeft 的动画
     * @param {Object} el 容器元素
     * @param {Number} fron 开始的距离
     * @param {Number} to 结束的距离
     * @param {Boolean} immediate 是否立即执行【不用动画】
     */
    scrollTo(el, from, to, immediate, fn = false) {
      if (immediate) {
        el.scrollLeft += to - from;
        if (fn) fn();
        return;
      }
      let count = 0;
      const frames = Math.round((this.duration * 1000) / 16);
      const animate = () => {
        el.scrollLeft += (to - from) / frames;
        if (++count < frames) {
          raf(animate);
        } else {
          if (fn) fn();
        }
      };
      animate();
    },
    setLineOffset(lineOffset) {
      this.lineOffset = lineOffset;
      this.$refs.tabsLine.style.cssText = `transform: translate3d(${lineOffset}px, 0px, 0px)`;
    },
    getCurrentScrollOffset() {
      const { listStyle } = this;
      return listStyle.transform
        ? Number(listStyle.transform.match(/translateX\(-(\d+(\.\d+)*)px\)/)[1])
        : 0;
    },
    handleResize: throttle(function() {
      this.slideTo(this.index);
    }, 500),
    /**
     * @desc 根据value获取index
     */
    getIndexByValue(list, value) {
      let index = 0;
      if (value === '') {
        index = 0;
      } else {
        for (let i = 0, len = list.length; i < len; i++) {
          if (list[i].value === value) {
            index = i;
            break;
          }
        }
      }
      return index;
    }
  },
  /**
   * @desc 卸载
   */
  beforeDestroy() {
    this.observer.removeListener(this.$refs.tabs, this.handleResize);
  }
};
</script>
