当前位置:   article > 正文

vue3+Element-plus el-select 下拉表格组件( TSelectTable组件动态赋值默认值回显问题解决及单选默认值修改及新增isClearQuery属性清除查询条件数据)_vue3 el-select

vue3 el-select

注意:使用此组件必须:Element-plus版本2.6以上;@wocwin/t-ui-plus最新版本。

2024-04-19 TSelectTable组件动态赋值默认值回显问题解决及单选默认值修改;及新增isClearQuery属性关闭下拉框自动清除查询条件的数据

在这里插入图片描述
在这里插入图片描述

一、最终效果

在这里插入图片描述

二、代码示例

<t-select-table
  :table="table"
  :columns="table.columns"
  :max-height="400"
  :keywords="{ label: 'name', value: 'id' }"
  @radioChange="radioChange"
></t-select-table>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、参数配置

1. 配置参数(Attributes)继承 el-table 及 el-select 属性

参数说明类型默认值
v-model绑定值boolean / string / number仅显示
table表格数据对象Object{}
—data展示下拉数据源Array[]
—total数据总条数Number-
—pageSize每页显示条目个数Number-
—currentPage当前页数Number-
columns表头信息Array[]
----bindel-table-column AttributesObject-
----noShowTip是否换行 (设置:noShowTip:true)Booleanfalse
----fixed列是否固定( left, right)string, boolean-
----align对齐方式(left/center/right)Stringcenter
----render返回三个参数(text:当前值,row:当前整条数据 ,index:当前行)function-
----slotName插槽显示此列数据(其值是具名作用域插槽)String-
------scope具名插槽获取此行数据必须用解构接收{scope}Object当前行数据
keywords关键字配置(value-key 配置)Object
------label选项的标签String‘label’
------value选项的值String / number‘value’
radioTxt单选文案String单选
multiple是否开启多选Booleanfalse
rowClickRadio是否开启整行选中(单选)booleantrue
isShowFirstColumn是否显示首列(单选)booleantrue
defaultSelectVal设置第一页默认选中项–keywords.value 值)Array-
filterable是否开启过滤(根据 keywords 的 label 值进行过滤)Booleantrue
reserveSelection是否支持翻页选中Booleantrue
isShowPagination开启分页Booleanfalse
tableWidthtable 宽度Number550
isKeyup单选是否开启键盘事件Booleanfalse
isShowQuery是否允许配置查询条件(继承TQueryCondition的所有属性、事件、插槽)Booleanfalse
isShowBlurBtn条件查询组件是否显示隐藏下拉框按钮Booleanfalse
btnBind显示下拉框按钮配置,继承el-button所有属性;默认值{type:'danger',btnTxt:'关闭下拉框'}Object-
isClearQuery关闭下拉框是否清空搜索条件Booleanfalse

2. 事件(events)继承 el-table 及 el-select 属性

事件名说明回调参数
page-change页码改变事件返回选中的页码
selectionChange多选事件返回选中的项数据及选中项的 keywords.value 集合
radioChange单选返回当前项所有数据

3.方法(Methods)继承 el-table 及 el-select 属性

方法名说明回调参数
clear清空选中项
focus使 input 获取焦点
blur使 input 失去焦点,并隐藏下拉框

四、具体代码

