前端攻城?️对模态弹框确定很熟悉,无论是套用bootstrap的仍是本身写的,它经常使用来完成与用户的展现交互和处理一些数理逻辑。可是在用来展现小体量的信息时我认为它是过于庞大的,咱们能够采用更优雅的气泡卡片来展现那些小体量的信息。
就像这样的↓↓↓
先附上体验地址css
<div class="v-popover-tag" @click.stop="pop($event)"> <slot></slot> </div> <div class="v-popover-wrap" :style="{left: x + 'px', top: y + 'px', visibility: show ? 'visible' : 'hidden'}" v-el:pop> <div class="v-popover-box"> <div class="v-popover-title">{{title}}</div> <div class="v-popover-content">{{content}}</div> <div :class="['v-popover-arrow', placement == 'top' ? 'v-popover-arrow-top' : 'v-popover-arrow-bottom']" :style="{left: arrowLeft + 'px'}"></div> </div> </div>
这里对熟悉vue的同窗来说没有什么特殊的地方,主要有一个slot
标签会有疑问,在编译模版时遇到slot
标签会回到html
文档中用相应的内容代替,使用方式能够参考官方文档vue-slothtml
props: { title: { type: String, default: '标题' }, content: { type: String, default: '内容' }, placement: { type: String, default: 'top' } }, data() { return { show: false, arrowLeft: 0, x: 0, y: 0 } }
来自父组件的数据title
和content
是必选项(虽然我也给它们设置了默认值),placement
表明气泡卡片的出现位置,默认会出如今触发目标的上方,暂时支持top和bottom。其余都是子组件的自身数据,用于控制气泡卡片的显示隐藏和位置。前端
pop(e) { if(this.show){ this.show = false return } var target = e.target this.arrowLeft = target.offsetWidth / 2 this.x = target.offsetLeft if(this.placement == 'top'){ this.y = target.offsetTop - this.$els['pop'].offsetHeight - 3 }else { this.y = target.offsetTop + target.offsetHeight + 3 } this.show = true }
这里依靠事件的冒泡,slot
中的事件会冒泡到子组件中定义的父层div
标签上,进而触发事件执行后续的位置计算。vue
这方面难点主要是那两个小三角形的,其余的都比较简单。git
.v-popover-arrow{ position: absolute; width: 0; height: 0; border: 5px solid transparent; margin-left: -5px; &:after{ content: " "; margin-left: -4px; border: 4px solid transparent; position: absolute; width: 0; height: 0; } } .v-popover-arrow-top{ border-bottom-width: 0; border-top-color: #d9d9d9; bottom: -5px; &:after{ border-top-color: #fff; bottom: -3px; } }
html: <div id="app"> <v-popover :title="popTitle" :content="popContent" :placement="popPlacement"> <button class="btn btn-primary">点击弹出气泡卡片</button> </v-popover> </div> js: var btn = new Vue({ el: '#app', data: { popTitle: '我是标题' popContent: '气泡内容气泡内容气泡内容气泡内容气泡内容气泡内容气泡内容气泡内容气泡内容', popPlacement: 'top' }, components: { 'v-popover': components.popover } })
这里我在组件标签中插了一个button
标签,上面提到的slot
最终就会被这个按钮代替,同时它的点击事件会通过冒泡被触发。github
插播小广告。。。不要打我,我和@二胖手正在维护相关组件库web-style,待组件基本完善后,参考文档也会跟上,欢迎关注,有什么好的建议也欢迎讨论。web