早期React多级折叠动效选项菜单思考与实现

折叠菜单或者叫多级选项菜单,用流行UI框架下的相关实现改改就好了,为什么要手写?因为手痒 啊,有个简单方法特别想印证一下效果。前面的选项框就不做了,就是你点击了用一个数组去收集id之类的数据。我主要实现一下效果。

1.首先模拟的数据结构:

js 复制代码
let [list, setList] = useState([{
    title: "父标题111",
    child: [{
      title: '子标题1111'
    }, {
      title: '子标题1112',
      child: [
        { title: '子标题11121' },
        {
          title: '子标题11122',
          child: [
            { title: "子标题111221" },
            { title: "子标题111222" },
            { title: "子标题111223" },
            { title: "子标题111224" },
            { title: "子标题111225" },
            { title: "子标题111226" },
          ]
        }
      ]
    }, {
      title: '子标题1113'
    }]
  },
  {
    title: "父标题222",
    child: [{
      title: '子标题2221'
    }]
  },
  { title: "父标题333" }
  ])

2.控制child显示隐藏可不是用display/visibility属性就行了,有动画效果要用transition和控制高度。用到的样式,一些想法都在代码注释里:

css 复制代码
*{
    margin: 0;
    padding: 0;
}
.uuu{  
    transition:0.5s;
    height:0;  //一开始子项的ul列表要隐藏
    overflow: hidden;
}
ul{
    padding-left:20px; 
}

3.视图起始

js 复制代码
function App() {
...//上面的模拟数据
 return (
    <List list={list} />
  )
}

4.List定义,设计上肯定是组件递归。

js 复制代码
function List(props) {
  return <ul className={[props.iso ? 'uuu' : '', 'out'].join(' ')} >
    {props.list.map((t, i) => {
      return <>
        <li key={i} >
          <div onClick={(e) => { t.child && an(e, t.child.length) }}>{t.title}</div>
          {t.child && <List list={t.child} iso={true}></List>}
        </li>
      </>
    })
    }
  </ul>
}

5.想法:点击title的div如果是显示子菜单,除了下一层ul要显示高度,它的所有上层都要增加这个高度,标识它可控外层的条件是增加了'out'这个class,父级没有这个class表示不是菜单本身不需要增加高度。

增加的iso={true}是什么,为什么视图起始没有?这个是控制子菜单一开始隐藏的,而最外层不需要隐藏。

6.核心代码。首先"展开"效果,上面有说,不仅本身高度展开,所有上层都要加这个高度:

js 复制代码
let lout = (e, l) => {
  if (e.className.indexOf('out') > -1) {
    e.style.height = e.clientHeight + l + 'px'
    lout(e.parentNode.parentNode, l)  
  } //点击的是div,它的上级是li,再上级才是ul。
}

7."折叠"效果,不仅折叠本身,它的所有子级都要折叠起来:

js 复制代码
let lin = (e) => {
  e.style.height = 0
  e.childNodes.forEach(_e => {
    if (_e.childNodes.length > 1) {
      lin(_e.childNodes[1])
    }
  });
}

为什么要判断>1并且childNodes取第二项?因为有第一项div层。

8.控制逻辑。

js 复制代码
let nHeight = 21

let an = (e, l) => {
  let dom = e.currentTarget.nextSibling
  let flag = dom.clientHeight == 0 ? false : true
  if (flag) {
    lout(dom, dom.clientHeight * (-1))
    lin(dom)
  } else {
    lout(dom, l * nHeight)
  }
}

如果当前菜单为折叠态,那就展开它和它的所有上层菜单;如果当前菜单是展开态,那不仅要折叠它和它的所有子级菜单,同时要把所有上层菜单也减少这个高度,也就是为什么要*(-1)。

相关推荐
谢尔登1 小时前
【React】React 18 并发特性
前端·react.js·前端框架
Joker`s smile1 小时前
使用React+ant Table 实现 表格无限循环滚动播放
前端·javascript·react.js
国家不保护废物1 小时前
🌟 React 魔法学院入学指南:从零构建你的第一个魔法阵(项目)!
前端·react.js·架构
然我1 小时前
从原生 JS 到 React:手把手带你开启 React 业务开发之旅
javascript·react.js·前端框架
国家不保护废物1 小时前
从刀耕火种到现代框架:DOM编程 vs Vue/React 进化史
前端·vue.js·react.js
代码搬运媛1 小时前
React 中 HTML 插入的全场景实践与安全指南
安全·react.js·html
大得3692 小时前
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
前端·javascript·react.js
白瓷梅子汤2 小时前
跟着官方示例学习 @tanStack-table --- Column Ordering
前端·react.js
我想说一句2 小时前
React组件化开发实战:从"待办事项"看前端乐高搭建术
前端·javascript·react.js
Dontla9 小时前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript