preface

Pop-up dialog box is widely used in daily development. Whether it is a Web page, or an App, or a desktop application, you can use the dialog box to achieve a high experience of human-computer interaction. Browsing ElementUi, we can see that in its component library, there are many components about pop-up: Dialog box, pop-up box, text prompt, bubble confirmation box……

As for Ui library development, I created a set of open source Ui library project that is compatible with VUE + LESS based on the components of ElementUi. If you are interested, please come to GIT to step on it

Attachment:

  • Git – github.com/Jason9708/C…
  • Juejin. im/post/684490…

What this article will bring is to touch an ElementUi dialog box, from zero to one to understand how a qualified component is built


What is a component?

Components can be divided into business components and generic components

  • The business component
    • Only responsible for the specific business, easy to invoke, components and business coupling
    • Cannot migrate, scalability is poor
  • Common component
    • In the abstractUIComponent, without specific function implementation
    • Use requires specific business code
    • With high reuse, high scalability

How to think about implementing a qualified component? Think function → extract business function and basic function → implement basic function and define the interface of business function


Create dialog components

Demand analysis

Filtering according to the functional attributes of the ElementUi dialog, we implement the following requirements:

  • The dialog box display is controlled by the parent component and implemented by the child component
  • Headers pass values through the parent component, or throughslot
  • Specific content and the bottom are passedslotUser-defined
  • The mask layer, the body scroll, the upper right button, the theme color, custom classes, and so on are configurable
  • Callback before the popover closes, callback after the popover opens, and callback after the popover closes

The final result

The code

File directory

  • index.vue: Component file
  • index.less: the stylesheet
  • view01.vue: Tests the component file
1 – index.vueComponent files

❗ Ps:

  • $slots.footer– To determine whether the slots used in the parent component include slots named footer
  • this.$emit('update:visible', false)– This usage requires the parent component to cooperate in the bindingvisibleThe use ofsyncModifier that allows a child component to modify the value of its parent component
  • handleClose– This method is passed when the parent component has passed beforeClose and it is functionhide()This usage implements additional operations on the parent component before closingbeforeCloseThe function can take one argument, which is used to actively close the popover
<template>
    <div class='cai-dialog-wrapper' ref='dialog-wrapper' v-show='visibleDialog' @click.self='handleWrapperClick'>
        <transition name="dialog-fade">
            <div ref='dialog'
                 :class="['cai-dialog',{ 'cai-dialog-dark':dark },customClass]"
                 :style='dialogSize'
                  v-if='dialogRender'> <! <div class='cai-dialog-header'> <! -- Dialog title, which can be replaced --> <slot name='title'>
                        <span class='cai-dialog__title'>{{ title }}</span> </slot> <! Close the dialog button --> <buttontype='button'
                        class='cai-dialog__headerbtn'
                        aria-label='Close'
                        v-if='displayClose'
                        @click='handleClose'>
                        <i class='cai-icon-close'></i> </button> </div> <! <div class='cai-dialog-body'> <slot></slot> </div> <! <div class='cai-dialog-footer' v-if='$slots.footer'>
                    <slot name='footer'></slot>
                </div>
            </div>
        </transition>
    </div>
</template>

<script>
export default {
    name:'CaiDialog'.data() {return{
            visibleDialog:false,
            dialogRender:false, dialogSize:{} // props:{visible:{type: Boolean,
            default: false
        },
        title:{
            type: String,
            default: ' '}, // turns off the callback to the pop-up window (which takes one argument)done()) beforeClose: Function, // if the mask layer is needed modal:{type: Boolean,
            default: true}, // Whether to lock body scroll when Dialog appears lockScroll: {type: Boolean,
            default: true}, // can you close Dialog closeOnClickModal by clicking modal: {type: Boolean,
            default: false}, // Whether to display the upper-right close button displayClose:{type: Boolean,
            default: trueHigh}, / / the biggest wide width: String, height: String, / / theme colors - highlighting (default) | dark night: {type:Boolean,
            default:false}, // customClass: {type:String,
            default:' '
        }
    },
    watch:{
        visible(newVal){
            if(newVal){
                this.visibleDialog = true
                this.dialogRender = trueChangeDialogStyle () this. ChangeDialogStyle () this.$emit('open')}else{
                this.visibleDialog = false
                this.dialogRender = false
                document.body.style['overflow'] = 'auto'
                this.$emit('close')
            }
        }
    },
    methods:{
        handleWrapperClick() {if(! this.closeOnClickModal)returnThis.handleclose ()}, // handles the closing dialog, called if beforeClose existshandleClose() {if(typeof this.beforeClose === 'function') {
                this.beforeClose(this.hide)
            }else{
                this.hide()
            }
        },
        hide(){
            this.$emit('update:visible'.false); }, // Modify the Dialog style based on the Props valuechangeDialogStyle(){// lockScroll - disables the underlying scrollif(this.lockScroll) document.body.style['overflow'] = 'hidden'
            var that = this
            this.$nextTick(() => {
                var dialogWrapperStyle = that.$refs['dialog-wrapper'].style
                var dialogStyle = that.$refs.dialog.style
                if(that.width) dialogStyle.width = that.width + 'px'
                if(that.height) dialogStyle.height = that.height + 'px'// Implement an unmasked layerif(! that.modal) dialogWrapperStyle.background ='transparent'
            })
        }
    }
}
</script>

