前端如何封装一个组件?怎么造轮子?手写js封装一个dialog弹窗组件。

此文转载自:https://blog.csdn.net/clli_Chain/article/details/112307521

一、现在要你完成一个Dialog组件,说说你设计的思路?它应该有什么功能?

以前没有尝试过封装组件,其实也没有严格意义的去笼统的学习过封装组件,最近使用layui满频繁的,想要封装一个dialog,尝试一下自己去动手封装一个组件,锻炼一下自己的动手能力,当然在这里也是分享给大家。

回到上方我们其实可以回想一下大体的功能,如果是一个弹窗的话,我们应该怎样去调用?应该怎么去使用呢?是使用js api来调用,还是说放置一个已经写好的html模板,让其设置display:none? js 手动将其显示?

其实上面的问题,我们可以参照一下layui和bootstrap

首先我们可以先看一下bootstrap的弹窗组件
在这里插入图片描述

在这里插入图片描述

我们其实可以明显的看出在bootstrap中其实也就是手动的将html标签语句放置在了body体内,而layui其实就是将对应的弹窗封装成了一个js文件,当调用时,去调用这个js文件的方法,然后采用插入节点的方式,将弹窗呈现。

那么我们应该去采用哪种方式来封装这个弹窗呢?在这里的话我们就将其手动的写入到js文件当中,让其使用js api的方式,让弹窗跳出,从而实现效果。

大体功能

  • 该组件需要提供hook指定渲染位置,默认渲染在body下面。
  • 然后改组件可以指定外层样式,如宽度等
  • 组件外层还需要一层mask来遮住底层内容,点击mask可以执行传进来的onCancel函数关闭Dialog。
  • 另外组件是可控的,需要外层传入visible表示是否可见。
  • 然后Dialog可能需要自定义头head和底部footer,默认有头部和底部,底部有一个确认按钮和取消按钮,确认按钮会执行外部传进来的onOk事件,然后取消按钮会执行外部传进来的onCancel事件。
  • 组件高度可能大于页面高度,组件内部需要滚动条。

我略微的删减掉了几个功能,因为我们采用的是像layui 式js的跳出方式,所以我们不需要 对应的变量去控制对应的展示还是隐藏,所以我们的dialog需要实现的就是上方的几个功能。

二、文档结构

在这里插入图片描述
我们大体需要3个文件,一个css、一个html、一个js文件

三、样式Css文件

/*index.css*/
*{
  margin:0;
  padding:0;
}
/* a标签去除下划线改变颜色 */
a{
  text-decoration: none;
  color: black;
}
/* 弹窗容器 */
.keyui-dialog-box{
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100000;
}
/* 遮罩层样式 */
.keyui-masking-layer{
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .3);
}
/* 弹窗默认样式 */
.keyui-dialog{
  width:50vw;
  height:50vh;
  background-color: white;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
}
/* 头部设置固定高度 */
.keyui-dialog-head{
  width: 100%;
  height: 40px;
  line-height: 40px;
  padding: 0 20px;
  box-sizing: border-box;
  background-color: #f8f8f8;
  border-bottom: 1px solid #eeeeee;
  position: relative;
}
/* 右上角关闭图标 */
.keyui-rightUp-close{
  position: absolute;
  right: 20px;
}
/* 弹窗内容区域 */
.keyui-dialog-content{
  height: calc(100% - 40px);
  padding: 20px;
  box-sizing: border-box;
  overflow-y: auto;  /* 为什么要设置auto,因为内容区域有时会超出弹窗大小 */
}
/* btn按钮样式 */
.keyui-btn {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #FFF;
  border: 1px solid #DCDFE6;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: 0;
  margin: 0;
  -webkit-transition: .1s;
  transition: .1s;
  font-weight: 500;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px; 
}
/* 鼠标移入按钮效果 */
.keyui-btn:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}
/* 确认按钮 */
.keyui-btn-primary {
  color: #FFF;
  background-color: #409EFF;
  border-color: #409EFF;
}
/* 确认按钮鼠标移入效果 */
.keyui-btn-primary:hover {
  background: #66b1ff;
  border-color: #fff;
  color: #fff;
}
/* 确认按钮mini样式 */
.keyui-btn-mini {
  font-size: 12px;
  border-radius: 3px;
  padding: 7px 15px;
}
/* 确认按钮small样式 */
.keyui-btn-small {
  padding: 9px 15px;
  font-size: 12px;
  border-radius: 3px;
}
/* 下框按钮区域居中,来一些边距样式 */
.dialog-bottom{
  padding:5px;
  background-color: #fff;
  text-align: center;
}

四、模拟调用场景index.html文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>弹窗组件封装</title>
    <!-- 引入css样式 -->
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <!-- 弹窗按钮,用于调用点击事件的弹窗 -->
    <button id="btn">弹窗组件</button>

    <!-- 指定content内容,在这里采用id,并默认将其设置为隐藏 -->
    <div id="content" style="display:none;">我是一个小天才</div>
  </body>