<template>
  <el-select
    ref="selectRef"
    :model-value="multiple ? state.defaultValue : selectDefaultLabel"
    popper-class="t-select-table"
    :style="{ width: selectWidth ? `${selectWidth}px` : '100%' }"
    :multiple="multiple"
    v-bind="selectAttr"
    :value-key="keywords.value"
    :filterable="filterable"
    :filter-method="filterMethod || filterMethodHandle"
    v-click-outside="closeBox"
    @visible-change="visibleChange"
    @remove-tag="removeTag"
    @clear="clear"
    @keyup="selectKeyup"
  >
    <template #empty>
      <div
        class="t-table-select__table"
        :style="{ width: tableWidth ? `${tableWidth}px` : '100%' }"
      >
        <div class="table_query_condition" v-if="isShowQuery">
          <t-query-condition
            ref="tQueryConditionRef"
            :boolEnter="false"
            @handleEvent="handleEvent"
            v-bind="$attrs"
          >
            <template v-for="(index, name) in slots" v-slot:[name]="data">
              <slot :name="name" v-bind="data"></slot>
            </template>
            <template #querybar v-if="isShowBlurBtn">
              <el-button
                v-bind="{ type: 'danger', ...btnBind }"
                @click="blur"
                >{{ btnBind.btnTxt || '关闭下拉框' }}</el-button
              >
              <slot name="querybar"></slot>
            </template>
          </t-query-condition>
        </div>
        <el-table
          ref="selectTable"
          :data="state.tableData"
          :class="{
            radioStyle: !multiple,
            highlightCurrentRow: isRadio,
            keyUpStyle: isKeyup,
          }"
          highlight-current-row
          border
          :row-key="getRowKey"
          @row-click="rowClick"
          @cell-dblclick="cellDblclick"
          @selection-change="handlesSelectionChange"
          v-bind="$attrs"
        >
          <el-table-column
            v-if="multiple"
            type="selection"
            width="55"
            align="center"
            :reserve-selection="reserveSelection"
            fixed
          ></el-table-column>
          <el-table-column
            type="radio"
            width="55"
            :label="radioTxt"
            fixed
            align="center"
            v-if="!multiple && isShowFirstColumn"
          >
            <template #default="scope">
              <el-radio
                v-model="radioVal"
                :label="scope.$index + 1"
                @click.stop="
                  radioChangeHandle($event, scope.row, scope.$index + 1)
                "
              ></el-radio>
            </template>
          </el-table-column>
          <el-table-column
            v-for="(item, index) in columns"
            :key="index + 'i'"
            :type="item.type"
            :label="item.label"
            :prop="item.prop"
            :min-width="item['min-width'] || item.minWidth"
            :width="item.width"
            :align="item.align || 'center'"
            :fixed="item.fixed"
            :show-overflow-tooltip="item.noShowTip"
            v-bind="{ ...item.bind, ...$attrs }"
          >
            <template #default="scope">
              <!-- render方式 -->
              <template v-if="item.render">
                <render-col
                  :column="item"
                  :row="scope.row"
                  :render="item.render"
                  :index="scope.$index"
                />
              </template>
              <!-- 作用域插槽 -->
              <template v-if="item.slotName">
                <slot :name="item.slotName" :scope="scope"></slot>
              </template>
              <div v-if="!item.render && !item.slotName">
                <span>{{ scope.row[item.prop] }}</span>
              </div>
            </template>
          </el-table-column>
          <slot></slot>
        </el-table>
        <div class="t-table-select__page" v-if="isShowPagination">
          <el-pagination
            v-model:current-page="table.currentPage"
            v-model:page-size="table.pageSize"
            small
            background
            @current-change="handlesCurrentChange"
            layout="total, prev, pager, next, jumper"
            :pager-count="5"
            :total="table.total"
            v-bind="$attrs"
          />
        </div>
      </div>
    </template>
  </el-select>
</template>

