美文网首页
elementui 的el-scrollbar

elementui 的el-scrollbar

作者: Clover园 | 来源:发表于2021-07-20 09:48 被阅读0次

    el-scrollbar不出现横向滚动条,要触发resize才会出现,有bug,需要自己修复

    //这样就可以了,主要触发upda的方法
    watch: {
        visitedViews() {
          const el = this.$refs.scrollContainer
          el.update()
        }
      },
    

    使用

    import tagsView from './TagsView'
    <tags-view />

    image.png

    TagsView/ScrollPane.vue

    <template>
      <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
        <slot />
      </el-scrollbar>
    </template>
    
    <script>
    const tagAndTagSpacing = 4 // tagAndTagSpacing
    
    export default {
      name: 'ScrollPane',
      props: {
        visitedViews: {
          type: Array,
          default: () => []
        }
      },
      data() {
        return {
          left: 0
        }
      },
      watch: {
        visitedViews() {
          const el = this.$refs.scrollContainer
          el.update()
        }
      },
      computed: {
        scrollWrapper() {
          return this.$refs.scrollContainer.$refs.wrap
        }
      },
      methods: {
        handleScroll(e) {
          const eventDelta = e.wheelDelta || -e.deltaY * 40
          const $scrollWrapper = this.scrollWrapper
          $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
        },
        moveToTarget(currentTag) {
          const $container = this.$refs.scrollContainer.$el
          const $containerWidth = $container.offsetWidth
          const $scrollWrapper = this.scrollWrapper
          const tagList = this.$parent.$refs.tag
    
          let firstTag = null
          let lastTag = null
    
          // find first tag and last tag
          if (tagList.length > 0) {
            firstTag = tagList[0]
            lastTag = tagList[tagList.length - 1]
          }
    
          if (firstTag === currentTag) {
            $scrollWrapper.scrollLeft = 0
          } else if (lastTag === currentTag) {
            $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
          } else {
            // find preTag and nextTag
            const currentIndex = tagList.findIndex(item => item === currentTag)
            const prevTag = tagList[currentIndex - 1]
            const nextTag = tagList[currentIndex + 1]
    
            // the tag's offsetLeft after of nextTag
            const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
    
            // the tag's offsetLeft before of prevTag
            const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
    
            if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
              $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
            } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
              $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
            }
          }
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .scroll-container {
      white-space: nowrap;
      position: relative;
      // overflow: hidden;
      width: 100%;
      /deep/ {
        .el-scrollbar__bar {
          bottom: 0px;
          .el-scrollbar__thumb{
            // min-width:100%;
          }
        }
        .el-scrollbar__wrap {
          height: 49px;
          overflow-x: hidden;
        }
      }
    }
    </style>
    
    

    TagsView/index.vue

    <template>
      <div id="tags-view-container" class="tags-view-container">
        <scroll-pane ref="scrollPane" class="tags-view-wrapper" :visitedViews="visitedViews">
          <router-link
            v-for="tag in visitedViews"
            ref="tag"
            :key="tag.path"
            :class="isActive(tag)?'active':''"
            :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
            tag="span"
            class="tags-view-item"
            @click.middle.native="closeSelectedTag(tag)"
            @contextmenu.prevent.native="openMenu(tag,$event)"
          >
            {{ tag.title }}
            <span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
          </router-link>
        </scroll-pane>
        <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
          <li @click="refreshSelectedTag(selectedTag)">刷新</li>
          <li v-if="!(selectedTag.meta&&selectedTag.meta.affix)&&visitedViews.length>1" @click="closeSelectedTag(selectedTag)">关闭</li>
          <li @click="closeOthersTags" v-if="visitedViews.length>1">关闭其他</li>
          <li @click="closeAllTags(selectedTag)" v-if="visitedViews.length>1">关闭全部</li>
        </ul>
      </div>
    </template>
    
    <script>
    import ScrollPane from './ScrollPane'
    import path from 'path'
    
    export default {
      components: { ScrollPane },
      data() {
        return {
          visible: false,
          top: 0,
          left: 0,
          selectedTag: {},
          affixTags: []
        }
      },
      computed: {
        visitedViews() {
          return this.$store.state.tagsView.visitedViews
        },
        routes() {
          return this.$store.state.routers
        }
      },
      watch: {
        $route() {
          this.addTags()
          this.moveToCurrentTag()
        },
        visible(value) {
          if (value) {
            document.body.addEventListener('click', this.closeMenu)
          } else {
            document.body.removeEventListener('click', this.closeMenu)
          }
        }
      },
      mounted() {
        this.initTags()
        this.addTags()
      },
      methods: {
        isActive(route) {
          return route.path === this.$route.path
        },
        filterAffixTags(routes, basePath = '/') {
          let tags = []
          routes.forEach(route => {
            if (route.meta && route.meta.affix) {
              const tagPath = path.resolve(basePath, route.path)
              tags.push({
                fullPath: tagPath,
                path: tagPath,
                name: route.name,
                meta: { ...route.meta }
              })
            }
            if (route.children) {
              const tempTags = this.filterAffixTags(route.children, route.path)
              if (tempTags.length >= 1) {
                tags = [...tags, ...tempTags]
              }
            }
          })
          return tags
        },
        initTags() {
          const affixTags = this.affixTags = this.filterAffixTags(this.routes)
          for (const tag of affixTags) {
            // Must have tag name
            if (tag.name) {
              this.$store.dispatch('tagsView/addVisitedView', tag)
            }
          }
        },
        addTags() {
          const { name } = this.$route
          if (name) {
            this.$store.dispatch('tagsView/addView', this.$route)
          }
          return false
        },
        moveToCurrentTag() {
          const tags = this.$refs.tag
          this.$nextTick(() => {
            for (const tag of tags) {
              if (tag.to.path === this.$route.path) {
                this.$refs.scrollPane.moveToTarget(tag)
                // when query is different then update
                if (tag.to.fullPath !== this.$route.fullPath) {
                  this.$store.dispatch('tagsView/updateVisitedView', this.$route)
                }
                break
              }
            }
          })
        },
        refreshSelectedTag(view) {
          this.$store.dispatch('tagsView/delCachedView', view).then(() => {
            const { fullPath } = view
            this.$nextTick(() => {
              this.$router.replace({
                path: '/redirect' + fullPath
              })
            })
          })
        },
        closeSelectedTag(view) {
          this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
            if (this.isActive(view)) {
              this.toLastView(visitedViews, view)
            }
          })
        },
        closeOthersTags() {
          this.$router.push(this.selectedTag)
          this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
            this.moveToCurrentTag()
          })
        },
        closeAllTags(view) {
          this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
            debugger
            if (this.affixTags.some(tag => tag.path === view.path)) {
              return
            }
            this.toLastView(visitedViews, view)
          })
        },
        toLastView(visitedViews, view) {
          const latestView = visitedViews.slice(-1)[0]
          if (latestView) {
            this.$router.push(latestView)
          } else {
            const _path = this.$store.state.menus[0].path ? this.$store.state.menus[0].path : '/'
            this.$router.push(_path)
          }
        },
        openMenu(tag, e) {
          const menuMinWidth = 105
          const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
          const offsetWidth = this.$el.offsetWidth // container width
          const maxLeft = offsetWidth - menuMinWidth // left boundary
          const left = e.clientX - offsetLeft + 15 // 15: margin right
    
          if (left > maxLeft) {
            this.left = maxLeft
          } else {
            this.left = left
          }
    
          this.top = e.clientY
          this.visible = true
          this.selectedTag = tag
        },
        closeMenu() {
          this.visible = false
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .tags-view-container {
      height: 34px;
      width: 100%;
      background: #fff;
      border-bottom: 1px solid #d8dce5;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
      .tags-view-wrapper {
        .tags-view-item {
          display: inline-block;
          position: relative;
          cursor: pointer;
          height: 26px;
          line-height: 26px;
          border: 1px solid #d8dce5;
          color: #495060;
          background: #fff;
          padding: 0 8px;
          font-size: 12px;
          margin-left: 5px;
          margin-top: 4px;
          &:first-of-type {
            margin-left: 15px;
          }
          &:last-of-type {
            margin-right: 15px;
          }
          &.active {
            // #42b983
            background-color: #002140;
            color: #fff;
            border-color: #002140;
            &::before {
              content: '';
              background: #fff;
              display: inline-block;
              width: 8px;
              height: 8px;
              border-radius: 50%;
              position: relative;
              margin-right: 2px;
            }
          }
        }
      }
      .contextmenu {
        margin: 0;
        background: #fff;
        z-index: 3000;
        position: absolute;
        list-style-type: none;
        padding: 5px 0;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 400;
        color: #333;
        box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
        li {
          margin: 0;
          padding: 7px 16px;
          cursor: pointer;
          &:hover {
            background: #eee;
          }
        }
      }
    }
    </style>
    
    <style lang="scss">
    //reset element css of el-icon-close
    .tags-view-wrapper {
      .tags-view-item {
        .el-icon-close {
          width: 16px;
          height: 16px;
          vertical-align: 2px;
          border-radius: 50%;
          text-align: center;
          transition: all .3s cubic-bezier(.645, .045, .355, 1);
          transform-origin: 100% 50%;
          &:before {
            transform: scale(.6);
            display: inline-block;
            vertical-align: -3px;
          }
          &:hover {
            background-color: #b4bccc;
            color: #fff;
          }
        }
      }
    }
    </style>
    
    

    相关文章

      网友评论

          本文标题:elementui 的el-scrollbar

          本文链接:https://www.haomeiwen.com/subject/aislmltx.html