手风琴效果

242 阅读1分钟

思路

  • 获取所有的菜单,点击时展开或者折叠其兄弟元素的菜单
  • 给子菜单设置一个属性status,判断其状态是关闭,打开,还是正在进行中
  • 根据其属性写打开子菜单的函数,关闭子菜单的函数,还有两者之间相互切换
  • 封装一个展示动画效果的函数

image.png

 <ul class="container">
    <li class="menu">
      <h2>菜单1</h2>
      <ul class="submenu">
        <li>菜单1</li>
        <li>菜单2</li>
        <li>菜单3</li>
        <li>菜单4</li>
      </ul>
    </li>
    <li class="menu">
      <h2>菜单2</h2>
      <ul class="submenu">
        <li>菜单1</li>
        <li>菜单2</li>
        <li>菜单3</li>
        <li>菜单4</li>
      </ul>
    </li>
    <li class="menu">
      <h2>菜单3</h2>
      <ul class="submenu">
        <li>菜单1</li>
        <li>菜单2</li>
        <li>菜单3</li>
        <li>菜单4</li>
      </ul>
    </li>
    <li class="menu">
      <h2>菜单4</h2>
      <ul class="submenu">
        <li>菜单1</li>
        <li>菜单2</li>
        <li>菜单3</li>
        <li>菜单4</li>
      </ul>
    </li>
  </ul>
// 初始化
var title = document.querySelectorAll(".menu h2")
var itemHeight = 30
var totalMS = 300


// 交互
for (var i = 0; i < title.length; i++){
  title[i].onclick = function () {
    // 收起其他子菜单
    var beforeOpen = document.querySelector('.submenu[status=open]')
    if (beforeOpen) {
      closeSubMenu(beforeOpen)
    }
    toggleSubMenu(this.nextElementSibling)
  }
}

// 打开子菜单
function openSubMenu(subMenu) {
  // 判断子菜单是打开open,关闭close,还是正在打开中playing
  var status = subMenu.getAttribute('status')
  if (status && status !== 'close') {
    return
  }
  // 把状态设置成正在打开中
  subMenu.setAttribute('status', 'playing')
  createAnimation({
    from: 0,
    to: itemHeight * subMenu.children.length,
    totalMS: totalMS,
    move(n) {
      subMenu.style.height = n + 'px'
    },
    moveEnd() {
      subMenu.setAttribute('status', 'open')
    }
  })
}

// 关闭子菜单
function closeSubMenu(subMenu) {
  var status = subMenu.getAttribute('status')
  if (status !== 'open') {
    return
  }
  subMenu.setAttribute('status', 'close')
  createAnimation({
    from: itemHeight * subMenu.children.length,
    to: 0,
    totalMS: totalMS,
    move(n) {
      subMenu.style.height = n + 'px'
    },
    moveEnd() {
      subMenu.setAttribute('status', 'close')
    }
  })
}

// 切换状态
function toggleSubMenu(subMenu) {
  var status = subMenu.getAttribute('status')
  if (status === 'playing') {
    return
  } else if (status === 'open') {
    closeSubMenu(subMenu)
  } else {
    openSubMenu(subMenu)
  }
}
function createAnimation(option) {
  var from = option.from
  var to = option.to
  var totalMS = option.totalMS || 500
  var duration = option.duration || 15
  var time = totalMS / duration
  var dis = Math.floor(to - from) / time

  var currentTime = 0
  var timerId = setInterval(() => {
    from += dis
    currentTime++
    if (currentTime >= time) {
      from = to
      clearInterval(timerId)
      option.moveEnd && option.moveEnd()
    }
    option.move && option.move(from)
  }, duration);
}