<style lang='less' scoped>
@import './index.less';
@import '.. /.. /CaiIcon/component/index.less'; // Icon style sheet can be ignored </style>Copy the code
2 – index.lessThe stylesheet
.cai-dialog-wrapper{ position: fixed; top:0; bottom:0; right: 0; left: 0; overflow: auto; Background: rgba (0,0,0,0.6); z-index:1999; // Default style.cai-dialog{position:absolute; border:1px solid rgba(247, 241, 240); border-radius:5px; color:# 303952;
        padding:10px;
        left:50%;
        top:50%;
        transform:translate(-50%, -50%);
        display:flex;
        flex-direction: column;
        justify-content: space-between;
        background: rgba(247, 241, 240);
        min-width:200px;
        min-height:100px;
        overflow: auto;
        .cai-dialog-header{
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom:10px;
            font-size:14px;
            .cai-dialog__title{
                font-weight: 600;
            }
            .cai-dialog__headerbtn{
                background: transparent;
                border-color: transparent;
                padding:0;
                outline:none;
                .cai-icon-close{
                    color:# 303952;
                    cursor:pointer;
                    transition: all .1s linear;
                    &:hover{
                        color:#ff3f34;} } } } .cai-dialog-body{ flex:1; }} // night mode. Cai-dialog-dark {border-color: border-color:#3d3d3d;
        background: #3d3d3d;
        color:#fff;
        .cai-dialog-header{
            .cai-dialog__headerbtn{
                .cai-icon-close{
                    color:#fff;
                    cursor:pointer;
                    transition: all .1s linear;
                    &:hover{
                        color:#ef5777;}}}}} // Enter/leave animation. Dialog-fade -enter-active,.dialog-fade-leave-active {transition: all.3s linear; } .dialog-fade-enter { opacity: 0; top:48%; }}Copy the code
3 – view01.vueTest component files
<! -- visible - Control display title - popover title beforeClose - Callback modal before popover closes - Whether mask layer is needed lockScroll - whether body scroll is locked when Dialog appears CloseOnClickModal - whether can be closed by clicking on the modal Dialog displayClose - whether show dark corner close button - theme colors - highlighting (default) | customClass - custom class at night @open-dialog Open callback @close-dialog closed callback slot {footer - bottom unnamed - content} --> <div style='width:310px; padding:20px; border:1px solid #DDDDDD; display:flex; flex-wrap:wrap; '>
  <cai-button @click='openDialog1'> Highlight dialog box </cai-button> <cai-dialog :visible.sync='showDialog1' closeOnClickModal width='400' height='200' title='I am Light' :before-close='handleDialogClose' @open='DialogOpen' @close='DialogClose'> 
    I am a Dialog
    <span slot="footer" style='display:flex; justify-content:flex-end; '>
      <cai-button @click="showDialog1 = false"> </cai-button> < cai-button@click ="showDialog1 = false"> determine < / CAI - button > < / span > < / CAI - dialog > < CAI - divider > < / CAI - divider > < CAI - button @ click ='openDialog2'> Night dialog </cai-button> <cai-dialog :visible.sync='showDialog2' dark :displayClose='false' :lockScroll='false' :before-close='handleDialogClose'> <! -- custom header from slot --> <span slot="title">
     I am Dark
    </span>
    I am a Dialog
    <span slot="footer" style='display:flex; justify-content:flex-end; '>
      <cai-button @click="showDialog2 = false"> </cai-button> < cai-button@click ="showDialog2 = false"> < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; white-space: inherit! Important;"Copy the code
data() {return{
        // Dialog
        showDialog1:false,
        showDialog2:false}}methods() {openDialog1(){
      this.showDialog1 = true
    },
    openDialog2(){
      this.showDialog2 = true
    },
    DialogOpen(){
      console.log('DialogOpen')},DialogClose(){
      console.log('DialogOpen')
    },
    handleDialogClose(done){
      console.log('Popover is closed')
      done()}}Copy the code

The end of the

Component Open Source Address

Github.com/Jason9708/C…

Git is an open source UI library project, currently developed nearly 20 UI components adapted to Vue, interested partners to ⭐

Screenshot of some components