<script setup lang="ts" name="TSelectTable">
import TQueryCondition from '../../query-condition/src/index.vue'
import RenderCol from './renderCol.vue'
import {
  computed,
  useAttrs,
  useSlots,
  ref,
  watch,
  nextTick,
  reactive,
  onMounted,
} from 'vue'
import { ElMessage } from 'element-plus'
import ClickOutside from '../../utils/directives/click-outside/index'
const props = defineProps({
  modelValue: {
    type: [Array, String, Number, Boolean, Object],
    default: undefined,
  },
  // 选择值
  value: {
    type: [String, Number, Array],
  },
  // table所需数据
  table: {
    type: Object,
    default: () => {
      return {}
    },
  },
  // 表头数据
  columns: {
    type: Array as unknown as any[],
    default: () => [],
  },
  // 单选文案
  radioTxt: {
    type: String,
    default: '单选',
  },
  // 是否显示搜索条件
  isShowQuery: {
    type: Boolean,
    default: false,
  },
  // 是否清空搜索条件
  isClearQuery: {
    type: Boolean,
    default: false,
  },
  // 是否显示隐藏下拉框按钮
  isShowBlurBtn: {
    type: Boolean,
    default: false,
  },
  // 显示隐藏下拉框按钮属性
  btnBind: {
    type: Object,
    default: () => {
      return {
        btnTxt: '关闭下拉框',
      }
    },
  },
  // 单选框--是否开启点击整行选中
  rowClickRadio: {
    type: Boolean,
    default: true,
  },
  // 是否显示首列
  isShowFirstColumn: {
    type: Boolean,
    default: true,
  },
  // 是否过滤
  filterable: {
    type: Boolean,
    default: true,
  },
  // 是否支持翻页选中
  reserveSelection: {
    type: Boolean,
    default: true,
  },
  // 是否显示分页
  isShowPagination: {
    type: Boolean,
    default: false,
  },
  // 是否自定义过滤
  filterMethod: {
    type: Function,
  },
  // 下拉数据指向的label/value
  keywords: {
    type: Object,
    default: () => {
      return {
        label: 'label',
        value: 'value',
      }
    },
  },
  // 单选是否开启键盘事件
  isKeyup: {
    type: Boolean,
    default: false,
  },
  // 多选
  multiple: {
    type: Boolean,
    default: false,
  },
  // select 宽度
  selectWidth: {
    type: [String, Number],
    default: 550,
  },
  // table宽度
  tableWidth: {
    type: [String, Number],
    default: 550,
  },
  // 设置默认选中项--keywords.value值(单选是String, Number类型;多选时是数组)
  defaultSelectVal: {
    type: Array,
    default: () => [],
  },
})
const selectAttr = computed(() => {
  return {
    clearable: true,
    ...useAttrs(),
  }
})
// 自定义指令
const vClickOutside = ClickOutside
const slots = useSlots()
const isDefaultSelectVal = ref(true) // 是否已经重新选择了
const forbidden = ref(true) // 判断单选选中及取消选中
const isRadio = ref(false)
const isQueryVisible = ref(false) // 查询条件是否显示隐藏下拉框
const isVisible = ref(false) // 是否显示隐藏下拉框
const radioVal: any = ref('')
const selectDefaultLabel: any = ref(props.modelValue) // 单选赋值
const state: any = reactive({
  defaultSelectValue: props.defaultSelectVal, // 默认选中
  tableData: props.table.data, // table数据
  defaultValue: props.value,
  ids: [], // 多选id集合
  tabularMap: {}, // 存储下拉tale的所有name
})
// 获取ref
const selectRef: any = ref<HTMLElement | null>(null)
const selectTable: any = ref<HTMLElement | null>(null)
const tQueryConditionRef: any = ref<HTMLElement | null>(null)
const nowIndex = ref(-1)
watch(
  () => props.table.data,
  (val) => {
    state.tableData = val
    nextTick(() => {
      state.tableData &&
        state.tableData.length > 0 &&
        state.tableData.forEach((item: { [x: string]: any }) => {
          state.tabularMap[item[props.keywords.value]] =
            item[props.keywords.label]
        })
    })
  },
  { deep: true }
)
watch(
  () => props.defaultSelectVal,
  (val) => {
    console.log('props.defaultSelectVal---watch', val, isDefaultSelectVal.value)
    state.defaultSelectValue = val
    if (val.length > 0 && isDefaultSelectVal.value) {
      defaultSelect(val)
    }
  },
  { deep: true }
)
onMounted(() => {
  // 设置默认选中项(单选)
  if (state.defaultSelectValue.length > 0 && isDefaultSelectVal.value) {
    defaultSelect(state.defaultSelectValue)
  }
})
// 表格显示隐藏回调
const visibleChange = (visible: boolean) => {
  // console.log('表格显示隐藏回调', visible)
  isVisible.value = visible
  if (isQueryVisible.value) {
    selectRef.value.expanded = true
  }
  // console.log('表格显示隐藏回调--222', visible)
  if (visible) {
    if (props.defaultSelectVal.length > 0 && isDefaultSelectVal.value) {
      defaultSelect(props.defaultSelectVal)
    }
    initTableData()
  } else {
    if (
      tQueryConditionRef.value &&
      props.isShowQuery &&
      props.isClearQuery &&
      !selectRef.value.expanded
    ) {
      tQueryConditionRef.value?.resetHandle()
    }
    findLabel()
    filterMethodHandle('')
  }
}
// 查询条件change事件触发
const handleEvent = () => {
  // console.log('查询条件change事件触发')
  selectRef.value.expanded = true
}
// 条件查询组件的visible-change事件
const queryVisibleChange = (val: boolean) => {
  // console.log('selectVisibleChange---999', val)
  isQueryVisible.value = val
}
// el-select点击了空白区域
const closeBox = () => {
  // console.log('select点击了空白区域', tQueryConditionRef.value)
  // 获取查询条件组件的项
  if (tQueryConditionRef.value && props.isShowQuery) {
    selectRef.value.expanded = true
    Object.values(tQueryConditionRef.value?.props?.opts).map((val: any) => {
      if (
        val.comp.includes('select') ||
        val.comp.includes('picker') ||
        val.comp.includes('date')
      ) {
        val.eventHandle = {
          'visible-change': ($event: boolean) => queryVisibleChange($event),
        }
        // queryVisibleChange(true)
        // isQueryVisible.value = true
        selectRef.value.expanded = true
      }
    })
    if (isVisible.value && props.isShowQuery) {
      selectRef.value.expanded = true
    } else {
      selectRef.value.expanded = false
    }
  }
}
// 单选键盘事件
const selectKeyup = (e: { keyCode: any }) => {
  if (!props.multiple) {
    if (!props.isKeyup) return
    if (state.tableData.length === 0) return
    switch (e.keyCode) {
      case 40: // 下键
        if (state.tableData[nowIndex.value * 1 + 1] !== undefined) {
          selectTable.value.setCurrentRow(
            state.tableData[nowIndex.value * 1 + 1]
          )
          nowIndex.value = nowIndex.value * 1 + 1
        } else {
          nowIndex.value = 0
          selectTable.value.setCurrentRow(state.tableData[0])
        }
        break
      case 38: // 上键
        if (
          state.tableData[nowIndex.value * 1 - 1] !== undefined &&
          nowIndex.value > 0
        ) {
          selectTable.value.setCurrentRow(
            state.tableData[nowIndex.value * 1 - 1]
          )
          nowIndex.value = nowIndex.value * 1 - 1
        } else {
          nowIndex.value = 0
          selectTable.value.setCurrentRow(state.tableData[0])
        }
        break
      case 13: // 回车
        rowClick(state.tableData[nowIndex.value])
        break
    }
  }
}
// 赋值
const findLabel = () => {
  nextTick(() => {
    if (props.multiple) {
      selectRef.value.selected?.forEach(
        (item: { currentLabel: any; value: any }) => {
          item.currentLabel = item.value
        }
      )
    } else {
      selectDefaultLabel.value =
        (state.defaultValue && state.defaultValue[props.keywords.label]) || ''
    }
  })
}

