IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 2021-10-10 -> 正文阅读

[JavaScript知识库]2021-10-10

教你用v-model二次封装dialog

在项目中,弹框也是一个高度可复用的组件,特别是去基于element-ui来二次封装的dialog。原因大概有以下几点把:1.与UI给的样式不对 2.弹框的内容比较多但是该弹框用到的地方又多 3.便于维护,粘贴复制大家都会,但是,轮到产品经理或者UI调整的时候,就会傻眼了,怎么复制粘贴了这么多地方,改起来不得死啊。所以,如果在项目中多次用到又相似的弹框,我们也可以封装成一个全局组件,使得开发更好的进行下去。

接下来就是我们的二次封装的过程。

首先来看效果图,这里封装的是一个比较简单实用的弹框,首先文字这一块是随时变化的,所以是直接props传值过来的,然后中间的报送截止日期用的是一个插槽,默认是不需要这个报送日期的。
在这里插入图片描述

封装的代码部分:

<template>
  <div class="ConfirmPop">
    <el-dialog :visible="visible" top="25vh" @close="colseDialog" custom-class="confirm">
      <template v-slot:title>
        <div class="title">
          <i class="el-icon-warning-outline" /><span>请确认</span>
        </div>
      </template>
      <div class="modal-content-demo">
        <slot>
          <div class="date_box" v-if="showDate">
            <span class="trackReportEndTime">报送截止日期</span>
            <el-date-picker
              type="date"
              width="400px"
              placeholder="请选择"
              v-model="basicForm.trackReportEndTime"
              @change="dataChange"
              format="yyyy-MM-dd"
              value-format="yyyy-MM-dd"
            ></el-date-picker>
          </div>
          <div class="question">
            {{ confirmContent }}
          </div>
        </slot>
      </div>
      <template v-slot:footer>
        <div class="footer">
          <el-button @click="cancelSend">取消</el-button>
          <el-button type="primary" :loading="loading" @click="confirmSend"
            >确定</el-button
          >
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    show: {
      type: Boolean,
      default: false
    },
    loading: {
      type: Boolean,
      default: false
    },
    confirmContent: {
      type: String,
      default: '确认将报送该项目审计问题整改跟踪台账?'
    },
    dateTime: {
      type: String
    },
    showDate: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    visible: {
      get () {
        return this.show
      },
      set (val) {
        // 当visible改变的时候,触发父组件的 updateVisible方法,在该方法中更改传入子组件的 visible的值
        this.$emit('updateVisible', val)
      }
    }
  },
  data () {
    return {
      basicForm: {}
    }
  },
  methods: {
    dataChange (date, type) {
      // console.log(date);
      this.$emit('update:dateTime', date)
    },
    cancelSend () {
      // 如果外面传了cancelSend方法,那么说明父组件需要这个方法,那我们就传出去,不需要的话,就直接关闭dialog
      if(this.$listeners.cancelSend){
        this.$emit('cancelSend')
      }else{
        this.visible = false
      }
    },
    confirmSend () {
      this.$emit('confirmSend')
    },
    colseDialog () {
      this.visible = false
    }
  }
}
</script>

<style lang="less" scoped>
.ConfirmPop {
}
::v-deep .confirm {
  width: 530px;
  height: 330px;
  padding: 80px 60px;
  .el-dialog__header{
    .title{
      text-align: left;
      padding-left: 30px;
      font-size: 16px;
      font-weight: normal;
      i{
        color: #faad14 ;
      }
      span{
        margin-left: 6px;
        color: #606266;
      }
    }
  }
  .el-dialog__body{
    padding: 10px 30px 20px 20px;
    text-align: left;
    padding-left: 50px;
    .date_box{
      margin-bottom: 20px;
      span.trackReportEndTime{
        margin-right: 8px;
      }
    }
  }
}
</style>

我自己认为其中最精华的部分其实是computed这里,因为其实computed其实默认是只有getter属性的,但是其实我们也可以为其增加set属性来对这个值进行去设置,通过发送事件然后在父组件接收,改变传进来的值来控制dialog的关闭和打开。 另外的话,getter属性就绑定了父组件传进来的值,只要父组件的值改变子组件控制dialog的值就会跟着改变。从而实行了父组件通过一个值来控制dialog子组件关闭打开的效果。

