本篇文章将封装一个优雅的项目级通用弹出框。

该弹出框实现重用的同时,将内容与表现分离,让使用者可以专注于绘制弹框内容,而不用在意弹框的具体实现。

文章阅读预计15分钟。

成果预览:
在这里插入图片描述

一 父组件准备

我们创建文件modelTest.vue,将其引入父组件并注册。

// 父组件
<template>
    <div class="home">
        <button @click="modelVisit">弹框展示</button>
        <model-test v-if="modelData.isVisit"></model-test>
    </div>
</template>

<script>
import modelTest from './modelTest';

export default {
    components: {
        modelTest
    },
    data(){
        return {
            modelData: {
                isVisit: false
            }
        }
    },
    methods: {
        modelVisit(){
            this.modelData.isVisit = true;
        }
    }
}
</script>

可以看到父组件中定义了标志变量modelData.isVisit,控制弹框的展示。

当点击按钮时展示弹框组件。

二 实现弹框组件

2.1 需求分析

首先我们分析该组件中的内容,组件总体包括两部分, 遮罩和弹出框。

弹出框内容可划分为三部分,header,center,footer。

点击遮罩部分关闭弹框(组件隐藏)。

2.2 遮罩部分实现

2.2.1 绘制页面

遮罩部分在所有组件的前面,使用样式z-index=199实现。

遮罩部分占据整个视口。

// modelTest.vue
<template>
    <div class="modelTest">
        <div class="sidebox-backdrop"></div>
    </div>
</template>

<style scoped>
    .modelTest .sidebox-backdrop{
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 199;
        background-color: rgb(31 33 38 / 25%);
    }
</style>

现在点击按钮,就可以看到弹出的遮罩覆盖整个视口。

2.2.2 添加点击事件

接下来为遮罩添加点击事件。

在遮罩点击事件中,我们希望改变父组件变量的值。

update是子组件改变父组件变量时使用的语法糖。

// 用法示例 下面的代码在子组件中将变量valc付给了父组件变量bar
<comp :myMessage.sync="bar"></comp> //父
this.$emit('update:myMessage',valc); // 子

在这里我们也是同样的用法。改变组件代码如下。

子组件:

<div class="sidebox-backdrop" @click="handleClose"></div>
    methods: {
        handleClose(){
            this.$emit('update:isVisit', false)
        }
    }

父组件:

<model-test v-if="modelData.isVisit" :isVisit.sync="modelData.isVisit">

2.3 弹框部分实现

2.3.1页面绘制

弹框分为三部分 头 中 脚,为达到组件的通用性,我们将头和脚的样式固定,内容采用动态插槽的格式。

<template>
    <div class="modelTest">
        <div class="sidebox-backdrop" @click="handleClose"></div>
        <div class="sidebox-content" >
            <div class="header">
                header
            </div>
            <div class="center" :style="contentStyle">
                <slot name="center" />
            </div>
            <div class="footer">
                <slot name="footer" />
            </div>
        </div>
    </div>
</template>

弹框中header未放置插槽,因为header一般比较简单,做一个传入内容的展示即可。

2.3.2 样式添加

我们做一个位置在左侧的抽屉式弹框。

我们为弹框整体类添加样式。

弹框元素在遮罩元素的前面,使用样式z-index=200实现。

我们使用绝对定位将弹框元素相对于视口拉伸。

    .modelTest .sidebox-content{
        z-index: 200;
        position: fixed;
        left: 0;
        top: 0px;
        background-color: white;
    }

可以看到这里没有定义弹框的宽度和高度,这是为灵活性考虑,将其以变量形势定义,方便后期从父组件传入。

<div class="sidebox-content" :style="contentStyle">
    data(){
        return {
            width: '550px',
            height: '100%'
        }
    },
    computed: {
        contentStyle(){
            return {
                width: this.width, 
                height: this.height
            }
        }
    }

这样我们得到一个抽屉式弹框,接下来为弹框内部元素定义样式。

    .modelTest .sidebox-content .header, .modelTest .sidebox-content .footer{
        width: 100%;
        height: 30px;
        line-height: 30px;
    }
    .modelTest .sidebox-content .center{
        height: calc(100% - 60px);
    }

弹框组件基本上完成了,接下来我们看看如何使用。

三 使用组件

刚刚我们已经在父组件中引入了弹框组件,并且设置了点击按钮展示弹框,点击遮罩关闭弹框,在弹框中我们使用了两个插槽center和footer,在父组件中需要给出。

<model-test v-if="modelData.isVisit" :isVisit.sync="modelData.isVisit">
     <template slot="center">
         <div>center</div>
     </template>
     <template slot="footer">
          <div>footer</div>
     </template> 
</model-test>

在实际项目中,我们可以将两个插槽封装为组件,在template中使用子组件即可。

<model-test v-if="modelData.isVisit" :isVisit.sync="modelData.isVisit">
     <template slot="center">
         <center/>
     </template>
     <template slot="footer">
         <footer/>
     </template> 
</model-test>

在子组件中我们可以完成和修改复杂的逻辑页面,而不用在意弹框的实现。

点击按钮,弹框已经成功展示了。
在header center footer组件上做添加即可。
示例图片:
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