// 抛出事件
const emits = defineEmits(['page-change', 'selectionChange', 'radioChange'])

// 当前页码
const handlesCurrentChange = (val: any) => {
  if (props.multiple) {
    if (!props.reserveSelection) {
      clear()
    }
  } else {
    clear()
  }
  emits('page-change', val)
}
// 默认选中(且只能默认选中第一页的数据)
const defaultSelect = (defaultSelectVal: any[]) => {
  if (props.multiple) {
    let multipleList: any = []
    defaultSelectVal.map((val) => {
      state.tableData.forEach((row: any) => {
        if (val === row[props.keywords.value]) {
          multipleList.push(row)
        }
      })
    })
    setTimeout(() => {
      state.defaultValue = multipleList.map(
        (item: { [x: string]: any }) => item[props.keywords.label]
      )
      multipleList.forEach((row: { [x: string]: any }) => {
        const arr = state.tableData.filter(
          (item: { [x: string]: any }) =>
            item[props.keywords.value] === row[props.keywords.value]
        )
        if (arr.length > 0) {
          selectTable.value.toggleRowSelection(arr[0], true)
        }
      })
      selectRef.value?.selected?.forEach(
        (item: { currentLabel: any; value: any }) => {
          item.currentLabel = item.value
        }
      )
    }, 0)
  } else {
    let row: any, index: any
    state.tableData.map((val: { [x: string]: any }, i: any) => {
      if (val[props.keywords.value] === defaultSelectVal[0]) {
        row = val
        index = i
      }
    })
    radioVal.value = index + 1
    state.defaultValue = row
    setTimeout(() => {
      selectDefaultLabel.value = row && row[props.keywords.label]
    }, 0)
    emits('radioChange', row, row && row[props.keywords.value])
  }
}
// 复选框(多选)
const handlesSelectionChange = (val: any[]) => {
  // console.log('复选框', val)
  isDefaultSelectVal.value = false
  state.defaultValue = val.map((item) => item[props.keywords.label])
  state.ids = val.map((item) => item[props.keywords.value])
  if (val.length === 0) isDefaultSelectVal.value = true
  emits('selectionChange', val, state.ids)
}
// 搜索后表格勾选不取消
const getRowKey = (row: { [x: string]: any }) => {
  return row[props.keywords.value]
}
// 搜索过滤
const filterMethodHandle = (val: string) => {
  if (!props.filterable) return
  const tableData = JSON.parse(JSON.stringify(props.table?.data))
  if (tableData && tableData.length > 0) {
    if (!props.multiple) {
      if (val) {
        radioVal.value = ''
      } else {
        tableData.map((item: { [x: string]: any }, index: number) => {
          if (
            item[props.keywords.value] === selectDefaultLabel.value &&
            selectDefaultLabel.value[props.keywords.value]
          ) {
            radioVal.value = index + 1
          }
        })
      }
    }
    state.tableData = tableData.filter(
      (item: { [x: string]: string | string[] }) => {
        if (item[props.keywords.label].includes(val)) {
          return item
        }
      }
    )
  }
}

