前端工作室专注前端开发
 博客首页

下拉选择和多选弹窗组件简单封装

2025-03-18 14:40:24
JS基础与深入
7
文章图片

本篇介绍下拉选择和多选弹窗组件简单封装

下拉选择和多选弹窗组件简单封装

本篇介绍下拉选择和多选弹窗组件简单封装 Alt text

父组件

<template>
  <div>
    下拉组件和多选弹窗简单封装
    <div>数据:{{ form }}</div>
    <lee-form :form="form" :formList="formList" @update:form="updateForm">
      <template v-slot:slotTwo>
        <inputSingleSelectTable
          :label="'name'"
          prop="id"
          :formList="formListTwo"
          url="xxxx"
          :columns="[
            { prop: 'id', label: 'id', width: 100 },
            { prop: 'name', label: '姓名', width: 100 },
            { prop: 'age', label: '年龄', width: 100 }
          ]"
          @select="
            (val) => {
              console.log(val)
              form.slotTwo = { label: val.name, value: val.id }
            }
          "
        />
      </template>
      <template v-slot:slotThree>
        <inputMultipleSelectTable
          :label="'name'"
          prop="id"
          url="xxxx"
          :formList="formListThree"
          :columns="[
            { prop: '', label: '', type: 'selection', width: 200 },
            { prop: 'id', label: 'id', width: 200 },
            { prop: 'name', label: '姓名', width: 200 },
            { prop: 'age', label: '年龄', width: 200 }
          ]"
          @select="
            (val) => {
              console.log(val)
              form.slotThree = val
            }
          "
        />
      </template>
    </lee-form>
  </div>
</template>
<script setup lang="ts">
import { reactive, computed } from 'vue'
import { type FormList, FormInter } from '@/types/types'
import LeeForm from '@/components/form/leeForm.vue'
import inputSingleSelectTable from '@/components/form/inputSingleSelectTable.vue'
import inputMultipleSelectTable from '@/components/form/inputMultipleSelectTable.vue'
const formList = computed<FormList[]>(() => [
  {
    renderType: 'slot',
    label: '单选悬浮窗',
    prop: 'slotTwo',
    span: 12,
    slotName: 'slotTwo',
    rules: [{ required: true, message: '请选择', trigger: 'blur' }]
  },
  {
    renderType: 'slot',
    label: '多选弹窗',
    prop: 'slotThree',
    span: 12,
    slotName: 'slotThree',
    rules: [{ required: true, message: '请选择', trigger: 'blur' }]
  }
])
const formListTwo = computed<FormList[]>(() => [
  {
    renderType: 'ElInput',
    label: '姓名',
    prop: 'name',
    span: 12
  },
  {
    renderType: 'ElInputNumber',
    label: '年龄',
    prop: 'age',
    span: 12
  }
])
const formListThree = computed<FormList[]>(() => [
  {
    renderType: 'ElInput',
    label: '姓名',
    prop: 'name',
    span: 12
  },
  {
    renderType: 'ElInputNumber',
    label: '年龄',
    prop: 'age',
    span: 12
  }
])
const form = reactive<FormInter>({
  name: '',
  elCascader: []
})
/**
 * 更新表单数据
 * @param {Record<string, any>} val - 需要更新的表单数据对象
 * @description 通过 Object.assign 方法将传入的数据对象合并到现有表单对象中
 */
const updateForm = (val: Record<string, any>) => {
  console.log(val)
  Object.assign(form, val)
}
</script>
<style scoped></style>


下拉子组件

Alt text

<!-- input框选择组件 -->
<template>
  <div class="input-select-table">
    <el-popover placement="bottom" :width="400" trigger="click">
      <template #reference>
        <el-input v-model="selectedValue" readonly placeholder="请选择" @click="showTable = true" />
      </template>
      <lee-form :form="form" :formList="formList" labelWidth="auto" @update:form="updateForm"
      :buttonList="[{ btnType: 'primary', text: '查询'}]"></lee-form>
      <LeeTable
        :table-data="tableData"
        :table-columns="columns"
        :show-pagination="true"
        :total="total"
        :current-page="currentPage"
        rowKey="prop"
        @page-change="handlePageChange"
        @row-click="handleRowClick"
      />
    </el-popover>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import LeeTable from '@/components/table/leeTable.vue'
const props = defineProps({
  url: {
    type: String,
    default: ''
  },
  columns: {
    type: Array,
    default: () => []
  },
  label: {
    type: String,
    default: ''
  },
  prop: {
    type: String,
    default: ''
  },
  formList: {
    type: Array,
    default: () => []
  }
})
interface TableRow {
  [key: string]: any
}
const emit = defineEmits(['update:modelValue', 'pageChange', 'select'])
const showTable = ref(false)
const selectedValue = ref('')
const tableData = ref<TableRow[]>([])
let total = ref(0)
let currentPage = ref(1)
const form = ref({})
const handlePageChange = (page: number) => {
  emit('pageChange', page)
  currentPage.value = page
  getData(page)
}
const handleRowClick = (row: any) => {
  console.log('handleRowClick', row)
  selectedValue.value = row[props.label]
  showTable.value = false
  emit('select', row)
}
const getData = (page: number = 1) => {
  console.log(page, form.value)
  if (props.url) {
    // 获取数据
    setTimeout(() => {
      tableData.value = [
        {
          id: currentPage.value *10 + 1,
          name: '张三',
          age: 20
        },
        {
          id: currentPage.value *10 + 2,
          name: '李四',
          age: 20
        },
        {
          id: currentPage.value *10 + 3,
          name: '王五',
          age: 20
        },
        {
          id: currentPage.value *10 + 4,
          name: '赵六',
          age: 20
        }
      ]
      total.value = 100
    })
  }
}
const updateForm = (val: Record<string, any>) => {
  console.log(val)
  Object.assign(form, val)
}
onMounted(() => {
  if (props.url) {
    getData()
  }
})
</script>
<style scoped>
.input-select-table {
  position: relative;
}
</style>

