Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue-index 一个vue的字母索引组件 #7

Open
EasonYou opened this issue Mar 28, 2018 · 0 comments
Open

Vue-index 一个vue的字母索引组件 #7

EasonYou opened this issue Mar 28, 2018 · 0 comments

Comments

@EasonYou
Copy link
Owner

Vue-index 一个vue的字母索引组件

前言

公司需求要是实现一个首字母索引的功能,类似于微信通讯录那样的效果。在多次在github上查找都没有找到类似的实现,所以自己就简单地实现了一把。

dom结构

主要的dom解构分两大块,一大块是索引内容的列表,一大块是字母列表

<div
  class="index-lists-wapper"
  ref="scrollTarget">
  <div
    class="index-lists-content"
    ref="scrollWapper">
    <div
      v-for="(item, index) in finalDatas"
      :data-character="item.character"
      :key="index"
      class="list-item">
    </div>
  </div>
</div>
<div
  class="side-index-wapper"
  ref="sideIndexWapper"
  @mousedown="bindSideItemMouseDownEvent"
  @mousemove="bindSideItemMouseMoveEvent"
  @mouseup="bindSideItemMouseUpEvent">
  <div
    v-for="(item, index) in finalCharacters"
    :key="index"
    class="side-index-item">
  </div>
  </div>
</div>

在内容索引列表上,绑定上data-set,好在后面做查找对比。
因为要实现按住滑动还能查找的功能,在字母列表上做了事件代理,减少dom的事件绑定。

字母列表事件处理

mousedown的情况下,设置一个标志位为isMouseDown。在mousemove的时候切换查找的字母,最后mouseup的时候设标志位为false
在这里有一个问题就是在超出区域范围,会使得mouseup无效,所以在created的时候绑定了下windows,解决超出范围无效的情况。

bindSideItemMouseDownEvent (e) {
  this.isMouseDown = true
  this.lastTime = new Date()
  this.switchCharacter(e)
},
bindSideItemMouseMoveEvent (e) {
  const nowTime = new Date()
  if (nowTime - this.lastTime > this.throttleTime) {
    this.lastTime = nowTime
    this.switchCharacter(e)
  }
},
bindSideItemMouseUpEvent (e) {
  this.isMouseDown = false
  this.modalFlag = false
}

// created 
created () {
  const self = this
  document.addEventListener('mouseup', () => {
    self.isMouseDown = false
    self.modalFlag = false
  })
}

接下来是switchCharacter方法

switchCharacter (e) {
  if (this.isMouseDown) {
    // 判断是否可以触发判断,触发条件是是否代理到了side-index-item类的dom
    // 并返回这个字母
    let character = this.isCanTrigger(e)
    // 如果这个字母变了的话,就可以改变查看的索引字母了
    if (character && character !== this.character) {
      this.character = character
    }
  }
}
//
isCanTrigger (e) {
  let target = e.target
  let flag = false
  // while循环查找是否有side-index-item
  while (target) {
    if (target && target.className === 'side-index-item') {
      flag = true
      break
    }
    target = target.parentNode
  }
  if (!flag) {
    return false
  }
  // 这里 -2 是因为有个modal(字母弹出层)还有一个text dom
  // 因为是按循序排序,所以找出index,就可以找出对应的首字母
  let index = Array.from(this.$refs.sideIndexWapper.childNodes).indexOf(target) - 2
  return this.finalCharacters[index]
}

最后只要watch索引字母character就可以做滚动了

watch: {
  character (newVal, oldVal) {
    // 获取traget是为了滚动
    // 获取wapper是为了获取他的childNodes就是列表项
    const scrollTarget = this.$refs.scrollTarget
    const scrollWapper = this.$refs.scrollWapper
    const scrollItems = Array.from(scrollWapper.childNodes)
    let offsetTop
    // 遍历查找,找到就跳出便利,取得目标dom的offsetTop
    scrollItems.some((item) => {
      if (item.className === 'list-item' && item.dataset.character === newVal) {
        offsetTop = item.offsetTop
        return true
      }
    })
    // 进行滚动
    scrollTarget.scrollTop = offsetTop === undefined ? scrollTarget.scrollTop : offsetTop
  }
}

到此位置就是整个索引的主要流程,具体的代码可以看项目vue-index

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant