<template>
  <div>
    <template v-if="isNeed">
      <div
        class="_v-container"
        :id="containerId"
        @touchstart="touchStart($event)"
        @touchmove="touchMove($event)"
        @touchend="touchEnd($event)"
        @mousedown="mouseDown($event)"
        @mousemove="mouseMove($event)"
        @mouseup="mouseUp($event)"
      >
        <div class="_scroller-bar" ref="scroller_bar" :id="contentId + '_bar'" style="opacity: 0"></div>
        <div
          class="pageIndexBox"
          v-if="pageIndex.length > 0"
          @touchstart.stop="pageIndex_touchstart($event)"
          @touchmove.stop="pageIndex_touchmove($event)"
          @touchend.stop="pageIndex_touchend($event)"
        >
          <div class="pageIndexBtn" v-for="(item, index) in pageIndex" @click="go_index(item)">
            <div class="page-index-tip">{{ item.label }}</div>
            {{ item.label }}
          </div>
        </div>
        <div class="_v-content" :id="contentId" ref="scroller_content">
          <div v-if="onRefresh" class="pull-to-refresh-layer" :class="{ active: state == 1, 'active refreshing': state == 2 }">
            <span class="spinner-holder">
              <arrow class="arrow" :fillColor="refreshLayerColor" v-if="state != 2"></arrow>

              <span class="text" v-if="state != 2" :style="{ color: refreshLayerColor }" v-text="refreshText"></span>

              <span v-if="state == 2">
                <slot name="refresh-spinner"><spinner :style="{ fill: refreshLayerColor, stroke: refreshLayerColor }"></spinner></slot>
              </span>
            </span>
          </div>

          <slot></slot>

          <div v-if="showInfiniteLayer && list.length > 0" class="loading-layer">
            <span class="spinner-holder" :class="{ active: showLoading }">
              <slot name="infinite-spinner"><spinner :style="{ fill: loadingLayerColor, stroke: loadingLayerColor }"></spinner></slot>
            </span>

            <div class="no-data-text" :class="{ active: !showLoading && loadingState == 2 }" :style="{ color: loadingLayerColor }" v-text="noDataText"></div>
          </div>
        </div>
      </div>
    </template>
    <div v-else style="height: 100%;width: 100%;position: relative;"><slot></slot></div>
  </div>
</template>
<script>
import Scroller from '../module/core';
import getContentRender from '../module/render';
import Spinner from './Spinner.vue';
import Arrow from './Arrow.vue';

const re = /^[\d]+(\%)?$/;

const widthAndHeightCoerce = v => {
  if (v[v.length - 1] != '%') return v + 'px';
  return v;
};

const widthAndHeightValidator = v => {
  return re.test(v);
};

