组件之间的通信
复制代码 扩展 for Mac for Windows 如何使用 快速入门 进阶配置 多语言支持
selected的传递
如图所示,关于(selected
:被选中的那个item),在menu
里面控制,通过watchChild
“监听每个item”,一旦menu-item
被点击便会触发
this.$emit('menuItemUpdate',this.name)复制代码
这里menu
便会通过menu-item
的$emit
和$on
实现数据的传递
watchChild(){ this.items.forEach(vm=>{ vm.$on('menuItemUpdate',name=>{ this.$emit('update:selected',[name]) }) }) },复制代码
这里的this.items
就是收集的每一个menu-item
,这在一开始就已经完成了。 要用到依赖注入
,这里面子组件menu-item
都直接操作menu
的data
,耦合度非常高。
//menu provide(){ return { root:this } }复制代码
//menu-item inject:['root'], created(){ this.root.addItem(this) //......... },复制代码
然后告诉menu-item
你可以被选中了。updated
钩子函数用作完成这个任务再适合不过了
updated(){ this.updateChild() }, methods:{ updateChild(){ this.items.forEach(vm=>{ if(this.selected.indexOf(vm.name)>-1){ vm.selected = true }else{ vm.selected = false } }) } } 复制代码
路径元素的收集
当menu-item
被选中时,触发tellParents
函数,收集这条路径上所有父元素的name
,把这个收集好的数据放到selectedArr
里面。这个还可以用来高亮路径上的父元素。 在click的时候触发onClick
函数
onClick(){ //........... let subFather = this.$parent.$el.classList.contains('x-sub-menu') this.$parent.$el.classList.contains('x-sub-menu') let groupFather = this.$parent.$el.classList.contains('x-menu-item-group') //.......... if(subFather||groupFather){ //....... this.tellParents(this) //....... }else{ //....... } },复制代码
tellParents
递归调用自身来收集 name
tellParents(that){ if(that.$parent.$parent.$options.name==='x-sub-menu' ||that.$parent.$parent.$options.name==='x-menu-item-group'){ this.root.selectedArr.unshift(that.$parent.name) this.tellParents(that.$parent) }else{ this.root.selectedArr.unshift(that.$parent.name) console.log(this.root.selectedArr) } },复制代码
最后就是我希望在menu-item
被选中后,可以关闭路径的所有弹出框popover。 这同样需要一个递归遍历
childClosePopover(){ if(this.$parent.$options.name==='x-sub-menu'){ this.open = false this.$parent.childClosePopover() } },复制代码
自定义主题颜色的实现
参照了一下Menu Attribute。 这里的文字颜色和图标颜色是同步的, hover的css效果和active
的一样
- text-color文字颜色 。
- active-color被选中颜色。
- back-ground-color正常背景色 。
- active-back-ground-color被选中的背景色 。
数据传递
如图所示的紫色的路线,通过递归遍历通知menu树
里面的每一个分支,改变颜色,是否垂直,disabled等等。 大部分添加的功能都在这条线上实现通信。
js控制颜色的更改
watch:{ selected(){ if(this.selected&&........{ this.$refs.item.style.backgroundColor = ........ this.$refs.item.style.color = ......... //........... }else{ //............ } } }复制代码
弹出框的问题
element对弹出框的操作是以在body
上添加子节点的方式。这样子最直接的就是避免了可能存在overflow:hideen
的问题。 后面的定位只需要用js来完成就行了,还要考虑到scroll
的问题。
最麻烦的地方在于动画过渡
上,单纯的用css会有弹出框回到原点的问题。 这里就需要用到 。 官网在这上面的说的很明确,但是实现过程中也踩了一些坑
- 动画瞬间完成的问题,这在官网上的解释时只用
JavaScript
做过渡的时候(没用css)的情况下动画会瞬间完成,要使用done。之后试了并没有用。这里并不是只用JavaScript做过渡的。之后想了一下,既然beforeEnter
和enter
瞬间就执行了,并没有动画的事件间隔,为什么不自己加一个settimeout
呢,问题就解决了,可能这种解决方法并不是很好。这里不用$nextTick
的
enter(el) { setTimeout(()=>{ //..... }) },复制代码
- 钩子中设置的一些额外的css属性要在
afterEnter
改回来啊,其中就例如overflow:hidden
和height
,导致在vertical
垂直面板上弹出框不会撑开父元素的问题。
afterLeave(el){ el.style.overflow = '' if(this.vertical){ el.style.height='' } },复制代码
后面就是和定位弹出框一样类似的js操作,在menu
导航菜单里面我并没有这么做,后面会改成这样的吧。
beforeEnter(el) { el.style.position= 'absolute' el.style.transform=....... //......... }, enter(el) { //...... },复制代码
处理一些细枝末节的问题
hover
触发和click
触发- 弹出框移出消失的时间控制和动画抖动。
- 高亮线条只在一级子组件中存在
menu-item-group
组件的添加,其实只是作为一个中转站而已,无非是拷贝一些函数。- 一些多层嵌套的位置问题,尚未完成。
遇到的一些css问题
- 横版里面
active
下面的亮条显示,一开始就是设置menu-item
里面的border-bottom
,因为同时设置了transition
。在显示的时候会有高度抖动的问题。后来改用伪类完成,不过在自定义颜色的时候非常麻烦。这个方法也放弃了。最后只有在下面加一个div
代替border-bottom
作为高亮线条,方法虽然很蠢,但是有效。 scoped
里面给某些子组件添加css样式用到了/deep/
深度作用。
简单的总结?
其实以这种显而易见的数据流作为基础,多增加一些功能无非是函数的添加和css的修改。找bug和维护也是相对比较轻松的。最后您如果觉得还不错的话,给我的项目一个star想必也是极好的。