ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模仿element-ui封装vue组件库(dialog)

2022-05-25 11:34:49  阅读:289  来源: 互联网

标签:vue fade 插槽 element ui ra dialog 组件 20px


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

前置知识:

vue过渡动画
sync修饰符
具名插槽与v-slot指令
参数支持:

参数名

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

 

事件支持:

事件名 


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


插槽说明:

插槽名称 

插槽描述
default  dialog的内容
title dialog的标题
footer dialog的底部操作区

 

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

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

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

<template>
<div class="ra-dialog_wrapper">
<div class="ra-dialog">
<div class="ra-dialog_header">
<span class="ra-dialog_title">提示</span>
<button class="ra-dialog_headerbtn">
<i class="ra-icon-close"></i>
</button>
</div>
<div class="ra-dialog_body">
<span>这是一段信息</span>
</div>
<div class="ra-dialog_footer">
<ra-button>取消</ra-button>
<ra-button type="primary">确定</ra-button>
</div>
</div>
</div>
</template>

样式如下:

<style lang="scss" scoped>
.ra-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);
.ra-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;
.ra-dialog_title{
line-height: 24px;
font-size: 18px;
color: #303133;
}
.ra-dialog_headerbtn{
position: absolute;
top: 20px;
right: 20px;
padding: 0;
background: transparent;
border: none;
outline: none;
cursor: pointer;
font-size: 16px;
.ra-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 .ra-button:first-child{
margin-right: 20px;
}
}
}
}
</style>

在main.js注册后,在app.vue中引用。即可展示。

4.2自定义title内容

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

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

<template>
<div class="ra-dialog_wrapper">
<div class="ra-dialog">
<div class="ra-dialog_header">
<slot name="title">
<!-- 将span放到slot内,这样不仅可以定义title文本,还可以定义样式等 -->
<span class="ra-dialog_title">
{{title}}
</span>
</slot>
<button class="ra-dialog_headerbtn">
<i class="ra-icon-close"></i>
</button>
</div>
<div class="ra-dialog_body">
<span>这是一段信息</span>
</div>
<div class="ra-dialog_footer">
<ra-button>取消</ra-button>
<ra-button type="primary">确定</ra-button>
</div>
</div>
</div>
</template>

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

<ra-dialog title="温馨提示">
<!-- 使用v-slot指定插槽进行编辑 -->
<template v-slot:title>
<h3 style="color:red">我是标题</h3>
</template>
</ra-dialog>

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

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

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

父组件传值:

<ra-dialog width="80%" top="200px"></ra-dialog>

子组件使用:

<template>
<div class="ra-dialog_wrapper">
<div class="ra-dialog" :style="{width:width,marginTop:top}">
···
</div>
</div>
</template>

4.4自定义body内容

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

4.4.1在body中使用匿名组件

<div class="ra-dialog_body">
<slot></slot>
</div>

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

<ra-dialog>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</ra-dialog>

4.5自定义footer内容

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

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

<div class="ra-dialog_footer">
<!-- 如果footer不传递内容,则不显示footer -->
<slot name="footer" v-if="$slots.footer"></slot>
</div>

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

<template v-slot:footer>
<ra-button>取消</ra-button>
<ra-button type="primary">确定</ra-button>
</template>

4.6dialog的显示与隐藏

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

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

//父组件传值
<demo :visible="visible" :money="money" @update:aa="fn1"></demo>
//子组件回调
methods: {
fn () {
this.$emit('aa', 200)
}
}

使用sync语法糖后,父组件不需要单独声明一个方法,只需要在回调时声明一个update绑定的回调函数(这个绑定值是传值自身)这样在父组件中就不需要再次定义回调函数进行接收了。

//父组件中的使用sync语法糖,传递和接收参数

<demo :visible.sync="visible" :money.sync="money"></demo>
//子组件中使用update绑定参数的方法进行回调
methods: {
fn () {
this.$emit('update:money', 200)
this.$emit('update:visible', true)
}
}

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

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

<div class="ra-dialog_wrapper" v-show="visible" @click.self="handleClose">
···
</div>

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

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

<ra-dialog :visible.sync="visible">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<template v-slot:footer>
<ra-button @click="switchDialog">取消</ra-button>
<ra-button type="primary">确定</ra-button>
</template>
</ra-dialog>

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

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

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

<div class="row">
<ra-dialog :visible.sync="visible">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<template v-slot:footer>
<ra-button @click="switchDialog">取消</ra-button>
<ra-button type="primary">确定</ra-button>
</template>
</ra-dialog>

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

<template v-slot:footer>
<ra-button>取消</one-button>
<ra-button type="primary">确定</ra-button>
</template>
回调方法:

method{
handleClose () {
this.$emit('update:visible', false)
}
}

4.7dialog的动画效果

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

4.7.1使用transition包裹整个dialog框架

<template>
<transition name="dialog-fade">
<div class="ra-dialog_wrapper" v-show="visible" @click.self="handleClose">
···
</div>
</transition>
</template>

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);
}
}

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

附组件代码:

<template>
<transition name="dialog-fade">
 <div class="ra-dialog_wrapper" v-show="visible" @click.self="handlerClose">
   <div class="ra-dialog" :style="{width:width,marginTop:top}">
     <div class="ra-dialog_header">
       <slot name="title">
         <!-- 将span放到slot内,这样不仅可以定义title文本,还可以定义样式等 -->
        <span class="ra-dialog_title">
          {{title}}
        </span>
       </slot>
       <button class="ra-dialog_headerbtn" @click="handlerClose">
         <i class="ra-icon-close"></i>
       </button>
     </div>
     <div class="ra-dialog_body">
       <slot></slot>
     </div>
     <div class="ra-dialog_footer">
       <!-- 如果footer不传递内容,则不显示footer -->
       <slot name="footer" v-if="$slots.footer"></slot>
     </div>
   </div>
 </div>
</transition>
</template>

<script>

export default {
  name: 'ra-dialog',
  props: {
    title: {
      type: String,
      default: '提示'
    },
    width: {
      type: String,
      default: '50%'
    },
    top: {
      type: String,
      default: '50%'
    },
    visible: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    handlerClose () {
      this.$emit('update:visible', false)
    }
  }
}
</script>
<style lang="scss" scoped>
// scope会给当前组件模板中的所有元素都添加一个随机的属性
// scope会给当前组件中所有的样式页都添加一个对应的属性选择器
.ra-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);
  .ra-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;
      .ra-dialog_title{
        line-height: 24px;
        font-size: 18px;
        color: #303133;
      }
      .ra-dialog_headerbtn{
        position: absolute;
        top: 20px;
        right: 20px;
        padding: 0;
        background: transparent;
        border: none;
        outline: none;
        cursor: pointer;
        font-size: 16px;
        .ra-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 .ra-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>

 

标签:vue,fade,插槽,element,ui,ra,dialog,组件,20px
来源: https://www.cnblogs.com/Rainbow5421/p/16308660.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有