scroll-nav-bar.vue 4.4 KB
Newer Older
1 2 3 4
<template>
  <div class="cube-scroll-nav-bar" :class="'cube-scroll-nav-bar_' + direction">
    <cube-scroll
      ref="scroll"
T
tank0317 已提交
5
      nestMode="none"
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
      :options="options"
      :direction="direction">
      <div class="cube-scroll-nav-bar-items" ref="items">
        <div
          class="cube-scroll-nav-bar-item"
          v-for="(txt, index) in txts"
          :key="index"
          :class="{'cube-scroll-nav-bar-item_active': active === labels[index]}"
          @click="clickHandler(labels[index])">
          <slot
            :txt="txt"
            :index="index"
            :active="active"
            :label="labels[index]">
              <span v-html="txt"></span>
            </slot>
        </div>
      </div>
    </cube-scroll>
  </div>
</template>

<script type="text/ecmascript-6">
  import scrollMixin from '../../common/mixins/scroll'
  import CubeScroll from '../scroll/scroll.vue'

  const DIRECTION_H = 'horizontal'
  const DIRECTION_V = 'vertical'

  const COMPONENT_NAME = 'cube-scroll-nav-bar'
  const EVENT_CHANGE = 'change'

  export default {
    name: COMPONENT_NAME,
40 41 42 43 44 45
    inject: {
      scrollNav: {
        default: null
      }
    },
    mixins: [scrollMixin],
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    props: {
      direction: {
        type: String,
        default: DIRECTION_H,
        validator(val) {
          return val === DIRECTION_H || val === DIRECTION_V
        }
      },
      labels: {
        type: Array,
        default() {
          /* istanbul ignore next */
          return []
        }
      },
      txts: {
        type: Array,
        default() {
          /* istanbul ignore next */
          return this.labels
        }
      },
      current: {
        type: [String, Number],
        default: ''
      }
    },
    data() {
      return {
        active: this.current
      }
    },
    watch: {
      current(newVal) {
        this.active = newVal
      },
      active(newVal) {
        this.$emit(EVENT_CHANGE, newVal)
        this._adjust()
      }
    },
    mounted() {
      this.scrollNav && this.scrollNav.setBar(this)
      if (this.active) {
        // waiting panels loaded
        this.$nextTick(() => {
          this._adjust()
        })
      }
    },
    beforeDestroy() {
      this.scrollNav && this.scrollNav.setBar(null)
    },
    methods: {
      clickHandler(label) {
        if (label === this.active) {
          return
        }
        this.active = label
        this.scrollNav && this.scrollNav.barChange(label)
      },
      refresh() {
        this.$refs.scroll.refresh()
        this._adjust()
      },
      _adjust() {
        // waiting ui
        this.$nextTick(() => {
          const isHorizontal = this.direction === DIRECTION_H
          const targetProp = isHorizontal ? 'clientWidth' : 'clientHeight'
          const active = this.active
          const viewportSize = this.$refs.scroll.$el[targetProp]
          const itemsEle = this.$refs.items
          const scrollerSize = itemsEle[targetProp]
          const minTranslate = Math.min(0, viewportSize - scrollerSize)
          const middleTranslate = viewportSize / 2
          const items = itemsEle.children
          let size = 0
          this.labels.every((label, index) => {
            if (label === active) {
              size += (items[index][targetProp] / 2)
              return false
            }
            size += items[index][targetProp]
            return true
          })
          let translate = middleTranslate - size
          translate = Math.max(minTranslate, Math.min(0, translate))
          this.$refs.scroll.scrollTo(isHorizontal ? translate : 0, isHorizontal ? 0 : translate, 300)
        })
      }
    },
    components: {
      CubeScroll
    }
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">
  @require "../../common/stylus/variable.styl"

  .cube-scroll-nav-bar
    position: relative
    display: flex
    color: $scroll-nav-color
    background-color: $scroll-nav-bgc
  .cube-scroll-nav-bar_horizontal
    align-items: center
    .cube-scroll-wrapper
      flex: 1
      text-align: center
    .cube-scroll-content
      display: inline-block
    .cube-scroll-nav-bar-items
      white-space: nowrap
  .cube-scroll-nav-bar_vertical
    height: 100%
    justify-content: center
    text-align: center
    .cube-scroll-nav-bar-item
      display: block
  .cube-scroll-nav-bar-items
    font-size: $fontsize-medium
  .cube-scroll-nav-bar-item
    display: inline-block
    padding: 20px 15px
  .cube-scroll-nav-bar-item_active
    color: $scroll-nav-active-color
</style>