export default {
  components: {
    Spinner,
    Arrow
  },

  props: {
    onRefresh: Function,
    onInfinite: Function,
    onScrolling: {
      type: Function,
      default: function(e) {}
    },
    refreshText: {
      type: String,
      default: '下拉刷新'
    },

    noDataText: {
      type: String,
      default: '没有更多数据'
    },

    width: {
      type: String,
      default: '100%',
      validator: widthAndHeightValidator
    },

    height: {
      type: String,
      default: '100%',
      validator: widthAndHeightValidator
    },

    list: {
      type: Array,
      default: () => {
        return [];
      }
    },
    snapping: {
      type: Boolean,
      default: false
    },

    snapWidth: {
      type: Number,
      default: 100
    },

    snapHeight: {
      type: Number,
      default: 100
    },

    animating: {
      type: Boolean,
      default: true
    },

    animationDuration: {
      type: Number,
      default: 250
    },

    bouncing: {
      type: Boolean,
      default: true
    },

    refreshLayerColor: {
      type: String,
      default: '#AAA'
    },

    loadingLayerColor: {
      type: String,
      default: '#AAA'
    },

    cssClass: String, // content css class

    minContentHeight: {
      type: Number,
      default: 0 // px
    },

    isNeed: {
      //是否需要显示滚动组件
      type: Boolean,
      default: true
    }
  },

  computed: {
    w: function() {
      return widthAndHeightCoerce(this.width);
    },

    h: function() {
      return widthAndHeightCoerce(this.height);
    },

    showInfiniteLayer() {
      let contentHeight = 0;
      this.content ? (contentHeight = this.content.offsetHeight) : void 666;

      return this.onInfinite ? contentHeight > this.minContentHeight : false;
    }
  },

  data() {
    return {
      bar_top: 0,
      bar_id:
        'bar-' +
        Math.random()
          .toString(36)
          .substring(3, 8),
      containerId:
        'outer-' +
        Math.random()
          .toString(36)
          .substring(3, 8),
      contentId:
        'inner-' +
        Math.random()
          .toString(36)
          .substring(3, 8),
      state: 0, // 0: pull to refresh, 1: release to refresh, 2: refreshing
      loadingState: 0, // 0: stop, 1: loading, 2: stopping loading
      showLoading: false,
      bar_height: 0,
      bar_opacity: 0,
      bar: undefined,
      container: undefined,
      content: undefined,
      scroller: undefined,
      pullToRefreshLayer: undefined,
      mousedown: false,
      infiniteTimer: undefined,
      resizeTimer: undefined,
      container_height: 0,
      container_top: 0,
      focus_resize_timer: undefined,
      focus_style: {},
      focus_top: 0,
      window_height: 0,
      pageIndex: [],
      last_top: 0
    };
  },

  mounted() {
    console.log(this.isNeed);
    if (this.isNeed) {
      this.$nextTick(() => {
        this.init();
        this.createPageIndex();
      });
    }
  },
  deactivated() {
    this.last_top = this.getPosition().top;
  },
  destroyed() {
    clearInterval(this.resizeTimer);
    if (this.infiniteTimer) clearInterval(this.infiniteTimer);
  },

  methods: {
    init() {
      let self = this;
      this.container = document.getElementById(this.containerId);
      this.window_height = localStorage.getItem('window_height');
      this.container.style.width = this.w;
      this.container.style.height = this.h;
      this.bar = document.getElementById(this.bar_id);
      this.container_height = JSON.parse(JSON.stringify(this.h));
      this.container_top = JSON.parse(JSON.stringify(this.container.getBoundingClientRect().top));
      this.content = document.getElementById(this.contentId);
      if (this.cssClass) this.content.classList.add(this.cssClass);
      this.pullToRefreshLayer = this.content.getElementsByTagName('div')[0];
      let render = getContentRender(this.content);
      let scrollerOptions = {
        scrollingX: false
      };
      this.bar_height = (self.container.offsetHeight / self.content.offsetHeight) * self.container.offsetHeight;
      this.scroller = new Scroller(render, {
        scrollingX: false,
        snapping: this.snapping,
        animating: this.animating,
        animationDuration: this.animationDuration,
        bouncing: this.bouncing,
        scrolling: function(x, y) {
          self.bar_height = (self.container.offsetHeight / self.content.offsetHeight) * self.container.offsetHeight;
          if (self.bar_height < 50) {
            self.bar_height = 50;
          }
          self.bar_opacity = 1;
          let cp = (y / self.content.offsetHeight) * self.container.offsetHeight;
          self.bar_top = cp.toString();
          self.onScrolling(Math.round(cp));
          const { scroller_bar } = self.$refs;
          if (scroller_bar) {
            scroller_bar.style.transform = 'translate3d(0px, ' + self.bar_top + 'px, 0px) scale(1)';
            scroller_bar.style.height = self.bar_height + 'px';
            scroller_bar.style.opacity = self.bar_opacity;
          }
          // localStorage.setItem('scroller-top-' + self.contentId, self.getPosition().top)

          if (self.onInfinite) {
            let { left, top, zoom } = self.scroller.getValues();
            // 在 keep alive 中 deactivated 的组件长宽变为 0
            if (self.content.offsetHeight > 0 && top + 60 > self.content.offsetHeight - self.container.clientHeight) {
              if (self.loadingState) return;
              self.loadingState = 1;
              self.showLoading = true;
              self.onInfinite(self.finishInfinite);
            }
          }
        },
        scrollingComplete: function() {
          self.bar_opacity = 0;
          const { scroller_bar } = self.$refs;
          if (scroller_bar) {
            scroller_bar.style.opacity = self.bar_opacity;
          }
        }
      });

      // enable PullToRefresh
      if (this.onRefresh) {
        this.scroller.activatePullToRefresh(
          60,
          () => {
            this.state = 1;
          },
          () => {
            this.state = 0;
          },
          () => {
            this.state = 2;

            this.$on('$finishPullToRefresh', () => {
              setTimeout(() => {
                this.state = 0;
                this.finishPullToRefresh();
              });
            });
            this.onRefresh(this.finishPullToRefresh);
          }
        );
        this.triggerPullToRefresh();
      }

      // setup scroller
      let rect = this.container.getBoundingClientRect();
      this.scroller.setPosition(rect.left + this.container.clientLeft, rect.top + this.container.clientTop);

      // snapping
      if (this.snapping) {
        // console.log(this.snapWidth, this.snapHeight)
        this.scroller.setSnapSize(this.snapWidth, this.snapHeight);
      }

      // onContentResize
      const contentSize = () => {
        return {
          width: this.content.offsetWidth,
          height: this.content.offsetHeight
        };
      };
      const containerSize = () => {
        return {
          width: this.container.clientWidth,
          height: this.container.clientHeight
        };
      };
      let { content_width, content_height } = contentSize();
      let _container_size = containerSize();
      let no_focus_count = 0;
      window.addEventListener(
        'resize',
        () => {
          setTimeout(() => {
            // console.log( '失焦时高度:'+window.innerHeight)
            if (window.plus && Math.abs(this.window_height - window.innerHeight) < 5 && navigator.userAgent.indexOf('Android') > 0) {
              setTimeout(() => {
                // alert(Math.abs(this.window_height - window.innerHeight))
                // Math.abs(this.window_height - window.innerHeight) < 5

                if (Math.abs(this.window_height - window.innerHeight) < 0.17) {
                  document.activeElement.blur();
                }
              }, 100);
            }
          }, 10);

          if (navigator.userAgent.indexOf('Android') > 0) {
            // let pos_y = this.getPosition().top
            document.documentElement.style.opacity = 0;
            // self.scrollTo(0, pos_y)
            window.scroll(0, 0);
            document.documentElement.style.opacity = 1;
          }
          document.documentElement.style.overflow = 'visible';
          document.body.style.overflow = 'visible';
          self.container.style.overflow = 'visible';

          self.container.style.overflow = 'hidden';
          document.documentElement.style.overflow = 'hidden';
          document.body.style.overflow = 'hidden';
          document.activeElement.classList.remove('cur_focus');
          if (document.activeElement && document.activeElement.type == 'textarea') {
            // 此处ios环境下，在textarea中输入内容，自动上滚之后，再点击input就全部内容都上滚了，看起来像是原生的滚动，不知道是怎么回事
            document.activeElement.addEventListener('input', function() {
              let getInputPositon = self.getInputPositon(document.activeElement) + document.activeElement.getBoundingClientRect().top;
              if (getInputPositon > self.container.clientHeight) {
                self.scrollBy(0, 30, true);
              }
            });
          }
          if (this.window_height > containerSize().height) {
            let { width, height } = contentSize();
            this.resize(content_height, height);
          }
        },
        false
      );

      this.resizeTimer = setInterval(() => {
        // let {width, height} = contentSize()
        let contentSize_obj = contentSize();
        if (contentSize_obj.width !== content_width || contentSize_obj.height !== content_height) {
          let old_height = content_height;
          content_width = contentSize_obj.width;
          content_height = contentSize_obj.height;
          this.resize(old_height, contentSize_obj.height);
          if (this.last_top != 0) {
            this.scrollTo(0, this.last_top);
          }
        }
      }, 10);
    },
    pageIndex_touchstart(e) {},
    pageIndex_touchend(e) {
      let index_tip = document.querySelectorAll('.pageIndexBtn');
      for (let i in index_tip) {
        index_tip.item(i).classList.remove('cur');
      }
    },
    pageIndex_touchmove(e) {
      let touch = e.changedTouches[0];
      let point = document.elementFromPoint(touch.clientX, touch.clientY);
      let index_tip = document.querySelectorAll('.pageIndexBtn');
      for (let i in index_tip) {
        index_tip.item(i).classList.remove('cur');
      }
      point.classList.add('cur');
      let list = document.querySelectorAll('[data-pageindex]');
      for (let i = 0; i < list.length; i++) {
        if (this.$refs['scroller_content'].contains(list.item(i)) && list.item(i).getAttribute('data-pageindex') == point.innerText.split('')[0]) {
          this.go_index({ label: point.innerText, element: list.item(i) });
        }
      }
    },
    go_index(item) {
      let activeElementClientTop = item.element.getBoundingClientRect().top;
      this.scrollBy(0, activeElementClientTop - this.container.getBoundingClientRect().top);
    },
    createPageIndex() {
      let list = document.querySelectorAll('[data-pageindex]');
      this.pageIndex = [];
      for (let i = 0; i < list.length; i++) {
        if (this.$refs['scroller_content'].contains(list.item(i))) {
          this.pageIndex.push({ label: list.item(i).getAttribute('data-pageindex'), element: list.item(i) });
        }
      }
    },
    /**
     * 获取输入光标在页面中的坐标
     * @param		{HTMLElement}	输入框元素
     * @return		{Object}		返回left和top,bottom
     */
    getInputPositon: function(elem) {
      var that = this;
      var cloneDiv = '{$clone_div}',
        cloneLeft = '{$cloneLeft}',
        cloneFocus = '{$cloneFocus}',
        cloneRight = '{$cloneRight}';
      var none = '<span style="white-space:pre-wrap;"> </span>';
      var div = elem[cloneDiv] || document.createElement('div'),
        focus = elem[cloneFocus] || document.createElement('span');
      var text = elem[cloneLeft] || document.createElement('span');
      var offset = that._offset(elem),
        index = this._getFocus(elem),
        focusOffset = { left: 0, top: 0 };

      if (!elem[cloneDiv]) {
        (elem[cloneDiv] = div), (elem[cloneFocus] = focus);
        elem[cloneLeft] = text;
        div.appendChild(text);
        div.appendChild(focus);
        document.body.appendChild(div);
        focus.innerHTML = '|';
        focus.style.cssText = 'display:inline-block;width:0px;overflow:hidden;z-index:-100;word-wrap:break-word;word-break:break-all;';
        div.className = this._cloneStyle(elem);
        div.style.cssText = 'visibility:hidden;display:inline-block;position:absolute;z-index:-100;word-wrap:break-word;word-break:break-all;overflow:hidden;';
      }
      div.style.top = '-10000000px';
      var strTmp = elem.value
        .substring(0, index)
        .replace(/</g, '<')
        .replace(/>/g, '>')
        .replace(/\n/g, '<br/>')
        .replace(/\s/g, none);
      text.innerHTML = strTmp;

      focus.style.display = 'inline-block';
      try {
        focusOffset = this._offset(focus);
      } catch (e) {}
      focus.style.display = 'none';
      return text.offsetHeight;
    },

    // 克隆元素样式并返回类
    _cloneStyle: function(elem, cache) {
      if (!cache && elem['${cloneName}']) return elem['${cloneName}'];
      var className,
        name,
        rstyle = /^(number|string)$/;
      var rname = /^(content|outline|outlineWidth)$/; // Opera: content; IE8:outline && outlineWidth
      var cssText = [],
        sStyle = elem.style;

      for (name in sStyle) {
        if (!rname.test(name)) {
          var val = this._getStyle(elem, name);
          if (val !== '' && rstyle.test(typeof val)) {
            // Firefox 4
            name = name.replace(/([A-Z])/g, '-$1').toLowerCase();
            cssText.push(name);
            cssText.push(':');
            cssText.push(val);
            cssText.push(';');
          }
        }
      }
      cssText = cssText.join('');
      elem['${cloneName}'] = className = 'clone' + new Date().getTime();
      this._addHeadStyle('.' + className + '{' + cssText + '}');
      return className;
    },

    // 向页头插入样式
    _addHeadStyle: function(content) {
      var style = this.focus_style[document];
      if (!style) {
        style = this.focus_style[document] = document.createElement('style');
        style.id = 'temp_style';
        document.getElementsByTagName('head')[0].appendChild(style);
      }
      (style.styleSheet && (style.styleSheet.cssText += content)) || style.appendChild(document.createTextNode(content));
    },

    // 获取最终样式
    _getStyle:
      'getComputedStyle' in window
        ? function(elem, name) {
            return getComputedStyle(elem, null)[name];
          }
        : function(elem, name) {
            return elem.currentStyle[name];
          },

    // 获取光标在文本框的位置
    _getFocus: function(elem) {
      var index = 0;
      if (document.selection) {
        // IE Support
        elem.focus();
        var Sel = document.selection.createRange();
        if (elem.nodeName === 'TEXTAREA') {
          // textarea
          var Sel2 = Sel.duplicate();
          Sel2.moveToElementText(elem);
          var index = -1;
          while (Sel2.inRange(Sel)) {
            Sel2.moveStart('character');
            index++;
          }
        } else if (elem.nodeName === 'INPUT') {
          // input
          Sel.moveStart('character', -elem.value.length);
          index = Sel.text.length;
        }
      } else if (elem.selectionStart || elem.selectionStart == '0') {
        // Firefox support
        index = elem.selectionStart;
      }
      return index;
    },

    // 获取元素在页面中位置
    _offset: function(elem) {
      var box = elem.getBoundingClientRect(),
        doc = elem.ownerDocument,
        body = doc.body,
        docElem = doc.documentElement;
      var clientTop = docElem.clientTop || body.clientTop || 0,
        clientLeft = docElem.clientLeft || body.clientLeft || 0;
      var top = box.top + (self.pageYOffset || docElem.scrollTop) - clientTop,
        left = box.left + (self.pageXOffset || docElem.scrollLeft) - clientLeft;
      return {
        left: left,
        top: top,
        right: left + box.width,
        bottom: top + box.height
      };
    },
    resize(old_height, height) {
      let _this = this;
      let container = this.container;
      let content = this.content;
      this.scroller.setDimensions(container.clientWidth, container.clientHeight, content.offsetWidth, content.offsetHeight);
      // 虚拟元素定位
      let vInput = document.querySelectorAll('.v-input');
      if (vInput.length > 0 && container.contains(vInput.item(0))) {
        let pos_y = this.getPosition().top;
        let activeElementClientTop = vInput.item(0).getBoundingClientRect().top;
        if (container.clientHeight - 60 < activeElementClientTop - this.container.getBoundingClientRect().top) {
          setTimeout(() => {
            this.scrollTo(0, pos_y + (activeElementClientTop - this.container.getBoundingClientRect().top - container.clientHeight + 100), true);
          }, 100);
        }
      }
      if (
        old_height &&
        height &&
        height - old_height != 0 &&
        document.activeElement &&
        (document.activeElement.type == 'textarea' ||
          document.activeElement.type == 'text' ||
          document.activeElement.type == 'password' ||
          document.activeElement.type == 'search' ||
          document.activeElement.type == 'number')
      ) {
        setTimeout(() => {
          if (document.activeElement.style.textShadow === '') {
            document.activeElement.style.textShadow = 'rgba(0,0,0,0) 0 0 0'; // 改变某个不可见样式，触发dom重绘，这样可以解决光标错位的问题
          } else {
            document.activeElement.style.textShadow = '';
          }
        }, 450);
      }
      let pos_y = this.getPosition().top;

      document.activeElement.addEventListener(
        'blur',
        function() {
          setTimeout(() => {
            if (
              !container.contains(document.activeElement) &&
              (document.activeElement.type == 'textarea' ||
                document.activeElement.type == 'text' ||
                document.activeElement.type == 'password' ||
                document.activeElement.type == 'search' ||
                document.activeElement.type == 'number')
            ) {
              _this.scrollTo(0, pos_y, true);
              _this.resize(old_height, height);
              document.body.style.height = '100%';
            }
          }, 200);
        },
        false
      );
      if (container.contains(document.activeElement) && window.plus) {
        let last_click_pos = localStorage.getItem('last_click_pos');
        let activeElementClientTop = document.activeElement.getBoundingClientRect().top;
        if (last_click_pos) {
          last_click_pos = JSON.parse(last_click_pos);
          activeElementClientTop += last_click_pos.y;
        }
        if (container.clientHeight - 60 < activeElementClientTop - this.container.getBoundingClientRect().top) {
          setTimeout(() => {
            this.scrollTo(0, pos_y + (activeElementClientTop - this.container.getBoundingClientRect().top - container.clientHeight + 60), true);
          }, 100);
          setTimeout(() => {
            if (document.activeElement.style.textShadow === '') {
              document.activeElement.style.textShadow = 'rgba(0,0,0,0) 0 0 0'; // 改变某个不可见样式，触发dom重绘，这样可以解决光标错位的问题
            } else {
              document.activeElement.style.textShadow = '';
            }
          }, 450);
          var bar_height = plus.navigator.getStatusbarHeight();
          document.body.style.height = window.innerHeight - bar_height + 'px';
        }
      }
    },

    finishPullToRefresh() {
      this.scroller.finishPullToRefresh();
    },

    finishInfinite(hideSpinner) {
      this.loadingState = hideSpinner ? 2 : 0;
      this.showLoading = false;
      if (this.loadingState == 2) {
        this.resetLoadingState();
      }
    },

    triggerPullToRefresh() {
      // 触发更新，每次都回到0的位置，然后就能出现loading了
      this.scrollTo(0, 0);
      setTimeout(() => {
        this.scroller.triggerPullToRefresh();
      }, 100);
    },

    scrollTo(x, y, animate) {
      this.scroller.scrollTo(x, y, animate);
    },

    scrollBy(x, y, animate) {
      this.scroller.scrollBy(x, y, animate);
    },

    touchStart(e) {
      this.scroller.doTouchStart(e.touches, e.timeStamp);
    },

    touchMove(e) {
      let self = this;
      e.preventDefault();
      this.scroller.doTouchMove(e.touches, e.timeStamp);
      // 同步滚动条的位置
      let y = this.getPosition().top;
      self.bar_height = (self.container.offsetHeight / self.content.offsetHeight) * self.container.offsetHeight;
      if (self.bar_height < 50) {
        self.bar_height = 50;
      }
      self.bar_opacity = 1;
      let cp = (y / self.content.offsetHeight) * self.container.offsetHeight;
      self.bar_top = Math.round(cp);
      self.onScrolling(Math.round(cp));
      // console.log(document.getElementById(this.contentId+'_bar').getAttribute('style'))
      const { scroller_bar } = self.$refs;
      if (scroller_bar) {
        scroller_bar.style.transform = 'translate3d(0px, ' + self.bar_top + 'px, 0px) scale(1)';
        scroller_bar.style.height = self.bar_height + 'px';
        scroller_bar.style.opacity = self.bar_opacity;
      }
      // localStorage.setItem('scroller-top-' + self.contentId, self.getPosition().top)
    },

    touchEnd(e) {
      this.scroller.doTouchEnd(e.timeStamp);
      let y = this.getPosition().top;
      setTimeout(() => {
        this.onScrolling(Math.round(y));
      }, 100);
    },

    mouseDown(e) {
      this.scroller.doTouchStart(
        [
          {
            pageX: e.pageX,
            pageY: e.pageY
          }
        ],
        e.timeStamp
      );
      this.mousedown = true;
    },

    mouseMove(e) {
      if (!this.mousedown) {
        return;
      }
      this.scroller.doTouchMove(
        [
          {
            pageX: e.pageX,
            pageY: e.pageY
          }
        ],
        e.timeStamp
      );
      this.mousedown = true;
    },

    mouseUp(e) {
      if (!this.mousedown) {
        return;
      }
      this.scroller.doTouchEnd(e.timeStamp);
      this.mousedown = false;
    },

    // 获取位置
    getPosition() {
      let v = this.scroller.getValues();

      return {
        left: parseInt(v.left),
        top: parseInt(v.top)
      };
    },

    resetLoadingState() {
      let { left, top, zoom } = this.scroller.getValues();
      let container = this.container;
      let content = this.content;

      if (top + 60 > this.content.offsetHeight - this.container.clientHeight) {
        setTimeout(() => {
          this.resetLoadingState();
        }, 1000);
      } else {
        this.loadingState = 0;
      }
    }
  }
};
</script>
<style lang="css" scoped>
.cur .page-index-tip {
  display: block;
}
.page-index-tip {
  position: absolute;
  display: none;
  top: -0.15rem;
  right: 0.5rem;
  width: 0.6rem;
  height: 0.6rem;
  font-size: 0.32rem;
  color: #55789b;
  text-align: center;
  line-height: 0.6rem;
  background-color: #daecff;
  border-radius: 0.3rem;
}
.pageIndexBox {
  position: absolute;
  top: 50%;
  right: -0.3rem;
  transform: translate(-50%, -50%);
  z-index: 9999;
}
.pageIndexBox .pageIndexBtn {
  font-size: 0.24rem;
  padding: 0.01rem 0;
  width: 0.68rem;
  text-align: center;
  position: relative;
}
._scroller-bar {
  -webkit-border-radius: 0.2rem;
  -moz-border-radius: 0.2rem;
  border-radius: 0.2rem;
  transition: opacity 0.1s;
  -moz-transition: opacity 0.1s; /* Firefox 4 */
  -webkit-transition: opacity 0.1s; /* Safari 和 Chrome */
  -o-transition: opacity 0.1s; /* Opera */
  width: 0.06rem;
  background-color: rgba(0, 0, 0, 0.3);
  height: 20px; /*no*/

  -webkit-transform-origin: left top;
  -webkit-transform: translateZ(0);
  -moz-transform-origin: left top;
  -moz-transform: translateZ(0);
  -ms-transform-origin: left top;
  -ms-transform: translateZ(0);
  -o-transform-origin: left top;
  -o-transform: translateZ(0);
  transform-origin: left top;
  transform: translateZ(0);
  position: absolute;
  right: 0px; /*no*/
  top: 0rem;
  z-index: 999;
}

