辽宁住房和城乡建设部网站,网站外链怎么购买,建立网站 杭州,windows vps offline性x文章目录 学习链接效果图代码要点 简单模拟el-menu实现TestTree.vueMenu.vueSubMenu.vue 学习链接
vue实现折叠展开收缩动画 - 自己的链接
elment-ui/plus不定高度容器收缩折叠动画组件 - 自己的链接
vue的过渡与动画理解
Vue transition 折叠类动画自动获取隐藏层高度以及… 文章目录 学习链接效果图代码要点 简单模拟el-menu实现TestTree.vueMenu.vueSubMenu.vue 学习链接
vue实现折叠展开收缩动画 - 自己的链接
elment-ui/plus不定高度容器收缩折叠动画组件 - 自己的链接
vue的过渡与动画理解
Vue transition 折叠类动画自动获取隐藏层高度以及手风琴效果实现
vue transition动画钩子- vue官网
vue transition 过渡动画
基于vue渐变展开收起盒子动画盒子高度不定
效果图 代码
要点
需要注意这个dom结构过渡动画一定要有开始和结束值才能产生动画并且在js里面修改的时候不能连着修改要把第二次修改放到setTimeout里面为了让菜单能够不是一次性过渡让它可以一直产生过渡动画需要在动画结束后清理掉设置的高度这个设置的高度只需要在动画的时候生效。以上的操作参考了elementui的el-menu 和 iview里面的menu使用下面这种原生的方式实现之后再对比vue的transition组件的的钩子函数感觉好类似阿可参考vue项目中实现折叠面板动画效果就是不知道我这样用setTimeout到底属不属于正常操作。不过感觉理解了下面这个之后再去看vue的transition过渡钩子好像就比较容易理解了
style langscss scoped
import url(//at.alicdn.com/t/c/font_4065865_kb7oyb2wje9.css);
ul,
li {margin: 0;list-style: none;padding: 0;
}.tree-wrapper {width: 200px;border: 1px solid #ccc;border-radius: 5px;user-select: none;
}.menu-title {padding: 7px 12px;cursor: pointer;display: flex;align-items: center;justify-content: space-between;:hover{background-color: #eee;}i.iconfont.icon-jiantou {font-size: 26px;display: inline-block;transition: transform 0.3s;}
}// 箭头展开样式
.menu-opened .menu-title i.icon-jiantou {transform: rotate(180deg);
}// 子菜单高度使用过渡
ul.menu {transition: all 0.3s;overflow: hidden;
}/styletemplatediv classtree-wrapperul classmenuli classmenu-submenu menu-opened div classmenu-title data-expandedtrue clickclickMenu($event)divspan目录1/span/divi classiconfont icon-jiantou/i/divul classmenu idt1-uli classmenu-submenu menu-opened div classmenu-title data-expandedtrue stylepadding-left: 43px; clickclickMenu($event)divspan目录1-1/span/divi classiconfont icon-jiantou/i/divul classmenuli classmenu-item data-expandedtruediv classmenu-title stylepadding-left: 67px;divspan菜单1-1-1/span/div/div/li/ul/lili classmenu-itemdiv classmenu-title stylepadding-left: 43px;divspan菜单1-2/span/div/div/li/ul/lili classmenu-submenu menu-opened div classmenu-title data-expandedtrue clickclickMenu($event)divspan目录2/span/divi classiconfont icon-jiantou/i/divul classmenuli classmenu-itemdiv classmenu-title stylepadding-left: 43px;divspan菜单2-1/span/div/div/lili classmenu-itemdiv classmenu-title stylepadding-left: 43px;divspan菜单2-2/span/div/div/li/ul/lili classmenu-itemdiv classmenu-titledivspan菜单4/span/div/div/li/ul/div
/templatescript setupfunction clickMenu(e) {// console.log(e.target,e.target); // 获取的是发生事件的对象,有可能是子元素// console.log(e.currentTarget,e.currentTarget); // 获取的是绑定了事件的对象, 这里用的是这个!// console.log(e.currentTarget.dataset); // 自定义的dataset属性// console.log(e.currentTarget.nextSibling); // 下一个兄弟节点// 获取绑定了点击事件的对象, 即目录的那个menu-title这个domlet currentTarget e.currentTarget// 使用dataset自定义属性, 将当前目录所对应的子节点是否为展开状态, 记录到data-expanded属性当中, 作为一个标记// 如果它是打开状态, 那么就需要关闭它if(currentTarget.dataset[expanded] true) {console.log(1);// 获取目录的下一个节点ullet ul currentTarget.nextSibling// 移除掉父节点的menu-opened类这个类用来控制三角形的旋转状态ul.parentNode.classList.remove(menu-opened)// 在打开状态下先去获取ul的scrollHeight值作为ul的height值里面有个细节如果ul中还有未展开的节点那么此时获取ul的scrollHeight是不包括未展开节点的高度的// 获取这个高度的目的是因为// 1. 我们知道关闭的时候的高度是0但是不知道打开状态下的高度是多少不能是auto写auto的话高度是正常了但是没有过渡动画所以拿scrollHeight作为高度// 2. 我们一定要保持在动画完毕时, 高度要清理掉, 否则后面的动画无法继续下去。所以不能直接设置style.height,然后就不管了, 动画完成后要清理掉style.height。ul.style.height ul.scrollHeight px// 这里的setTimeout不能省略, 虽然延迟时间为0。// 上面设置了起始高度如果要产生过渡动画的话那就要另一个高度值关闭的时候结束高度显然是0px但是不能直接立马设置为0px// 需要放在虾米那这个setTimeout里面去。setTimeout((){console.log(ul);// 设置结束高度ul.style.height 0pxconst func (){// 这里的意思就是想在动画结束后把高度清空然后将ul给隐藏掉保持干净// 动画都结束了将ul隐藏掉ul.style.display none// 解绑事件函数ul.removeEventListener(transitionend,func)// 记录当前目录是关闭状态currentTarget.dataset[expanded] false// 将高度置为空这个很重要动画结束后这个高度一定要清空掉因为这个高度不能写死// 如果写死了万一它里面还有子节点的话子节点一旦展开那这个高度肯定不够// 我们需要的只是在过渡的时候需要它的高度ul.style.height nullconsole.log(currentTarget.dataset[expanded],123);}// 在动画结束后直接func函数ul.addEventListener(transitionend, func)},0)} else {// 如果它是关闭状态, 那么就需要打开它// 打开它的话就必须要知道它有多高才能产生动画实现0到指定高度的变化console.log(2);// 拿到目录标题dom的下一个节点ullet ul currentTarget.nextSibling// 三角形打开状态ul.parentNode.classList.add(menu-opened)// 开始是0px过渡的起始值ul.style.height 0px// 可见状态ul.style.display block// 修改ul的高度必须要写在setTimeout里面不能在setTimeout外面立马改掉setTimeout((){// 设置过渡的结束值ul.style.height ul.scrollHeight pxconst func (){// 解除事件绑定ul.removeEventListener(transitionend,func)// 记录当前是打开状态currentTarget.dataset[expanded] true// 将高度置为空这个很重要动画结束后这个高度一定要清空掉因为这个高度不能写死// 如果写死了万一它里面还有子节点的话子节点一旦展开那这个高度肯定不够// 我们需要的只是在过渡的时候需要它的高度ul.style.height null}// 动画结束后收尾工作ul.addEventListener(transitionend, func)})}}
/script
简单模拟el-menu实现 生成的结构与上面完全一致所以还是要先把想要的样子先写出来规划好然后再通过vue拆分组件去实现。 获得的效果与上面一致但是写法更加的简单并且使用到了element-ui的CollapseTransition组件需要从el的源码中导入 注意下面在拆分组件的时候的技巧把当前的菜单标题和这个菜单下的子菜单拆成一个组件SubMenu这个组件专门负责生成子菜单 vue是可以支持两个组件之间相互引用的下面的Menu组件和SubMenu组件就是相互引用了 通过vue实现比上面写起来简单多了 TestTree.vue
templateMenu :menu-listmenuList stylewidth: 200px;border: 1px solid #ddd;border-radius: 4px;/Menu
/templatescript setup
import { ref,reactive } from vueimport Menu from ./Menu.vuelet menuList ref([{id: 1,title: 目录1,type: 1,children: [{id: 2,title: 目录1-1,type: 1,children: [{id: 3,title: 菜单1-1-1,type: 2,}]},{id: 4,title: 菜单1-2,type: 2,}]},{id: 5,title: 目录2,type: 1,children: [{id: 6,title: 菜单2-1,type: 2,},{id: 7,title: 菜单2-2,type: 2,}]},{id: 8,title: 菜单4,type: 2,}
])/scriptstyle langscss/styleMenu.vue
templateul classmenutemplate v-for(menu) in menuList :keymenu.idSubMenu v-ifmenu.type 1 :menumenu :levellevel/SubMenuli v-else classmenu-itemdiv classmenu-title :levellevel :style{padding-left: level 1?7px: 30 * (level - 1) px }divspan{{ menu.title }}/span/div/div/li/template/ul
/templatescript setup
import { ref, reactive } from vue
import SubMenu from ./SubMenu.vueconst props defineProps({level: {type: Number,default: 1},menuList: {type: Array,}
})const menuShow ref(true)/scriptstyle langscss scoped
import url(//at.alicdn.com/t/c/font_4065865_kb7oyb2wje9.css);ul,
li {margin: 0;list-style: none;padding: 0;
}.tree-wrapper {width: 200px;border: 1px solid #ccc;border-radius: 5px;user-select: none;
}.menu-title {padding: 7px 12px;cursor: pointer;display: flex;align-items: center;justify-content: space-between;:hover {background-color: #eee;}i.iconfont.icon-jiantou {font-size: 26px;display: inline-block;transition: transform 0.3s;}
}// 箭头展开样式
.menu-opened.menu-titlei.icon-jiantou {transform: rotate(180deg);
}// 子菜单高度使用过渡
ul.menu {transition: all 0.3s;overflow: hidden;
}
/styleSubMenu.vue
templateli :class[menu-submenu,{menu-opened: submenuShow}]div classmenu-title :levellevel :style{padding-left: level 1?7px: 30 * (level - 1) px } clicksubmenuShow !submenuShowdivspan{{ menu.title }}/span/divi classiconfont icon-jiantou/i/divtemplate v-ifmenu.children menu.children.length 0CollapseTransitionMenu v-showsubmenuShow :menu-listmenu.children :level level 1/Menu/CollapseTransition/template/li
/templatescript setup
import { ref,reactive } from vue
import CollapseTransition from element-plus/lib/components/collapse-transition/src/collapse-transition;
import Menu from ./Menu.vue
const props defineProps({menu: {type:Object},level: {type: Number,}
})const submenuShow ref(true)/scriptstyle langscss scoped
import url(//at.alicdn.com/t/c/font_4065865_kb7oyb2wje9.css);
ul,
li {margin: 0;list-style: none;padding: 0;
}.tree-wrapper {width: 200px;border: 1px solid #ccc;border-radius: 5px;user-select: none;
}.menu-title {padding: 7px 12px;cursor: pointer;display: flex;align-items: center;justify-content: space-between;:hover{background-color: #eee;}i.iconfont.icon-jiantou {font-size: 26px;display: inline-block;transition: transform 0.3s;}
}// 箭头展开样式
.menu-opened .menu-title i.icon-jiantou {transform: rotate(180deg);
}// 子菜单高度使用过渡
ul.menu {transition: all 0.3s;overflow: hidden;
}
/style