• vue封装自己的组件库 02.封装dialog组件



    link: https://blog.csdn.net/weixiaowei_2016/article/details/104702793


    四、封装一个element-ui风格的dialog组件

    前置知识:

    1. vue过渡动画
    2. sync修饰符
    3. 具名插槽与v-slot指令

    参数支持:

    参数名参数描述参数类型默认值
    title对话框标题string提示
    width宽度string50%
    top与顶部的距离string15vh
    visible是否显示dialog(支持sync修饰符)booleanfalse

    事件支持:

    事件名事件描述
    opened模态框显示事件
    closed模态框关闭事件

    插槽说明:

    插槽名称插槽描述
    defaultdialog的内容
    titledialog的标题
    footerdialog的底部操作区

    4.1dialog组件的基本框架和样式

    首先搭建起来dialog组件的框架,暂时不加入插槽,只构建出基本的框架和样式。

    框架分为三个部分,头部(header)、内容(body)、底部(footer),基本框架如下:

    <template>
     <div class="one-dialog_wrapper">
       <div class="one-dialog">
         <div class="one-dialog_header">
           <span class="one-dialog_title">提示span>
           <button class="one-dialog_headerbtn">
             <i class="one-icon-close">i>
           button>
         div>
         <div class="one-dialog_body">
           <span>这是一段信息span>
         div>
         <div class="one-dialog_footer">
           <one-button>取消one-button>
           <one-button type="primary">确定one-button>
         div>
       div>
     div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    样式如下:

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 这里按钮样式的修改用到了深度穿透 https://www.jianshu.com/p/2c6ce46d8ed1 因为在dialog组件内部修改了button组件的样式 改不动 需要深度穿透
    • scope做的事情 最终全局样式覆盖了局部样式
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLQNbXZ4-1658968650503)(image-20210731104904330.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAiETklx-1658968650505)(image-20210731105023277.png)]

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mprZXZf-1658968650506)(image-20210731105224740.png)]

    在main.js注册后,在app.vue中引用,形成以下效果:

    4.2自定义title内容

    title标题部分除了普通的标题内容外,也应该可以设置标题的样式,比如设置为h1红色的自定义标题内容,所以在这里我们就使用到了插槽,可以在使用时按照需求自定义标题内容和样式。

    4.2.0父子组件传值以及props验证不再赘述,之前内容已经介绍。

    核心点5 使用插槽

    4.2.1将标题span标签放到slot插槽下,这样便于控制span的内容和样式。

    <template>
     <div class="one-dialog_wrapper">
       <div class="one-dialog">
         <div class="one-dialog_header">
           <slot name="title">
             
            <span class="one-dialog_title">
              {{title}}
            span>
           slot>
           <button class="one-dialog_headerbtn">
             <i class="one-icon-close">i>
           button>
         div>
         <div class="one-dialog_body">
           <span>这是一段信息span>
         div>
         <div class="one-dialog_footer">
           <one-button>取消one-button>
           <one-button type="primary">确定one-button>
         div>
       div>
     div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4.2.2通过父子组件之间得传值以及slot指定组件自定义title内容和样式。

     <one-dialog title="温馨提示">
            
            <template v-slot:title>
              <h3 style="color:red">我是标题h3>
            template>
          one-dialog>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2.3效果如下

    4.3自定义dialog的宽度和距离顶部的

    4.3.1实现在组件调用时控制dialog组件的宽度以及位置。

    只需要在父组件中传递宽度和高度,并且在子组件中获取并且使用即可。

    父组件传值:

    <one-dialog width="80%" top="200px">one-dialog>
    
    • 1

    子组件使用:

    <template>
     <div class="one-dialog_wrapper">
       <div class="one-dialog" :style="{width:width,marginTop:top}">
         ···
       div>
     div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.4自定义body内容

    body内容可能是除span以外的其他内容,比如列表等,所以在这里使用插,并且在这里使用匿名插槽,使用匿名插槽的好处就是在使用时不需要使用template标签指定内容,直接在组件标签下编写内容即可

    4.4.1在body中使用匿名组件

    <div class="one-dialog_body">
        <slot>slot>
    div>
    
    • 1
    • 2
    • 3

    4.4.2在父组件中,只需要在标签下直接编辑内容即可,不需要再使用template标签绑定插槽或者父子组件传值了

    <one-dialog>
        <ul>
            <li>1li>
            <li>2li>
            <li>3li>
        ul>
    one-dialog>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.4.3显示效果

    4.5自定义footer内容

    footer中使用slot插槽,在父组件中的定义底部内容。

    核心点6 查看父组件有无传参

    4.5.1设置footer插槽,如果没有指定footer插槽,则不显示

     <div class="one-dialog_footer">
       
       <slot name="footer" v-if="$slots.footer">slot>
     div>
    
    • 1
    • 2
    • 3
    • 4

    4.5.2父组件中的定义footer插槽内容

    <template v-slot:footer>
        <one-button>取消one-button>
        <one-button type="primary">确定one-button>
    template>
    
    • 1
    • 2
    • 3
    • 4

    4.6dialog的显示与隐藏

    核心点6 使用sync语法糖

    dialog组件的显示与隐藏,需要使用到sync语法糖。这里简单介绍以下什么是sync语法糖,sync通俗来说,是父子组件传值过程中提供的一种模式,这种模式有两个功能:1.将父组件向子组件传值;2.子组件回调一个值给父组件。

    打个比方,如下代码需要两部才能实现上述功能:1.向子组件传值;2.接收子组件回调的值

    //父组件传值 
    <demo :visible="visible" :money="money" @update:aa="fn1">demo>
    //子组件回调
      methods: {
        fn () {
         this.$emit('aa', 200)
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用sync语法糖后,父组件不需要单独声明一个方法,只需要在回调时声明一个update绑定的回调函数(这个绑定值是传值自身)这样在父组件中就不需要再次定义回调函数进行接收了。 子组件依旧需要触发提交时间 this.$emit(‘update:visible’, true)

    //父组件中的使用sync语法糖,传递和接收参数
     
      <demo :visible.sync="visible" :money.sync="money">demo>
    //子组件中使用update绑定参数的方法进行回调
      methods: {
        fn () {
          this.$emit('update:money', 200)
          this.$emit('update:visible', true)
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    根据上面对于sync语法糖的介绍,我们在dialog显示和隐藏中要进行两种处理

    控制dialog的显示和隐藏,我们首先在子组件中使用v-show对于组建的显示与隐藏进行控制。

    <div class="one-dialog_wrapper" v-show="visible" @click.self="handleClose">
       ···
    div>
    
    • 1
    • 2
    • 3

    4.6.1父组件控制dialog的显示和隐藏

    父组件中的直接通过传递一个参数visible,使用点击方法控制这个参数的布尔值即可。

    <one-dialog :visible.sync="visible">
        <ul>
            <li>1li>
            <li>2li>
            <li>3li>
        ul>
        <template v-slot:footer>
            <one-button @click="switchDialog">取消one-button>
            <one-button type="primary">确定one-button>
        template>
    one-dialog>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.6.2子组件控制dialog的显示和隐藏

    子组件控制dialog的显示和隐藏,不能直接修改父组件传递过来的值,需要使用回调触发父组件中的值进行修改,这里就使用到了上面介绍的sync语法糖。

    首先在父组件中使用:visible.sync="visible"向子组件进行传值并且接收子组件回调。

    <div class="row">
        <one-dialog :visible.sync="visible">
            <ul>
                <li>1li>
                <li>2li>
                <li>3li>
            ul>
            <template v-slot:footer>
                <one-button @click="switchDialog">取消one-button>
                <one-button type="primary">确定one-button>
            template>
        one-dialog>
    div>   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UNgaxSe-1658968650508)(image-20210731101841529.png)]

    子组件通过自身定义的方法,控制dialog组件的显示与隐藏,然后将visible属性回调给父组件。

    <template v-slot:footer>
      <one-button>取消one-button>
      <one-button type="primary">确定one-button>
    template>
    
    • 1
    • 2
    • 3
    • 4

    回调方法:

      method{
        handleClose () {
          this.$emit('update:visible', false)
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总结:

    • 父组件传递的变量添加sync
    • 子组件想要改变数据时直接触发 this.$emit(‘update:visible’, false) 函数即可

    4.7dialog的动画效果

    使用transition包裹一个元素后,这个元素就会被自动添加类名,这部分vuejs文档都有介绍。

    4.7.1使用transition包裹整个dialog框架

    <template>
      <transition name="dialog-fade">
        <div class="one-dialog_wrapper" v-show="visible" @click.self="handleClose">
            ···
        div>
      transition>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.7.2使用vue动画进行处理

    这里先定义了fade动画,然后在dialog组件显示和隐藏的时候调用(反向调用)这个动画。

    .dialog-fade-enter-active{
      animation: fade .3s;
    }
    .dialog-fade-leave-active{
      animation: fade .3s reverse;
    }
    @keyframes fade{
      0% {
        opacity: 0;
        transform: translateY(-20px);
      }
      100%{
        opacity: 1;
        transform: translateY(0);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    -------------------------------------------------------至此,dialog组件封装完成!-----------------------------------------------

    附组件代码:

    <template>
      <transition name="dialog-fade">
        
        <div class="one-dialog_wrapper" v-show="visible" @click.self="handleClose">
          <div class="one-dialog" :style="{width:width,marginTop:top}">
            <div class="one-dialog_header">
              <slot name="title">
                
              <span class="one-dialog_title">
                {{title}}
              span>
              slot>
              <button class="one-dialog_headerbtn" @click="handleClose">
                <i class="one-icon-close">i>
              button>
            div>
            <div class="one-dialog_body">
              
              
              <slot>slot>
            div>
            <div class="one-dialog_footer">
              
              <slot name="footer" v-if="$slots.footer">
              slot>
            div>
          div>
        div>
      transition>
    template>
     
    <script>
     
    export default {
      name: 'oneDialog',
      components: {
      },
      props: {
        title: {
          type: String,
          default: '提示'
        },
        width: {
          type: String,
          default: '50%'
        },
        top: {
          type: String,
          default: '15vh'
        },
        footer: {
          type: Object
        },
        visible: {
          type: Boolean,
          default: false
        }
      },
      data () {
        return {
          show: false
        }
      },
      methods: {
        handleClose () {
          this.$emit('update:visible', false)
        }
      }
    }
    script>
     
    <style lang="scss" scoped>
    .one-dialog_wrapper{
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      overflow: auto;
      margin: 0;
      z-index: 2001;
      background-color: rgba(0,0,0,0.5);
      .one-dialog{
        position: relative;
        margin: 15vh auto 50px;
        background: #fff;
        border-radius: 2px;
        box-shadow: 0 1px 3px rgba(0,0,0,0.3);
        box-sizing: border-box;
        width: 30%;
        &_header{
          padding: 20px 20px 10px;
          .one-dialog_title{
            line-height: 24px;
            font-size: 18px;
            color: #303133;
          }
          .one-dialog_headerbtn{
            position: absolute;
            top: 20px;
            right: 20px;
            padding: 0;
            background: transparent;
            border: none;
            outline: none;
            cursor: pointer;
            font-size: 16px;
            .one-icon-close{
              color:909399
            }
          }
        }
        &_body{
          padding: 30px 20px;
          color: #606266;
          font-size: 14px;
          word-break: break-all;
        }
        &_footer{
          padding: 10px 20px 20px;
          text-align: right;
          box-sizing: border-box;
          ::v-deep .one-button:first-child{
            margin-right: 20px;
          }
        }
      }
    }
    .dialog-fade-enter-active{
      animation: fade .3s;
    }
    .dialog-fade-leave-active{
      animation: fade .3s reverse;
    }
    @keyframes fade{
      0% {
        opacity: 0;
        transform: translateY(-20px);
      }
      100%{
        opacity: 1;
        transform: translateY(0);
      }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
  • 相关阅读:
    Linux系统操作MySql常用命令
    HTML5期末大作业——HTML+CSS+JavaScript平遥古城旅游景点介绍(6页)
    使用js搭建简易的WebRTC实现视频直播
    linux————ansible
    ButterKnife依赖注入框架源码解析
    什么是哈希表
    案例分享-https证书链不完整导致请求失败
    多线程进阶2 - 哈希表
    Java AbstractProcessor不生效问题
    神经网络在科研中的应用,神经网络理论与应用
  • 原文地址:https://blog.csdn.net/a2274001782/article/details/126026888