._v-container {
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);

  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;

  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

._v-container > ._v-content {
  width: 100%;
  -webkit-transform-origin: left top;
  -webkit-transform: translateZ(0);
  -moz-transform-origin: left top;
  -moz-transform: translateZ(0);
  -ms-transform-origin: left top;
  -ms-transform: translateZ(0);
  -o-transform-origin: left top;
  -o-transform: translateZ(0);
  transform-origin: left top;
  transform: translateZ(0);
}

._v-container > ._v-content > .pull-to-refresh-layer {
  width: 100%;
  height: 60px;
  margin-top: -60px;
  text-align: center;
  font-size: 16px;
  color: #aaa;
}

._v-container > ._v-content > .loading-layer {
  width: 100%;
  height: 60px;
  text-align: center;
  font-size: 16px;
  line-height: 60px;
  color: #aaa;
  position: relative;
}

._v-container > ._v-content > .loading-layer > .no-data-text {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}

._v-container > ._v-content > .loading-layer > .spinner-holder,
._v-container > ._v-content > .loading-layer > .no-data-text {
  opacity: 0;
  transition: opacity 0.15s linear;
  -webkit-transition: opacity 0.15s linear;
}

._v-container > ._v-content > .loading-layer > .spinner-holder.active,
._v-container > ._v-content > .loading-layer > .no-data-text.active {
  opacity: 1;
}