// 获取表格数据
const initTableData = () => {
  // 表格默认赋值
  nextTick(() => {
    if (props.multiple) {
      state.defaultValue?.forEach((row: { [x: string]: any }) => {
        const arr = state.tableData.filter(
          (item: { [x: string]: any }) =>
            item[props.keywords.value] === row[props.keywords.value]
        )
        if (arr.length > 0) {
          selectTable.value.toggleRowSelection(arr[0], true)
        }
      })
    } else {
      const arr = state.tableData.filter(
        (item: { [x: string]: any }) =>
          item[props.keywords.value] === selectDefaultLabel.value &&
          selectDefaultLabel.value[props.keywords.value]
      )
      selectTable.value.setCurrentRow(arr[0])
    }
  })
}
// 复制内容
const copyDomText = (val: any) => {
  // 获取需要复制的元素以及元素内的文本内容
  const text = val
  // 添加一个input元素放置需要的文本内容
  const input = document.createElement('input')
  input.value = text
  document.body.appendChild(input)
  // 选中并复制文本到剪切板
  input.select()
  document.execCommand('copy')
  // 移除input元素
  document.body.removeChild(input)
}
// 双击复制单元格内容
const cellDblclick = (
  row: { [x: string]: any },
  column: { property: string | number }
) => {
  try {
    copyDomText(row[column.property])
    ElMessage.success('复制成功')
  } catch (e) {
    ElMessage.error('复制失败')
  }
}
// 点击单选框单元格触发事件
const radioChangeHandle = (
  event: { preventDefault: () => void },
  row: any,
  index: any
) => {
  event.preventDefault()
  isDefaultSelectVal.value = false
  radioClick(row, index)
}
// forbidden取值
const isForbidden = () => {
  forbidden.value = false
  setTimeout(() => {
    forbidden.value = true
  }, 0)
}
// 单选抛出事件radioChange
const radioClick = (row: { [x: string]: any }, index: any) => {
  forbidden.value = !!forbidden.value
  if (radioVal.value) {
    if (radioVal.value === index) {
      radioVal.value = ''
      isForbidden()
      state.defaultValue = {}
      isDefaultSelectVal.value = true
      emits('radioChange', {}, null) // 取消勾选就把回传数据清除
      blur()
    } else {
      isForbidden()
      radioVal.value = index
      state.defaultValue = row
      emits('radioChange', row, row[props.keywords.value])
      blur()
    }
  } else {
    isForbidden()
    radioVal.value = index
    state.defaultValue = row
    emits('radioChange', row, row[props.keywords.value])
    blur()
  }
}
// 单击行
const rowClick = async (row: { [x: string]: any }) => {
  if (!props.rowClickRadio) return
  if (!props.multiple) {
    let rowIndex: any
    // eslint-disable-next-line no-unused-expressions
    props.table?.data.forEach((item: { [x: string]: any }, index: any) => {
      if (item[props.keywords.value] === row[props.keywords.value]) {
        // console.log('index', index)
        rowIndex = index
      }
    })
    // await this.radioClick(row, rowIndex + 1)
    isDefaultSelectVal.value = false
    await radioClick(row, rowIndex + 1)
    if (radioVal.value) {
      isRadio.value = true
    } else {
      isRadio.value = false
    }
  }
}
// tags删除后回调
const removeTag = (tag: any) => {
  const row = state.tableData.find(
    (item: { [x: string]: any }) => item[props.keywords.label] === tag
  )
  console.log('tags删除后回调', row)
  selectTable.value.toggleRowSelection(row, false)
  isDefaultSelectVal.value = true
}
// 清空后的回调
const clear = () => {
  if (props.multiple) {
    selectTable.value.clearSelection()
    isDefaultSelectVal.value = true
    state.defaultValue = []
  } else {
    // 取消高亮
    selectTable.value.setCurrentRow(-1)
    nowIndex.value = -1
    radioVal.value = ''
    isDefaultSelectVal.value = true
    forbidden.value = false
    selectDefaultLabel.value = null
    state.defaultValue = null
    emits('radioChange', {}, null)
  }
}
// 触发select隐藏
const blur = () => {
  selectRef.value.blur()
}
// 触发select显示
const focus = () => {
  selectRef.value.focus()
}
// 暴露方法出去
defineExpose({ focus, blur, clear, tQueryConditionRef })
</script>

