上面的实现方式,只能实现固定模板内容,如果后期遇到其他气泡弹窗,但是内容不同的时候,这个组件就得修改才能用,所以还有一种实现方式:采用具名插槽
来实现popover框架,template、css部分可由调用者自由定义。
那么理想情况下,用户可以这么调用(假如我们的组件是:im-popover):
<im-popover v-model="visible">
<div><!--弹窗内容--></div>
<button slot="trigger">触发元素</button>
</im-popover>
弹窗内容是默认插槽,按钮元素需要声明slot=“trigger”
- 首先实现一个最基本的,我们点击trigger元素显示这个弹窗内容
<!--ImPopover.vue-->
<template>
<div class="im-popover__box" @click="handleClick">
<!--弹窗主体部分-->
v-show="visible"
ref="popoverDom"
:style="positionStyle"
class="im-popover">
ref="arrowDom"
:style="{left: `${arrowLeft}px`}"
class="im-popover__arrow"
<!--可自定义内容,默认插槽-->
<slot></slot>
<!--触发弹窗元素-->
<slot name="trigger"></slot>
</template>
<style lang="scss">
.im-popover {
z-index: 1000;
position: absolute;
max-width: 660px;
&__arrow {
// ...
&__box {
/* 这里需要设置成行内元素 */
display: inline-block;
</style>
- 编写对应的script脚本
其实就是之前的index.js和index.vue的结合,不过需要把this.$el
改成this.$refs.popoverDom
。
<script>
export default {
name: 'ImPopover',
props: {
// ...
methods: {
open() {
if (!this.visible) {
// 把popover组件追加到body尾部
this.appendContainer();
// ...
} else {
this.close();
appendContainer() {
document.body.appendChild(this.$refs.popoverDom);
handleClick(event) {
// 阻止冒泡
event.stopPropagation();
this.open();
// ...
</script>
<template>
<im-popover placement="top">
<div class="popover-content">
<img class="image" src="https://static-web.likeevideo.com/as/indigo-static/test/diamond.png" alt="">
<p class="txt">原始文字是人类用来紀錄特定事物、簡化圖像而成的書寫符號。 文字在发展早期都是图画形式的,有些是以形表意</p>
<div slot="trigger" class="app__button app__button--small">自定义弹窗内容</div>
</im-popover>
</template>
<script>
import ImPopover from './ImPopOver';
export default {
name: 'App',
components: {
ImPopover
</script>
<style lang="scss">
.popover-content {
width: 468px;
padding: 12px;
box-sizing: border-box;
display: flex;
align-items: center;
flex-direction: column;
.image {
width: 148px;
height: auto;
vertical-align: top;
.txt {
margin-top: 20px;
font-size: 28px;
color: #fff;
text-align: center;
</style>
好了,组件的两种实现方法都讲完了,其实popover组件涉及的功能比较多,比如有弹窗触发方式的配置(例如click、hover)、弹窗内容是否支持滚动和点击、弹窗的显示与隐藏回调、弹窗动画等等功能。这个等到以后组件需要拓展时再考虑吧。
如果你看到这篇文章,希望对你了解popover组件开发原理有所帮助。
欢迎大家留言讨论,祝工作顺利、生活愉快!
我是bigo前端,下期见。
本文首发于:https://github.com/bigo-frontend/blog/ 欢迎关注、转载。需求分析:组件可设置弹出位置(placement),支持top、bottom气泡弹窗弹出位置计算,边界计算,支持设置边界范围支持点击弹窗元素之外的区域,弹窗关闭支持弹窗内容自定义效果预览:实现方案实现自定义组件, 我们一般都会想到Vue.extend,vue.extend相当于一个扩展实例构造器,用于创建一个具有初始化选项的Vue子类,在实例化时可以进行扩展选项,最后使用$mou.
支持返回键, 可以按浏览器返回按钮关闭popup
可以写出小复杂的过度动画, 比如磁贴按压效果[在popUpMenu可看到]
支持css动画库, 比如animation.css, 使用的时候自行添加依赖就好了
提供了几个比较好的popup组...
要修改 `Popup` 组件中 `title` 的样式,你可以将自定义的样式传递给 `Popup` 组件的 `title` 属性。
具体来说,你可以使用 `title` 属性的 `style` 属性来定义样式。例如:
```jsx
<Popup
title="这是一个标题"
style={{ color: 'red', fontSize: '20px' }}
这是弹出框的内容。
</Popup>
上述代码将标题的字体颜色设置为红色,字体大小设置为 20 像素。
如果你想更细粒度地修改标题的样式,你可以使用 `title` 属性的 `className` 属性来添加一个自定义的 CSS 类名,然后在 CSS 样式表中定义该类名的样式。例如:
```jsx
<Popup
title="这是一个标题"
className="custom-title"
这是弹出框的内容。
</Popup>
在 CSS 样式表中,你可以定义 `.custom-title` 类名的样式:
```css
.custom-title {
color: red;
font-size: 20px;
这样,标题的字体颜色将会是红色,字体大小为 20 像素。