._v-container > ._v-content > .pull-to-refresh-layer .spinner-holder,
._v-container > ._v-content > .loading-layer .spinner-holder {
  text-align: center;
  -webkit-font-smoothing: antialiased;
}

._v-container > ._v-content > .pull-to-refresh-layer .spinner-holder .arrow,
._v-container > ._v-content > .loading-layer .spinner-holder .arrow {
  width: 20px;
  height: 20px;
  margin: 8px auto 0 auto;

  -webkit-transform: translate3d(0, 0, 0) rotate(0deg);
  transform: translate3d(0, 0, 0) rotate(0deg);

  -webkit-transition: -webkit-transform 0.2s linear;
  transition: transform 0.2s linear;
}

._v-container > ._v-content > .pull-to-refresh-layer .spinner-holder .text,
._v-container > ._v-content > .loading-layer .spinner-holder .text {
  display: block;
  margin: 0 auto;
  font-size: 14px;
  line-height: 20px;
  color: #aaa;
}

._v-container > ._v-content > .pull-to-refresh-layer .spinner-holder .spinner,
._v-container > ._v-content > .loading-layer .spinner-holder .spinner {
  margin-top: 14px;
  width: 32px;
  height: 32px;
  fill: #444;
  stroke: #69717d;
}

._v-container
  > ._v-content
  > .pull-to-refresh-layer.active
  .spinner-holder
  .arrow {
  -webkit-transform: translate3d(0, 0, 0) rotate(180deg);
  transform: translate3d(0, 0, 0) rotate(180deg);
}
</style>