<style lang="scss">
.t-select-table {
  // 单选样式
  .radioStyle {
    .el-radio {
      .el-radio__label {
        display: none;
      }
      &:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner {
        box-shadow: none;
      }
    }
    .el-table__row {
      cursor: pointer;
    }
  }
  // 键盘事件开启选择高亮
  .keyUpStyle {
    .el-table__body {
      tbody {
        .current-row {
          color: var(--el-color-primary) !important;
          cursor: pointer;
        }
      }
    }
  }
  // 选中行样式
  .highlightCurrentRow {
    :deep(.current-row) {
      color: var(--el-color-primary);
      cursor: pointer;
    }
  }
  .t-table-select__table {
    padding: 10px;

    .el-table__body,
    .el-table__header {
      margin: 0;
    }
    // 条件查询组件样式
    .table_query_condition {
      width: 100%;
      overflow-x: auto;
      overflow-y: hidden;
      padding: 10px;
    }
  }

  .t-table-select__page {
    padding-top: 5px;
    padding-right: 10px;
    .el-pagination {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      margin-right: calc(2% - 20px);
      background-color: var(--el-table-tr-bg-color);
    }
  }
}
</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762

五、组件地址

gitHub组件地址

gitee码云组件地址

六、相关文章

vue3+ts基于Element-plus再次封装基础组件文档


基于ElementUi再次封装基础组件文档


基于ant-design-vue再次封装基础组件文档

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/577831
推荐阅读
相关标签
  

闽ICP备14008679号