组件使用文档:
https://terryz.gitee.io/vue/#/selectpage/demo
实例:
需要使用的下拉分页的页面:
<el-form-item label="公司" prop="carrierId">
<base-selectPage v-model="ruleForm.carrierId" keyField="crmCorporationId" @change="rows => emitBookingAgent(rows, 1)" searchField="keyword" showField="code" concatField="code_nameCn" :searchParams="{carrier: true, customerStep: 1, shipping: true, allowOrder: false}"
data="/transportPrice-api/crm/corporation/getSimplePage" :tb-columns="defaultSelectPageColumns" :defaultRow="editType === 'edit' ? {crmCorporationId: ruleForm.carrierId, code: ruleForm.carrierCode, nameCn: ruleForm.carrierNameCn} : {}"
></base-selectPage>
</el-form-item>
import { defaultSelectPageColumns} from "@/utils/constants";
==============================================================================================
constants.js
// 基础分页下拉Columns
export const defaultSelectPageColumns = [
{ title: 'CODE', data: 'code', width: 130 },
title: '中文名', data: 'nameCn', minWidth: 180 },
{ title: '英文名', data: 'nameEn', minWidth: 250 },
]
=====================================================================================
data(){
return {
ruleForm: {
carrierId: "",
},
defaultSelectPageColumns: defaultSelectPageColumns,
}
}
========================================================================================
字段解释:
v-model="ruleForm.carrierId" 字段绑定的参数
keyField="crmCorporationId" 关键字
searchField="keyword" 搜索
showField="code" 展示
concatField="code_nameCn" 回显的时候,代码+中文名
:searchParams="{carrier: true, customerStep: 1, shipping: true, allowOrder: false}" 搜索条件
data="/xxxx/xxxx/xxxx/xxxxxxx" 数据接口路径
:tb-columns="defaultSelectPageColumns" 下拉框的列头设置
defaultRow="editType === 'edit' ? {crmCorporationId: ruleForm.carrierId, code: ruleForm.carrierCode, nameCn: ruleForm.carrierNameCn} : {}" 默认行显示
==============================================================================
main.js 中进行全局的配置
import BaseSelectPage from "@/components/BaseSelectPage"
全局挂载
Vue.component('BaseSelectPage', BaseSelectPage)
===============================================================================
BaseSelectPage 文件夹
index.vue
<template>
<el-popover
:placement="placement"
width="auto"
@show="handleShowPopover"
@hide="handleHidePopover"
:disabled="disabled"
ref="popoverRef"
class="popover-warp"
trigger="click">
<div class="select-main" ref="baseSelectPageRef">
<div class="base-search">
<!-- 加el-form防止外部form影响该search控件 -->
<el-form @submit.native.prevent>
<!-- 搜索 -->
<el-form-item>
<el-input v-model="searchVal" prefix-icon="el-icon-search" ref="searchRef" @input="handleSearchValChange" clearable></el-input>
</el-form-item>
</el-form>
</div>
<div class="base-table">
<el-table :data="list"
ref="tableRef"
highlight-current-row
@cell-mouse-enter="cellMouseEnter"
@row-click="rowClick"
:row-class-name="rowClassName"
:row-key="keyField"
max-height="500px"
v-loading="loading">
<!-- <el-table-column
type="selection"
align="center"
header-align="center"
width="40">
</el-table-column> -->
<el-table-column
v-for="(item, index) in tbColumns"
:key="index"
:width="item.width"
:min-width="item.minWidth || 100"
:prop="item.data"
:label="item.title"
:fixed="item.fixed"
:render-header="item.renderHeader"
:align="item.align || 'left'"
:header-align="item.headerAlign || 'left'"
:class-name="item.className"
:show-overflow-tooltip="item.showOverflowTooltip === false ? false : true">
</el-table-column>
</el-table>
</div>
<div class="base-pagination">
<el-pagination
@current-change="val => handlePageChange(val, 'pageNo')"
:current-page="pagination.pageNo"
:page-size="pagination.pageSize"
:total="pagination.total"
layout="prev, pager, next">
</el-pagination>
</div>
</div>
<div slot="reference" ref="referenceRef" class="referenceClass" :style="{width: width}">
<el-input :class="multiple && 'hidden-inp'" v-model="showVal" class="reference-inp" readonly :disabled="disabled" :placeholder="placeholder" :id="id" :size="size">
<div slot="suffix" ref="suffixRef" class="suffixClass">
<i class="el-input__icon el-icon-arrow-down" v-if="!clearableVisible" :class="{open: !disabled && visible}"></i>
<i class="el-input__icon el-icon-circle-close" v-else @click="clear"></i>
</div>
</el-input>
<div v-if="multiple" class="base-select_tags" :class="`base-select_tags--${size}`">
<transition-group v-if="!collapseTags && selectRows.length">
<el-tag
v-for="item in selectRows"
:key="item[keyField]"
:closable="!disabled"
:size="collapseTagSize"
type="info"
@close="deleteTag($event, item)"
class="base-tag"
disable-transitions>
<span class="el-select__tags-text">{{ formatTagItem(item) }}</span>
</el-tag>
</transition-group>
<span v-if="collapseTags && selectRows.length">
<el-tag
v-for="index of showMaxTagsLimit > selectRows.length ? selectRows.length : showMaxTagsLimit"
:key="selectRows[index-1][keyField]"
:closable="!disabled"
:size="collapseTagSize"
type="info"
@close="deleteTag($event, selectRows[index-1])"
class="base-tag"
disable-transitions>
<span class="el-select__tags-text">{{ formatTagItem(selectRows[index-1]) }}</span>
</el-tag>
<el-tag
v-if="selectRows.length > showMaxTagsLimit"
:closable="false"
:size="collapseTagSize"
type="info"
class="base-tag"
disable-transitions>
<span class="el-select__tags-text">+ {{ selectRows.length - showMaxTagsLimit }}</span>
</el-tag>
</span>
<span v-if="!selectRows.length" class="base-select_tags-placeholder">{{placeholder}}</span>
<div class="suffixClass">
<i class="el-input__icon el-icon-arrow-down" v-if="!clearableVisible" :class="{open: !disabled && visible}"></i>
<i class="el-input__icon el-icon-circle-close" v-else @click="clear"></i>
</div>
</div>
</div>
</el-popover>
</template>
<!-- 分页下拉组件 by lyh 2023年2月 -->
<script>
import { getAction } from '@/api/common/index'
import { debounce } from 'throttle-debounce'
import { equals, cutArray } from '@/utils/utils'
import { deepClone } from '@/utils/index'
export default {
name: 'BaseSelectPage',
props: {
value: [Array, String, Number],
/**
* table 数据
* Array:前端分页
* String:后端分页,传的是url
*/
data: {
type: [Array, String],
required: true
},
/**
* 禁用
*/
disabled: {
type: Boolean,
default: false
},
/**
* 清空
*/
clearable: {
type: Boolean,
default: false
},
/**
* 搜索的字段
*/
searchField: {
type: String,
default: 'keyword'
},
/**
* 唯一的key
*/
keyField: {
type: String,
required: true
},
/**
* 要展示的字段
*/
showField: {
type: String,
default: 'code'
},
/**
* 查询参数
*/
searchParams: {
type: Object,
default: () => {}
},
/**
* 是否多选
*/
multiple: {
type: Boolean,
default: false
},
pageSize: {
type: [Number, String],
default: 10
},
/**
* table columns数据
*/
tbColumns: {
type: Array,
default: () => {
return [
// {title: '名称', data: 'value'}
]
}
},
/**
* 服务端分页时初始化默认显示的数据
* 单选传的是Object,多选传的是Array
*/
defaultRow: {
type: [Object, Array],
default: () => {
return {}
}
},
/**
* 需要合并显示的字段
* name1_name2_name3....
*/
concatField: String,
/**
* placeholder
*/
placeholder: String,
/**
* 多选时是否将选中值按文字的形式展示
*/
collapseTags: Boolean,
/**
* 选中值按文字的形式展示时,最大显示的tag数
*/
showMaxTagsLimit: {
type: Number,
default: 1
},
/**
* 尺寸 small mini...
*/
size: {
type: String,
default: ''
},
/**
* 宽度
*/
width: {
type: String,
default: 'auto'
},
/**
* popover 的显示位置
*/
placement: {
type: String,
default: 'bottom'
},
/**
* 格式化返回值,仅服务端
* 必须返回这种格式 {list: [], total: 0}
*/
formatResult: {
type: Function,
default: null
},
id: String
},
data() {
return {
selectRows: [], // 选中的行
searchVal: '', // 搜索的值
showVal: '', // 存储显示的input控件的状态
loading: false,
visible: false, // Popover是否显示
clearableVisible: false, // clearable是否显示
list: [], // 服务端分页时,table数据
pagination: {
total: 0,
pageSize: this.pageSize,
pageNo: 1
},
currentRow: {}, // 当前行
noEmitInput: false, // 不触发emit Input事件
isServer: toString.call(this.data) === '[object String]' // 是否服务端分页
};
},
components: {},
created() {
// 初始回显赋值
if (!this.multiple) { // 单选
if (this.isServer) {
if (Object.keys(this.defaultRow).length && !this.selectRows.length) {
this.selectRows = [this.defaultRow]
}
} else {
if (this.value && this.data.length) {
this.noEmit()
this.selectRows = [this.data.find(r => String(r[this.keyField]) === String(this.value))]
}
}
} else { // 多选
if (this.isServer) {
if (this.defaultRow.length && !this.selectRows.length) {
this.noEmit()
this.selectRows = deepClone(this.defaultRow)
}
} else {
if (this.value.length && this.data.length) {
let arr = []
this.value.forEach(r => {
const row = this.data.find(r1 => r1[this.keyField] === r)
if (row) arr.push(row)
})
this.noEmit()
this.selectRows = arr
}
}
}
},
mounted() {
this.suffixRefEvent()
try {
// 设置base-table最小宽度
const popEl = this.$refs.popoverRef.$el
document.querySelector(`#${popEl.firstChild.id}`).querySelector('.base-table').style.minWidth = (popEl.offsetWidth - 24) + 'px'
} catch {}
},
methods: {
// Popover显示事件
handleShowPopover() {
this.visible = true
this.currentRow = {}
// 服务端分页
if (toString.call(this.data) === '[object String]') {
this.fetchData()
}
// 前端分页
if (toString.call(this.data) === '[object Array]') {
this.localData('', true)
}
this.$emit('visible-change', true)
this.initEvent()
try {
this.$nextTick(() => {
this.resetPopoverTop()
// 设置边框颜色
const setting = localStorage.getItem('layout-setting')
const popEl = this.$refs.popoverRef.$el
if (this.multiple) {
popEl.querySelector('.base-select_tags').style.borderColor = setting && JSON.parse(setting)?.['theme']
} else {
popEl.querySelector('.reference-inp').querySelector('.el-input__inner').style.borderColor = setting && JSON.parse(setting)?.['theme']
}
})
} catch {}
},
// Popover隐藏事件
handleHidePopover() {
this.visible = false
this.searchVal = ''
this.$emit('visible-change', false)
// 重置边框颜色
try {
this.$nextTick(() => {
const popEl = this.$refs.popoverRef.$el
if (this.multiple) {
const tagsEl = popEl.querySelector('.base-select_tags')
tagsEl.style.borderColor = ''
tagsEl.classList.remove('_bgc')
tagsEl.classList.add('_bgc')
} else {
const inpEl = popEl.querySelector('.reference-inp').querySelector('.el-input__inner')
inpEl.style.borderColor = ''
inpEl.classList.remove('_bgc')
inpEl.classList.add('_bgc')
}
})
} catch {}
},
// 调整下拉框位置
resetPopoverTop() {
this.$nextTick(() => {
const tagsEl = this.$refs.popoverRef.$el.querySelector('.base-select_tags')
const popperElm = this.$refs.popoverRef.popperElm
if (!tagsEl) return
const { bottom, top } = tagsEl.getBoundingClientRect() || {}
const { top: popperElmTop } = popperElm.getBoundingClientRect() || {}
if (popperElmTop > top) {
popperElm.style.top = bottom + 'px'
}
})
},
// 服务端分页时获取数据
async fetchData() {
const { pageSize, pageNo } = this.pagination
const query = {
pageSize, pageNo,
...this.searchParams,
...(this.searchField ? {[this.searchField]: this.searchVal} : {})
}
this.loading = true
const {code, data} = await getAction(this.data, query).finally(() => this.loading = false)
if (code != 0) {
this.list = []
this.$set(this.pagination, 'total', 0)
return
}
const {list, total} = toString.call(this.formatResult) != '[object Null]' ? this.formatResult(data) : data
this.list = list || []
this.$set(this.pagination, 'total', total || 0)
this.setSelectRows(1)
},
/**
* 前端分页时获取数据
* type:1 搜索
* isShow:是否Popover显示时调用
* isArrow:是否键盘左右键切换页码,或点击页码时调用
*/
localData(type, isShow, isArrow) {
let len = this.data.length, arr = []
if (type === 1) {
const searchFilterArr = this.data.filter(r => r[this.searchField].toLowerCase().includes(this.searchVal.toLowerCase()))
len = searchFilterArr.length
arr = cutArray(searchFilterArr, this.pageSize)
this.$set(this.pagination, 'total', len)
if(!isArrow || !len) this.$set(this.pagination, 'pageNo', 1)
this.list = len ? arr[this.pagination.pageNo-1] : []
} else {
if (len) {
arr = cutArray(this.data, this.pageSize)
this.$set(this.pagination, 'total', len)
this.list = arr[this.pagination.pageNo-1]
} else {
this.list = []
this.$set(this.pagination, 'total', 0)
}
}
// 切换到选中数据的分页
if (isShow) {
if (!this.multiple) {
if (this.value) {
arr.forEach((r, i) => {
if (r.some(r1 => String(r1[this.keyField]) === String(this.value))) {
this.list = r
this.$set(this.pagination, 'pageNo', i+1)
}
})
}
}
}
this.setSelectRows(2)
},
// 存在默认值情况下,重新赋值
setSelectRows(type) {
if (!this.multiple) {
if (type === 1) {
if (Object.keys(this.defaultRow).length && this.selectRows.length && equals(this.defaultRow, this.selectRows[0])) {
this.list.forEach(r => {
if (r[this.keyField] == this.defaultRow[this.keyField]) {
this.noEmit()
this.selectRows = [r]
}
})
}
} else {
}
} else {}
},
// 初始化键盘事件
initEvent() {
let that = this
this.$nextTick(() => {
this.$refs.searchRef.focus()
this.$refs.baseSelectPageRef.onkeydown = function (e) {
e = window.event || e
// 设置当前行
const setCurrentRow = (row) => {
that.$refs.tableRef.setCurrentRow(row)
that.currentRow = row
}
const { pageNo, total, pageSize } = that.pagination
switch (e.key) {
case 'ArrowRight':
if (that.pagination.pageNo === parseInt(total / pageSize)+1) return
that.$set(that.pagination, 'pageNo', pageNo+1)
that.isServer ? that.fetchData() : that.localData(that.searchVal ? 1 : '', false, true)
that.currentRow = {}
break;
case 'ArrowLeft':
if (that.pagination.pageNo === 1) return
that.$set(that.pagination, 'pageNo', pageNo-1)
that.isServer ? that.fetchData() : that.localData(that.searchVal ? 1 : '', false, true)
that.currentRow = {}
break;
case 'ArrowUp':
if (!Object.keys(that.currentRow).length) {
const row = that.list[that.list.length-1]
setCurrentRow(row)
} else {
for (let i = 0; i < that.list.length; i++) {
const row = that.list[i];
// 滚动到最后一行
if (that.currentRow[that.keyField] === that.list[0][that.keyField]) {
const curRow = that.list[that.list.length-1]
setCurrentRow(curRow)
break
}
// 滚动到上一行
if (that.currentRow[that.keyField] === row[that.keyField]) {
const curRow = that.list[i-1]
setCurrentRow(curRow)
break
}
}
}
break;
case 'ArrowDown':
if (!Object.keys(that.currentRow).length) {
const row = that.list[0]
setCurrentRow(row)
} else {
for (let i = 0; i < that.list.length; i++) {
const row = that.list[i];
// 滚动到第一行
if (that.currentRow[that.keyField] === that.list[that.list.length-1][that.keyField]) {
const curRow = that.list[0]
setCurrentRow(curRow)
break
}
// 滚动到下一行
if (that.currentRow[that.keyField] === row[that.keyField]) {
const curRow = that.list[i+1]
setCurrentRow(curRow)
break
}
}
}
break;
case 'Enter':
const curRow = that.currentRow
if (!that.multiple) {
if (Object.keys(curRow).length) {
that.selectRows = [curRow]
that.$refs.tableRef.clearSelection()
that.$refs.tableRef.toggleRowSelection(curRow)
that.$refs.popoverRef.doClose()
}
} else {
// 多选
if (Object.keys(curRow).length) {
if (!that.selectRows.some(r => r[that.keyField] === curRow[that.keyField])) {
that.selectRows.push(curRow)
} else {
const index = that.selectRows.findIndex(r => r[that.keyField] === curRow[that.keyField])
that.selectRows.splice(index, 1)
}
}
}
break;
}
that.$emit('keydownEnter', e, that)
}
})
},
// 鼠标滑动事件
cellMouseEnter(row, column, cell, event) {
this.$refs.tableRef.setCurrentRow(row)
// 保存当前行
this.currentRow = row
},
// 设置选中行颜色
rowClassName({row, rowIndex}) {
if (Array.isArray(this.selectRows)) {
if (this.selectRows.some(r => r?.[this.keyField] == row?.[this.keyField])) return 'base-select-row'
}
},
// 行单击
rowClick(row, column, event) {
if (!this.multiple) {
this.selectRows = [row]
this.$refs.popoverRef.doClose()
} else {
if (!this.selectRows.some(r => r[this.keyField] === row[this.keyField])) {
this.selectRows.push(row)
} else {
const index = this.selectRows.findIndex(r => r[this.keyField] === row[this.keyField])
this.selectRows.splice(index, 1)
}
this.resetPopoverTop()
}
},
// 页码改变事件
handlePageChange(val, type) {
this.pagination[type] = val
if (toString.call(this.data) === '[object String]') {
this.fetchData()
} else {
this.localData(this.searchVal ? 1 : '', false, true)
}
},
// 顶部搜索框改变事件
handleSearchValChange: debounce(300, function() {
this.currentRow = {}
this.$set(this.pagination, 'pageNo', 1)
if (toString.call(this.data) === '[object String]') {
this.fetchData()
} else {
this.localData(1)
}
}),
// 给删除按钮添加事件
suffixRefEvent() {
this.$refs.referenceRef.onmouseenter = () => {
this.clearableVisible = !!this.value && this.clearable && !this.disabled
}
this.$refs.referenceRef.onmouseleave = () => {
this.clearableVisible = false
}
},
// 清空数据
clear(e) {
e.stopPropagation()
this.selectRows = []
this.clearableVisible = false
},
isEmpty(v) {
return v === '' || v === null || v === undefined
},
// 不提交input事件和change事件
noEmit() {
this.noEmitInput = true
setTimeout(() => {
this.noEmitInput = false
}, 300)
},
// 刷新
reload() {
this.noEmit()
this.selectRows = []
this.showVal = ''
this.list = []
this.pagination = {
total: 0,
pageSize: this.pageSize,
pageNo: 1
}
this.currentRow = {}
},
// 格式化tag的显示内容
formatTagItem(item) {
if (this.isEmpty(item[this.showField])) return ''
if (this.concatField) {
const fieldArr = this.concatField.split('_')
let arr = []
fieldArr.forEach(r => {
const s = item[r] || ''
arr.push(s)
})
return arr.length ? arr.filter(r => r).join('/') : ''
} else {
return item[this.showField]
}
},
// 多选时,删除tags
deleteTag(e, item) {
const index = this.selectRows.findIndex(r => r[this.keyField] === item[this.keyField])
const delArr = this.selectRows.splice(index, 1)
this.$emit('remove-tag', delArr)
}
},
computed: {
keys() {
return (this.multiple ? this.selectRows.map(r => r[this.keyField]) : this.selectRows?.[0]?.[this.keyField]) || ''
},
selectSize() {
return this.size || (this.$ELEMENT || {}).size;
},
collapseTagSize() {
return ['small', 'mini'].indexOf(this.selectSize) > -1
? 'mini'
: 'small';
},
},
watch: {
value: function(n, o) {
if (!n) {
if (this.selectRows.length) {
this.selectRows = []
this.currentRow = {}
}
} else {
if (toString.call(this.data) === '[object String]') {
} else {
// value改变时,前端分页默认回显数据
if (this.data.length) {
if (this.multiple) {
let arr = []
n.forEach(r => {
const row = this.data.find(r1 => r1[this.keyField] === r)
if (row) arr.push(row)
})
this.noEmit()
this.selectRows = arr
} else {
this.noEmit()
this.selectRows = !this.isEmpty(n) ? [this.data.find(r => String(r[this.keyField]) === String(n))] : []
this.currentRow = {}
}
}
}
}
},
selectRows: {
handler: function(n, o) {
if (n.length) {
if (!this.multiple) {
if (this.concatField) { // 需要拼接返回字段值
const fieldArr = this.concatField.split('_')
let arr = []
fieldArr.forEach(r => {
const s = this.selectRows?.[0]?.[r] || ''
arr.push(s)
})
this.showVal = arr.length ? arr.filter(r => r).join('/') : ''
} else {
this.showVal = this.selectRows?.[0]?.[this.showField] || ''
}
}
} else {
this.showVal = ''
}
const toEmit = () => {
this.$emit('input', this.keys)
this.$emit('change', this.selectRows.slice())
}
if (!this.noEmitInput) {
if (!this.multiple) {
if (this.selectRows.length === 1) {
if (this.selectRows[0][this.keyField] != this.defaultRow[this.keyField]) {
toEmit()
}
} else {
toEmit()
}
} else {
// 多选
if (this.selectRows.length && this.defaultRow.length) {
if (this.selectRows.map(r => r[this.keyField]).join() != this.defaultRow.map(r => r[this.keyField]).join()) {
toEmit()
}
} else {
toEmit()
}
}
}
},
deep: true
},
defaultRow: function(n, o) {
if (!this.multiple && toString.call(this.data) === '[object String]') {
if (Object.keys(n).length && !equals(n, o)) {
if (!this.isEmpty(n[this.keyField])) {
this.noEmit()
const row = this.list.find(r => r[this.keyField] === n[this.keyField])
this.selectRows = [row || n]
}
}
} else {}
},
data: function(n) {
if (toString.call(n) === '[object String]') {
} else {
// data切换时,前端分页默认回显数据
if (n.length && this.value) {
this.noEmit()
this.selectRows = [n.find(r => String(r[this.keyField]) === String(this.value))]
}
this.currentRow = {}
}
}
}
};
</script>
<style scoped lang="scss">
.popover-warp {
display: block;
}
.select-main {
}
.base-search {
margin: 0 0 12px;
::v-deep .el-form-item {
margin-bottom: 0;
}
::v-deep .el-form-item--small .el-input__suffix .el-icon-circle-close {
line-height: 28px !important;
}
}
.base-table {
max-width: 600px;
::v-deep .el-table thead th.el-table__cell {
background-color: #fff !important;
}
::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
background-color: #f5f7fa;
}
::v-deep .el-table__body tr.current-row > td.el-table__cell {
background-color: #f5f7fa;
}
::v-deep .el-table__body tr.base-select-row {
color: var(--current-color, #1890ff);
font-weight: 600;
}
::v-deep .el-table th.el-table__cell.is-leaf,::v-deep .el-table td.el-table__cell {
border-bottom: 0;
}
::v-deep .el-table::before {
height: 0;
}
}
.base-pagination {
margin-top: 5px;
text-align: center;
::v-deep .el-pagination {
padding: 0;
color: #505050;
}
}
::v-deep .el-icon-arrow-down {
position: absolute;
top: 0px;
right: 0px;
transition: transform .3s ease;
transform: rotateZ(0deg);
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
color: #C0C4CC;
}
::v-deep .el-icon-circle-close {
cursor: pointer;
position: absolute;
top: 0px;
right: 0px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
color: #C0C4CC;
}
::v-deep .open {
transform: rotateZ(-180deg);
}
.referenceClass {
position: relative;
}
::v-deep .referenceClass .el-input__inner, .suffixClass {
cursor: pointer;
}
.hidden-inp {
z-index: -1;
opacity: 0;
}
.base-select_tags {
position: absolute;
top: 0;
width: 100%;
z-index: 1;
min-height: 32px;
line-height: 32px;
padding: 2px 25px 2px 5px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
border-radius: 4px;
background-color: #fff;
display: flex;
align-items: center;
&:hover {
border-color: #c0c4cc;
}
> span {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.base-select_tags-placeholder {
position: absolute;
color: #c0c4cc;
font-size: 13px;
}
}
::v-deep .base-select_tags .el-icon-arrow-down, ::v-deep .base-select_tags .el-icon-circle-close {
right: 4px;
}
._bgc {
border-color: #dcdfe6;
&:hover {
border-color: #c0c4cc;
}
}
.base-tag {
margin: 2px 6px 2px 0;
}
.el-form-item--mini .base-select_tags {
min-height: 28px;
line-height: 28px;
padding: 1px 25px 1px 5px;
}
.el-form-item--small .base-select_tags {
min-height: 32px;
line-height: 32px;
}
.el-form-item--medium .base-select_tags {
min-height: 36px;
line-height: 36px;
}
.el-form-item--default .base-select_tags {
min-height: 40px;
line-height: 40px;
}
@media (max-width: 768px) {
.base-table {
max-width: 85vw;
}
}
</style>
==========================================================================
api接口
getAction:
export function getAction(url,params) {
return request({
url,
method: 'get',
params
})
}
=====================================================
throttle-debounce:
declare module 'throttle-debounce' {
type throttleFn = (
delay: number,
noTrailing: boolean,
callback?: Function,
debounceMode?: boolean
) => Function;
type debounceFn = (
delay: number,
atBegin: boolean,
callback?: Function
) => Function;
const throttle: throttleFn;
const debounce: debounceFn;
}
=========================================================================
util.js:
equals:
/**
* 判断两个对象是否相等
* @param {*} x
* @param {*} y
* @returns
*/
export function equals(x,y){
var f1=x instanceof Object;
var f2=y instanceof Object;
if(!f1 || !f2){
return x===y
}
if(Object.keys(x).length!== Object.keys(y).length){
return false
}
for(var p in x){
var a= x[p] instanceof Object;
var b= y[p] instanceof Object;
if(a && b){
equals(x[p],y[p])
}else if(x[p]!=y[p]){
return false;
}
}
return true;
}
cutArray:
/**
* 按指定长度切割数组
* @param {*} array
* @param {*} subLength
* @returns
*/
export function cutArray(array, subLength) {
let index = 0;
let newArr = [];
while(index < array.length) {
newArr.push(array.slice(index, index += subLength));
}
return newArr;
}
deepClone:
// 深拷贝对象
// https://github.com/JakHuang/form-generator/blob/dev/src/utils/index.js#L107
export function deepClone(obj) {
const _toString = Object.prototype.toString
// null, undefined, non-object, function
if (!obj || typeof obj !== 'object') {
return obj
}
// DOM Node
if (obj.nodeType && 'cloneNode' in obj) {
return obj.cloneNode(true)
}
// Date
if (_toString.call(obj) === '[object Date]') {
return new Date(obj.getTime())
}
// RegExp
if (_toString.call(obj) === '[object RegExp]') {
const flags = []
if (obj.global) { flags.push('g') }
if (obj.multiline) { flags.push('m') }
if (obj.ignoreCase) { flags.push('i') }
return new RegExp(obj.source, flags.join(''))
}
const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {}
for (const key in obj) {
result[key] = deepClone(obj[key])
}
return result
}
============================================================================
文件下说明: REAdME.md
<h2 align="center">