其中还有一个小细节就是cancelSend方法的调用,让我们的父组件,如果不需要这个cancelSend方法,那么就不需要传入了,省的每次都在调用这个组件时需要写cancelSend方法(大部分情况下是不需要的)。

在代码中,我们可以知道这个传进来的show就是去控制里面element的dialog的显示和隐藏的,但是我们应该怎么去做呢,我之前自己写的时候,用的是watch,写的很复杂,大概就是这样子,虽然也能完成封装的这个效果,但是跟这个computed比起来,哈哈哈我的代码实在是太low了。所以,在复习的时候,我又重新封装了一次。

watch: {
    show (newVal) {
      if (newVal) {
        this.visible = true
      } else {
        this.visible = false
      }
    },
    visible (newVal) {
      if (!newVal) {
        if (this.show) {
          // this.show = false
          this.$emit('update:show', false)
        }
      }
    }
  },

下面的话,就是在页面中调用的代码,其实还是很简单的,主要就是返回了cancelSend取消的操作和confirmSend确认的操作。 但是的话,大家会不会要传的东西实在太多了,我看了一下,确实是的。怎么可以传这么多,明明还可以用v-model再去把这个精简一下,因为我们可以看到@updateVisible="updateVisible"这个函数根本就没做什么事。

<template>
  <div class="home">
    <!--  -->
    <el-button @click="openDialog">点我打开基本封装的弹出框</el-button>
    <ConfirmPop
      :show="confirmShow"
      confirmContent="还有尚未报送的问题台账,请确认是否继续报送?"
      :loading="loading"
      :dateTime.sync="dateTime"
      :showDate="true"
      @updateVisible="updateVisible"
      @cancelSend="cancelSend"
      @confirmSend="confirmSend"
    ></ConfirmPop>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  data () {
    return {
      confirmShow: false,
      loading: false,
      dateTime:''
    }
  },
  name: 'Home',
  components: {},
  methods: {
    openDialog () {
      this.confirmShow = true
    },
    cancelSend () {
      console.log('取消')
      this.confirmShow = false
    },
    confirmSend () {
      console.log('queren')
      this.loading = true
      setTimeout(()=>{
        this.loading = false
        this.confirmShow = false
      },1000)
      
    },
    updateVisible (val) {
      this.confirmShow = val
    }
  }
}
</script>


所以,该精简的还是得去精简一下啊。行吧,先介绍一个v-model。首先的话,v-model是:value和@input事件的语法糖。什么意思呢?就是你父组件在调用子组件的时候,如果你是这样子的,如下js。:value=“confirmShow” @input=“updateVisible” ,并且updateVisible只做了一件事(就是把接收的值赋给传下去:value的值)

<ConfirmPop
      :value="confirmShow"
      @input="updateVisible"
      confirmContent="还有尚未报送的问题台账,请确认是否继续报送?"
      :loading="loading"
      :dateTime.sync="dateTime"
      :showDate="true"
      @cancelSend="cancelSend"
      @confirmSend="confirmSend"
    ></ConfirmPop>
updateVisible(val){
    this.confirmShow = val
}

那么,你就可以精简成这样子,:value和@input都不需要了,改成v-model,另外把那个触发的事件也可以删掉

<ConfirmPop
      v-model="confirmShow"
      confirmContent="还有尚未报送的问题台账,请确认是否继续报送?"
      :loading="loading"
      :dateTime.sync="dateTime"
      :showDate="true"
      @cancelSend="cancelSend"
      @confirmSend="confirmSend"
    ></ConfirmPop>

综上,所以我们封装的代码不就也可以用v-model的方式来写嘛!!!!!!但是还是要稍微改一下地方的,因为我们一开始在子组件中接收的时候是用:show接收的,现在不行了,得使用:value,另外就是,computed中 触发的事件是叫updateVisible,这个不行了,得使用input事件。这两个是硬性要求的。当然,也可以使用model的配置来改事件名和属性名,但这里就不细说了。

上面上最终修改后的代码:

<template>
  <div class="ConfirmPop">
    <el-dialog :visible="visible" top="25vh" @close="colseDialog" custom-class="confirm">
      <template v-slot:title>
        <div class="title">
          <i class="el-icon-warning-outline" /><span>请确认</span>
        </div>
      </template>
      <div class="modal-content-demo">
        <slot>
          <div class="date_box" v-if="showDate">
            <span class="trackReportEndTime">报送截止日期</span>
            <el-date-picker
              type="date"
              width="400px"
              placeholder="请选择"
              v-model="basicForm.trackReportEndTime"
              @change="dataChange"
              format="yyyy-MM-dd"
              value-format="yyyy-MM-dd"
            ></el-date-picker>
          </div>
          <div class="question">
            {{ confirmContent }}
          </div>
        </slot>
      </div>
      <template v-slot:footer>
        <div class="footer">
          <el-button @click="cancelSend">取消</el-button>
          <el-button type="primary" :loading="loading" @click="confirmSend"
            >确定</el-button
          >
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    // 这里接收的这里改成了value
    value: {
      type: Boolean,
      default: false
    },
    loading: {
      type: Boolean,
      default: false
    },
    confirmContent: {
      type: String,
      default: '确认将报送该项目审计问题整改跟踪台账?'
    },
    dateTime: {
      type: String
    },
    showDate: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    visible: {
      get () {
        return this.value
      },
      set (val) {
        // 当visible改变的时候,触发父组件的 input方法,在该方法中更改传入子组件的值
        // 这里触发的事件改成了input
        this.$emit('input', val)
      }
    }
  },
  data () {
    return {
      basicForm: {}
    }
  },
  methods: {
    dataChange (date, type) {
      // console.log(date);
      this.$emit('update:dateTime', date)
    },
    cancelSend () {
      // 如果外面传了cancelSend方法,那么说明父组件需要这个方法,那我们就传出去,不需要的话,就直接关闭dialog
      if(this.$listeners.cancelSend){
        this.$emit('cancelSend')
      }else{
        this.visible = false
      }
    },
    confirmSend () {
      this.$emit('confirmSend')
    },
    colseDialog () {
      this.visible = false
    }
  }
}
</script>

<style lang="less" scoped>
.ConfirmPop {
}
::v-deep .confirm {
  width: 530px;
  height: 330px;
  padding: 80px 60px;
  .el-dialog__header{
    .title{
      text-align: left;
      padding-left: 30px;
      font-size: 16px;
      font-weight: normal;
      i{
        color: #faad14 ;
      }
      span{
        margin-left: 6px;
        color: #606266;
      }
    }
  }
  .el-dialog__body{
    padding: 10px 30px 20px 20px;
    text-align: left;
    padding-left: 50px;
    .date_box{
      margin-bottom: 20px;
      span.trackReportEndTime{
        margin-right: 8px;
      }
    }
  }
}
</style>

在页面中使用,大概就是简单多了:

<template>
  <div class="about">
    <!--  -->
    <el-button @click="openDialog">点我打开V-model封装的弹出框</el-button>
    <VmodelConfirmPop
      confirmContent="还有尚未报送的问题台账,请确认是否继续报送?"
      :loading="loading"
      v-model="confirmShow"
      @confirmSend="confirmSend"
    ></VmodelConfirmPop>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  data () {
    return {
      confirmShow: false,
      loading: false,
    }
  },
  name: 'Home',
  components: {},
  methods: {
    openDialog () {
      this.confirmShow = true
    },
    confirmSend () {
      console.log('queren')
      this.loading = true
      setTimeout(()=>{
        this.loading = false
        this.confirmShow = false
      },1000)
      
    }
  }
}
</script>

最后的话,把代码我也贴上,如果有需要封装的朋友可以去看一看,认为有不太好的地方也欢迎大家指出来哈哈哈,我一定会虚心接受学习的。

其中BaseConfirmPop是没用v-model的。

VmodelConfirmPop是使用了v-model之后的。

github地址:https://github.com/rui-rui-an/seconddialog

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-11 17:25:59  更:2021-10-11 17:26:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 20:54:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码