1. 上一次的问题总结。
- overflow:hidden -> body.appendChild
- 关闭重复 -> 分开,document 只管外面,popover 只管里面
- 忘了取消监听 document -> 收拢 close
2. 可以把一个函数哟没有五行作为一个优化的标准,简称为五行定律
3. 接下来把样式改好点
.content-wrapper { // 如果写了scoped,popover里面那么就只作用于popover里面,移到外面就在外面了就可以 position: absolute; border: 1px solid $border-color; border-radius: $border-radius; filter: drop-shadow(0 0 1px rgba(0,0,0,0.5)); /*通过drop-shadow解决小三角没有阴影的问题,但是兼容性不好 */ /*box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);*/ background: white; transform: translateY(-100%); margin-top: -10px; padding: .5em 1em; max-width: 20em; word-break: break-all; &::before , &::after{ content: ''; display: block; width: 0; height: 0; position: absolute; border: 10px solid transparent; left: 10px; } &::after{ content: ''; display: block; width: 0; height: 0; position: absolute; border: 10px solid transparent; left: 10px; } &::before { border-top-color: black; top: 100%; } &::after { border-top-color: white; top: calc(100% - 1px); } }
4. 增加功能:用户可以选择 popover 是上面下面左面右面
// 先要给contentWrapper加一个类,传递进入位置信息 <div ref="contentWrapper" class="content-wrapper" v-if="visible" :class="{[`position-${position}`]:true}"> </div> // 获得位置信息 props: { position:{ type: String, default: 'top', validator(value){ return ['top','bottom','left','right'].indexOf(value) >= 0 } } }, } // 在method里面写方法,主要控制大概位置 method: { positionContent() { const {contentWrapper, triggerWrapper} = this['$refs'] document.body.appendChild(contentWrapper) let {width, height, top, left} = triggerWrapper.getBoundingClientRect() if(this.position === 'top'){ contentWrapper.style.left = left + window.scrollX + "px" contentWrapper.style.top = top + window.scrollY + "px" }else if(this.position === 'bottom'){ contentWrapper.style.left = left + window.scrollX + "px" contentWrapper.style.top = top + height + window.scrollY + "px" }else if(this.position === 'left'){ contentWrapper.style.left = left + window.scrollX + "px" let {height: height2} = contentWrapper.getBoundingClientRect() contentWrapper.style.top = top + window.scrollY + (height - height2)/2 + "px" }else if(this.position === 'right'){ contentWrapper.style.left = left + window.scrollX + width + "px" let {height: height2} = contentWrapper.getBoundingClientRect() contentWrapper.style.top = top + window.scrollY + (height - height2)/2 + "px" } }, } // 然后对css进行处理,主要是箭头当想 <style lang="scss" scoped> $border-color: #333; $border-radius: 4px; .popover { display: inline-block; vertical-align: top; position: relative; } .content-wrapper { // 如果写了scoped,popover里面那么就只作用于popover里面,移到外面就在外面了就可以 position: absolute; border: 1px solid $border-color; border-radius: $border-radius; filter: drop-shadow(0 0 1px rgba(0,0,0,0.5)); /*通过drop-shadow解决小三角没有阴影的问题,但是兼容性不好 */ /*box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);*/ background: white; padding: .5em 1em; max-width: 20em; word-break: break-all; &::before , &::after{ content: ''; display: block; border: 10px solid transparent; width: 0; height: 0; position: absolute; } &.position-top { transform: translateY(-100%); margin-top: -10px; &::before, &::after{ left: 10px; } &::before { border-top-color: black; top: 100%; } &::after { border-top-color: white; top: calc(100% - 1px); } } &.position-bottom { margin-top: 10px; &::before, &::after{ left: 10px; } &::before { border-bottom-color: black; bottom: 100%; } &::after { border-bottom-color: white; bottom: calc(100% - 1px); } } &.position-left{ transform: translateX(-100%); margin-left: -10px; &::before, &::after{ transform: translateY(-50%); top: 50%; } &::before { border-left-color: black; left: 100%; } &::after { border-left-color: white; left: calc(100% - 1px) } } &.position-right{ margin-left: 10px; &::before, &::after{ transform: translateY(-50%); top: 50%; } &::before { border-right-color: black; right: 100%; } &::after { border-right-color: white; right: calc(100% - 1px) } } } </style>
5.发现目前代码比较冗余,进一步优化代码
多个 if else 逻辑相似,首先要把共有代码抽上去,利用表驱动编程的技巧。
positionContent() { const {contentWrapper, triggerWrapper} = this['$refs'] document.body.appendChild(contentWrapper) const {width, height, top, left} = triggerWrapper.getBoundingClientRect() const {height: height2} = contentWrapper.getBoundingClientRect() let positions = { top: { top: top + window.scrollY, left: left + window.scrollX }, bottom: { top: top + height + window.scrollY, left: left + window.scrollX }, left: { top: top + window.scrollY + (height - height2)/2, left: left + window.scrollX }, right: { top: top + window.scrollY + (height - height2)/2, left: left + window.scrollX + width }, } contentWrapper.style.left = positions[this.position].left + 'px' contentWrapper.style.top = positions[this.position].top + 'px' },
6.实现 hover 的效果
// 每个事件的处理逻辑不一样,所以要分开写if mounted(){ if(this.trigger === 'click'){ this['$refs']['popover'].addEventListener('click',this.onClick) } else { this['$refs']['popover'].addEventListener('mouseenter',this.open) this['$refs']['popover'].addEventListener('mouseleave',this.close) } }, // 负责任的轮子要写destory,防止内存泄露 destroyed(){ if(this.trigger === 'click'){ this['$refs']['popover'].removeEventListener('click',this.onClick) } else { this['$refs']['popover'].removeEventListener('mouseenter',this.open) this['$refs']['popover'].removeEventListener('mouseleave',this.close) } },
最后,个人微信,欢迎交流!

来源:https://www.cnblogs.com/ories/p/12244955.html