您现在的位置是:首页 >技术教程 >Vue+Vant封装通用模态框单选框组件网站首页技术教程

Vue+Vant封装通用模态框单选框组件

学学学无止境 2023-06-04 16:00:04
简介Vue+Vant封装通用模态框单选框组件

前言

我们知道,在vant组件中提供的组件往往是比较基础的,能够满足基本需求。但是我们想实现ui设计的一些比较丰富效果的组件,需要自己去实现,且当项目中多次用到的时候,我们将以组件化的思想将其封装起来,供各个页面方面使用。

vant提供的单选框效果:

 项目中UI提供的单选框效果图

1.右边显示单选框效果

2.右边显示为图标效果

 情况

 实现思路

在组建中定义如下变量,用来接收父组件传的值

定义props值

  • title:标题
  • showList:展示列表的数据
  • actionVal:当前列表数据中被选中的值
  • dialogType:弹框的类型(0-列表 文字 图标;1-列表 文字 radio;2-自动以内容)
  • onlyCancel:是否只显示取消按钮,true只显示取消按钮,false:既显示取消按钮,又显示确定按钮。因为有些是需要点击单选框某项之后直接关闭模态框触发回传事件,有些是需要点击确定按钮再触发,所以这里做了一个区分

定义点击事件

1.列表项点击事件:listClick(i)

listClick(i){
 // 这个key值也是根据父组件传递过来的列表,key值是每项的唯一标识值,这个唯一标示值根据自身业务逻辑而定
 this.currActionVal=i.key//存储当前最新值
 this.$emit('update',this.currentActionVal);//这里可以稍微优化,若存在确定按钮,这一步在确定事件中再进行
 setTimeout(()=>{
   this.show=false
 },500)
}

 2.点击确定按钮事件:handleConfirm

handleConfirm(){
    this.$emit('update',this.currentActionVal)
}

 3.点击取消事件:handleCancel

handleCancel(){
  this.$emit('cancel',this.currentActionVal,this.actionVal);//回传旧值和新值,若用户没有触发修改事件时,这里currentActionVal和this.actionVal相等
}

 父组件调用

引入与注册

使用

右边显示为图标效果

     // html
     <bottomDialog
        ref="actionDialog"
        :title="$t('hvac.actionModel')"
        :onlyCancel="true"
        :showList="actionIcon"
        :actionVal="action"
        :dialogType="0"
        @update="actionUpdate($event)"
        @cancel="actionCancel(arguments)"
      ></bottomDialog>

 

右边显示为radio效果

 

最后,附上封装的组件的代码

<template>
  <div>
    <van-dialog
      v-model="show"
      :title="currTitle"
      :confirmButtonText="$t('common.ensure')"
      confirmButtonColor="#FEB946"
      :cancelButtonText="$t('common.cancel')"
      cancelButtonColor="#666666"
      :showCancelButton="true"
      :showConfirmButton="showConfirmFlag"
      @confirm="handleConfirm"
      @cancel="handleCancel"
    >
      <!-- 列表 文字-图标 -->
      <div class="list-container" v-if="Number(dialogType) === 0">
        <div
          class="list-box"
          v-for="(i, k) in showList"
          :key="k"
          @click="listClick(i)"
        >
          <div
            class="item-right no-action-font"
            :class="{ 'smartOrange-color': i.key === currActionVal }"
          >
            {{ i.title }}
          </div>

          <div class="item-left" :class="i.class"></div>
        </div>
      </div>

      <!-- 列表radio 文字-radio -->
      <div class="list-container" v-if="Number(dialogType) === 1">
        <van-radio-group v-model="currActionVal">
          <div class="list-box" v-for="(i, k) in showList" :key="k">
            <div
              class="item-right no-action-font"
              :class="{ 'smartOrange-color': i.key === currActionVal }"
            >
              {{ i.title }}
            </div>

            <div class="item-left">
              <van-radio :name="i.key">
                <template #icon="props">
                  <div
                    class="item-left"
                    :class="
                      props.checked ? 'radio-icon-orange' : 'radio-icon-grey'
                    "
                  ></div>
                </template>
              </van-radio>
            </div>
          </div>
        </van-radio-group>
      </div>

      <!-- 自定义内容 -->
      <div class="list-container" v-if="Number(dialogType) === 2">
        <slot name="default"></slot>
      </div>
    </van-dialog>
  </div>
</template>

<script>
import { Dialog, RadioGroup, Radio } from "vant";
export default {
  name: "bottomDialog",
  components: {
    Dialog,
    RadioGroup,
    Radio,
  },
  props: {
    //   标题
    title: {
      type: String,
      default: "123",
    },
    //  是否只显示取消按钮  -true 只有取消按钮 -false 有取消、确定按钮
    onlyCancel: {
      type: Boolean,
      default: false,
    },
    // 展示列表数据
    showList: {
      type: Array,
      default() {
        return [];
      },
      required: false,
    },
    // 当前列表数据中被选中的值
    actionVal: {
      type: Number,
      default: 0,
      required: false,
    },
    // 弹窗的类型
    // 0-列表 文字-图标
    // 1-列表radio  文字-radio
    // 2-自定义内容
    dialogType: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      show: false,
      currTitle: this.title,
      showConfirmFlag: !this.onlyCancel,
      currActionVal: this.actionVal,
    };
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {},
  methods: {
    //   点击确定按钮事件
    handleConfirm() {
      console.log(this.currActionVal);
      this.$emit("update", this.currActionVal);
    },

    // 点击取消按钮事件
    handleCancel() {
      console.log("newVal:" + this.currActionVal);
      console.log("oldVal:" + this.actionVal);
      this.$emit("cancel", this.currActionVal, this.actionVal);
    },

    // 列表-图标点击事件
    listClick(i) {
      this.currActionVal = i.key;
      this.$emit("update", this.currActionVal);
      setTimeout(() => {
        this.show = false;
      }, 500);
    },
  },
};
</script>

<style lang="scss" scoped>
.list-container {
  padding: 20px 40px;

  .list-box {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    .item-left {
      width: 30px;
      height: 30px;
    }
  }
}
// 重写vant弹窗初始样式
.van-dialog {
  position: fixed !important;
  top: auto !important;
  left: 50% !important;
  bottom: 60px !important;
  transform: translateX(-50%) !important;
}
.van-dialog__header {
  font-size: 18px !important;
  color: #feb946 !important;
  font-weight: 600 !important;
}
::v-deep .van-radio__icon{
  height: 100%;
}
.van-radio{
  height: 100%;
}
.van-radio__icon {
  height: 30px !important;
}
</style>

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。