弹窗多选子组件

Alt text

<template>
  <div class="input-multiple-select-table">
    <el-input v-model="selectedLabels" readonly placeholder="请选择" @click="showTable = true" />
    <el-dialog v-model="showTable" width="80%" title="选择表格数据">
      <lee-form :form="form" :formList="formList" @update:form="updateForm" :buttonList="[{ btnType: 'primary', text: '查询'}]"></lee-form>
      <LeeTable
        ref="tableRef"
        :table-data="tableData"
        :table-columns="columns"
        :show-pagination="true"
        :total="total"
        :rowKey="prop"
        :currentPage="currentPage"
        @page-change="handlePageChange"
        @selection-change="handleSelectionChange"
        @deselected-rows="handelDeselectedRows"
      />
      <!-- 显示已选内容 -->
      <div class="selected-tags" style="height: 200px;border: 1px solid #ccc">
        <el-tag
          v-for="(item, index) in selectedValues"
          :key="index"
          closable
          @close="removeTag(index)"
        >
          {{ item[props.label] }}
        </el-tag>
      </div>
      <template #footer>
        <div>
          <el-button @click="showTable = false">取消</el-button>
          <el-button type="primary" @click="showTable = false">确定</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 显示已选内容 -->
    <div class="selected-tags">
      <el-tag
        v-for="(item, index) in selectedValues"
        :key="index"
        closable
        @close="removeTag(index)"
      >
        {{ item[props.label] }}
      </el-tag>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import LeeTable from '@/components/table/leeTable.vue'
const props = defineProps({
  url: {
    type: String,
    default: ''
  },
  columns: {
    type: Array,
    default: () => []
  },
  label: {
    type: String,
    default: ''
  },
  prop: {
    type: String,
    default: ''
  },
  formList: {
    type: Array,
    default: () => []
  }
})
interface TableRow {
  [key: string]: any
}
const emit = defineEmits(['update:modelValue', 'pageChange', 'select'])
const showTable = ref(false)
const selectedLabels = ref('')
const selectedValues = ref<TableRow[]>([])
const tableData = ref<TableRow[]>([])
const total = ref(0)
const tableRef = ref()
let currentPage = ref(1)
const form = ref({})
const handlePageChange = (page: number) => {
  emit('pageChange', page)
  currentPage.value = page
  getData(page)
}
const handleSelectionChange = (rows: TableRow[]) => {
  rows.forEach((row) => {
    const index = selectedValues.value.findIndex((item) => item[props.prop] === row[props.prop])
    if (index === -1) {
      selectedValues.value.push(row)
    }
  })
  selectedLabels.value = rows.map((row) => row[props.label]).join(', ')
  emit('select', rows)
}
const handelDeselectedRows = (rows: TableRow[]) => {
  rows.forEach((row) => {
    const index = selectedValues.value.findIndex((item) => item[props.prop] === row[props.prop])
    if (index !== -1) {
      selectedValues.value.splice(index, 1)
    }
  })
  selectedLabels.value = rows.map((row) => row[props.label]).join(', ')
}
const removeTag = (index: number) => {
  const [row] = selectedValues.value.splice(index, 1)
  selectedLabels.value = selectedValues.value.map((row) => row[props.label]).join(', ')
  tableRef.value.cancelRowSelection(row)
}
const getData = (page: number) => {
  console.log(page)
  // 获取数据
  setTimeout(() => {
    tableData.value = [
      { id: currentPage.value * 10 + 1, name: currentPage.value + '张三', age: 20 },
      { id: currentPage.value * 10 + 2, name: currentPage.value + '李四', age: 20 },
      { id: currentPage.value * 10 + 3, name: currentPage.value + '王五', age: 20 },
    ]
    total.value = 100
    if(tableRef.value){
      tableRef.value.setRowsSelection(selectedValues.value)
    }
  },1000)
}
const updateForm = (val: Record<string, any>) => {
  console.log(val)
  Object.assign(form, val)
}
onMounted(() => {
  if (props.url) {
    // 获取数据
    getData(1)
  }
})
</script>
<style scoped>
.input-multiple-select-table {
  position: relative;
}
.selected-tags {
  margin-top: 8px;
}
.selected-tags .el-tag {
  margin-right: 8px;
  margin-bottom: 8px;
}
</style>

form表单和表格组件也做了相应调整,具体查看githua代码

小恐龙

专注于WEB和移动前端开发

5年以上经验业余讲师被访问基金爱好者
社交帐号