</html>
<!-- 引入jquery,因为我们js中的很多调用方法都是基于jquery的所以我们需要在index.js的上方就要引入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<!-- 引入我们的keyui组件库 -->
<script src="./index.js"></script>

<script>
  $('#btn').click(function () {
    // 配置参数  index对应我们返还的节点
    var index = keyui.dialog({
      title:'弹窗',// title左上角标题
      content: '#content',// content 指定对应内容指向哪一个标签
      btn: ['确认', '取消'],// 下bottom按钮
      area:['200px','200px'],// 弹窗宽高大小
      yes: function () { //点击确认按钮事件
        console.log(index) //对应上方的index变量,传递给close参数,用于关闭弹窗
        keyui.close(index) //关闭弹窗
      },
      no:function(){ //点击取消按钮事件
        keyui.close(index) //关闭弹窗
      }
    })
  })
</script>

五、dialog弹窗js组件


// 点击删除方法
function rightclose(box) {
  $('#'+box).remove()
}
// dom节点转换为字符串方法
function toInnerHTML(obj){
  // 创建一个节点
  const div = document.createElement("div")
  // 将节点插入进去
  div.appendChild(obj);
  // 将传递进来的dom设置为显示  因为是复制的上方节点嘛
  obj.style.display="block"
  // 获取当当前的dom节点字符串
  var a=div.innerHTML;
  // return出去
  return a;
}
var yes1= function(){
}
var no1 = function(){
}
var keyui = {
  // 弹窗方法  外部可直接使用keyui.dialog调用
  dialog: function (obj) {
    // 设置默认值等等
    var {title='弹窗',content='',btn=[],yes,no,area=['50%','50%']} = obj
    // 创建一个时间戳当层级id
    var date = new Date().getTime()
    // 判断是不是真的传递了yes或者no 如果传递了yes或者no才会让对应的方法赋予上方的全局方法,供与回调
    if(typeof yes === "function"){
      yes1 = yes
    }
    if(typeof no === "function"){
      no1 = no
    }
    // 判断当前有没有btn这个数组
    var dialog_bottom=''
    //有btn并且btn的长度不为0那么说明传递了按钮
    if(btn&&btn.length){
      // 拼接
      dialog_bottom+= `<div class="dialog-bottom">`
      // 循环传递进来的数组
    btn.forEach((element,index) => {
      // 我们在这里只考虑传递两个按钮第一个相当于确认,第二个相当于取消,同时挂载点击方法,也就对应了我们上方的yes1,no1
      dialog_bottom +=  `<div class="keyui-btn keyui-btn-mini ${index==0?'keyui-btn-primary':''}" οnclick="${index==0?'yes1()':'no1()'}">${element}</div>`
     });
     dialog_bottom+= `</div>`
    }
    // 拼接一个dom节点,其实原理上我们还是使用的插入节点的方式。
    var box = $(`<div id="keyui-${date}" class="keyui-dialog-box">
                <div class="keyui-masking-layer">
                  <div class="keyui-dialog" style="${area[0]};height:${area[1]}">
                    <div class="keyui-dialog-head">
                    <span>${title}</span>
                      <a href="javascript:;" class="keyui-rightUp-close" οnclick="rightclose('keyui-${date}')">X</a>
                    </div>
                    <div class="keyui-dialog-content">
                      ${content?toInnerHTML($(content).clone(true)[0]):''}
                    </div>
                      ${dialog_bottom}
                  </div>
                </div>
              </div>`)
    // 分别说一下上方对应变量的意思
    /**
     * @param date 时间戳,主要是为了弹窗之中在弹弹窗,用于区分当前究竟是哪一个弹窗
     * @param area[] 0:宽度,1高度
     * @param title 标题
     * @param toInnerHTML($(content).clone(true)[0]) 完全克隆一个dom节点并作为参数传递给toInnerHTML用于拿到dom字符串
     * @param dialog_bottom bottom内容,如果传递的按钮是空的,那么就不会渲染,如果不是就会渲染
     */

    //  将数据插入到对应的body页面中  当然层级我们肯定要设置很高,防止被其他内容盖住
    $('body').append(box)

    // 返回我们拼接的id值  用于关闭这个弹窗
    return $('#keyui-'+date)[0]
  },
  // 关闭弹窗方法,index其实对应的是一个dom节点也就是上方弹窗返还的节点
  close: function (index) {
    //  取当前节点  直接清除
    index.remove();
  }
}

最终效果

在这里插入图片描述

   

更多内容详见微信公众号:Python测试和开发

Python测试和开发

原文地址:https://www.cnblogs.com/phyger/p/14251982.html