网站建设分类方案,网站怎么换域名,国家企业信用信息公示系统山西,广告公司介绍1 组件需求背景
在后台管理系统中#xff0c;表格的使用频率非常高#xff0c;统一封装表格动态列组件并全局注册使用#xff0c;可大大提升代码的复用性和可维护性。
2 全局注册
src/plugins/index.js#xff1a;
import columns from ./columns/indexexport default …1 组件需求背景
在后台管理系统中表格的使用频率非常高统一封装表格动态列组件并全局注册使用可大大提升代码的复用性和可维护性。
2 全局注册
src/plugins/index.js
import columns from ./columns/indexexport default {install(Vue) {// 动态列Vue.prototype.$columns columns}
}
src/main.js
import plugins from ./plugins // plugins
// 表格动态列组件
import DynamicColumn from /components/DynamicColumn
Vue.component(DynamicColumn, DynamicColumn)
Vue.use(plugins)页面(Page.vue)中使用 DynamicColumnv-for(ite, index) in columns:keyindex:itemite:data-listinfoList/infoList: [],
columns: this.$columns.getColumns(investmentDecision_list),Vue注册组件相关内容可见我的另外一篇博客Vue - 组件注册及其原理
3 具体组件相关代码
src/plugins/columns/index.js
const columns {getColumns: function(columnType) {const list columnList[columnType].listconst newColumn []list.forEach((v, i) {newColumn.push({...v,visible: v.visible undefined ? true : v.visible, // 是否显示字段prop: v.prop, // 字段keylabel: v.label, // 字段名称align: v.align, // 对齐方式sortable: v.sortable, // 是否排序inputType: v.inputType, // 输入方式fixed: v.fixed, // 是否固定列tip: v.tip, // 是否列名解析width: v.width, // 列宽unit: v.unit, // 后缀如%等keepDecimals: v.keepDecimals, // 保留小数位formatThousand: v.formatThousand, // 是否格式化千分位division: v.division, // 是否需要除数如格式化万则需要除10000class: v.class, // 样式style: v.style, // 样式disabled: v.disabled, // 禁用controls: v.controls,tagTypeStyle: v.tagTypeStyle, // tag标签风格函数类型返回一个字符串参考值为default | primary | success | info | warning | dangerrender: v.render, // 渲染函数返回一个处理后的值展示到页面中min: v.min, // 最小值max: v.max, // 最大值routerLink: v.routerLink,chartType: v.chartType, // Echart 图表类型参考值为1代表柱形折线图,2代表饼图chartData: v.chartData, // Echart 图表数据chartKey: v.chartKey, // Echart 图表Id的后缀columnTagText: v.columnTagText // 列标签标识})})return newColumn}
}export default columnssrc/components/DynamicColumn.vue
!--动态列--
template!-- :key${item.prop}${item.label} --!-- :show-overflow-tooltip!item.chartType --el-table-columnv-ifitem.visible:keyitem.propsecCode?Math.random():${item.prop}${item.label}:propitem.prop:labelitem.label:fixeditem.fixed:min-widthgetCellWidth(item,dataList):alignitem.align||left:show-overflow-tooltiptrue:sortableitem.sortabletemplate slotheaderel-tooltipv-ifitem.tipclassitemeffectdark:contentitem.tipplacementtop-startspanspan v-ifitem.valid stylecolor: #ec051b; font-size: 1.5em*/spanspan{{ item.label }}/spani classel-icon-question //span/el-tooltipspan v-elsespan v-ifitem.valid stylecolor: #ec051b; font-size: 1.5em*/spanspan{{ item.label }}/span/span/templatetemplate slot-scopescopeel-inputv-ifitem.inputType inputv-modelscope.row[item.prop]sizemini:placeholder$t(pleaseEnter):disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))changeonChange(scope.row,item)bluronBlur(scope.row,item)/el-input-numberv-else-ifitem.inputType numberv-modelscope.row[item.prop]sizemini:placeholder$t(pleaseEnter):precisionitem.keepDecimals:controlsitem.controls:minitem.min:maxitem.max:disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))changeonChange(scope.row,item)bluronBlur(scope.row,item)/el-selectv-else-ifitem.inputType selectv-modelscope.row[item.prop]:placeholder$t(pleaseSelect)sizemini:disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))click.nativelastValue scope.row[item.prop]changeonChange(scope.row,item)el-optionv-forite in scope.row[item.prop list] || []:keyite.value:labelite.label:valueite.value:disabledite.disabled//el-selectel-date-pickerv-else-ifitem.inputType datev-modelscope.row[item.prop]:formatitem.format||yyyy-MM-dd:value-formatitem.format||yyyy-MM-dd:typeitem.dateType||date:placeholder$t(pleaseSelect):disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))sizeminichangeonChange(scope.row,item)/el-switchv-else-ifitem.inputType switchv-modelscope.row[item.prop]:active-textitem.activeText:inactive-textitem.inactiveText:active-valueitem.activeValue:inactive-valueitem.inactiveValuechangeonChange(scope.row,item)/el-radio-groupv-else-ifitem.inputType radiov-modelscope.row[item.prop]:disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))changeonChange(scope.row,item)el-radiov-forite in scope.row[item.prop List] || []:keyite.value:disabledite.disabled:labelite.value{{ ite.label }}/el-radio/el-radio-groupel-checkboxv-else-ifitem.inputType checkbox scope.row[item.prop]!undefinedv-modelscope.row[item.prop]:disableditem.disabled||(scope.row.disabledscope.row.disabled.includes(item.prop))changeonChange(scope.row,item){{ scope.row[item.propLabel] }}/el-checkboxel-tagv-else-ifitem.tagTypeStyle:disable-transitionstrue:typeitem.tagTypeStyle(scope.row,scope.row[item.prop])||primary{{ formatter(scope.row, item) }}/el-tagrouter-linkv-else-if!item.columnTagText item.routerLink item.routerLink(scope.row)classdy-router-link:toitem.routerLink(scope.row)span{{ formatter(scope.row, item) }}/span/router-linkBarLineChartv-else-ifitem.chartType1 scope.row[item.prop]:dom-id${scope.row[item.chartKey]}${item.prop}:datascope.row[item.prop]height50pxbackground-colortransparent/!-- GridsBarLineChartv-else-ifitem.chartType2 scope.row.chartData:dom-id${scope.row[item.chartKey]}${item.prop}:datascope.row.chartDataheight50px/--divv-else-ifitem.columnTagText:classitem.class:styleitem.styleclickhandleClick(scope.row,item)div v-ifitem.routerLink item.routerLink(scope.row)router-link classdy-router-link :toitem.routerLink(scope.row)span{{ formatter(scope.row, item) }}/span/router-linkdiv stylemargin-top: -8px;el-tagv-ifitem.columnTagText(scope.row)typedangersizemini{{ item.columnTagText(scope.row) }}/el-tag/div/divdiv v-else{{ formatter(scope.row, item) }}/div/divspanv-else:classitem.class:styleitem.styleclickhandleClick(scope.row,item){{ formatter(scope.row, item) }}/span/template/el-table-column
/templatescript
import { moneyFormat, keepDecimals, isNumber } from /utils/utils
import Sortable from sortablejs
// 组件
import BarLineChart from /components/Echarts/BarLineChartexport default {components: {BarLineChart},props: {// 非必传只有存在多个表格时该参数作为表格的唯一标识主要用于拖拽tableSign: {type: String,default: null},// 所有的列字段用于拖拽schemas: {type: Array,default: () {return []}},// 不在schemas内并且在动态列之前的列数empty: {type: Number,default: 0},// 列字段item: {type: Object,default: () {return {}}},// 自定义格式化方法format: {type: Function,default: null},// 自定义格式化方法对应的字段formatColumns: {type: Function,default: () {return []}},// 表格数据dataList: {type: Array,default: () []}},data() {return {lastValue: undefined // 上次的值}},mounted() {// 表格拖拽方法if (this.schemas.length 0) {this.columnDrop()}},methods: {// 计算列宽因为element自适应的宽度还是存在部分字段名称换行情况所以需要重新计算getCellWidth(item, dataList) {const { label, width: defaultWidth } itemif (defaultWidth) {return defaultWidth}if (!label) {return 0}let renderTextMax if (dataList.length 0) {dataList.forEach((row) {// 取内容文本的最大值const renderText this.formatter(row, item) ?? this.calculateWidth(renderText) this.calculateWidth(renderTextMax) (renderTextMax renderText)})}// 取表头和内容文本的较大值this.calculateWidth(label) this.calculateWidth(renderTextMax) (renderTextMax label)let width 0const html document.createElement(span)html.innerText renderTextMaxhtml.className getTextWidthdocument.querySelector(body).appendChild(html)width document.querySelector(.getTextWidth).offsetWidthdocument.querySelector(.getTextWidth).remove()if (width 260) {return 280}return width 20},// 计算字符宽度calculateWidth(renderText) {let flexWidth 0for (let i 0; i String(renderText).length; i) {const char renderText[i]if ((char A char Z) || (char a char z)) {// 如果是英文字符为字符分配8个单位宽度flexWidth 8} else if (char \u4e00 char \u9fa5) {// 如果是中文字符为字符分配16个单位宽度flexWidth 16} else {// 其他种类字符为字符分配8个单位宽度flexWidth 8}}return flexWidth},// change事件向父组件传递字段和值onChange(row, item) {row.oldValue this.lastValue // 传选择之前的值this.setItemAndValue(this.$parent, row, item, columnChange)},// 点击事件icon点击向父组件传递对应的字段信息handleClick(row, item) {this.setItemAndValue(this.$parent, row, item, columnClick)},// 失去焦点事件icon点击向父组件传递对应的字段信息onBlur(row, item) {this.setItemAndValue(this.$parent, row, item, onBlur)},/*** function setItemAndValue 向父组件传递相应的字段和值* param {Object} parent 父组件原型* param {Object} item 字段信息* param {*} value 值* param {String} functionType 函数类型*/setItemAndValue(parent, row, item, functionType) {if (parent parent[functionType]) {parent[functionType](row, item)} else {if (parent.$parent) {this.setItemAndValue(parent.$parent, row, item, functionType)}}},// 格式化formatter(row, item) {// render优先级最高if (item.render) {return item.render(row, row[item.prop])}if (row[item.prop] null ||row[item.prop] undefined ||row[item.prop] ) {// value为0或者false还是照样原来显示return --}let value row[item.prop]if (this.format) {if (this.formatColumns.length 0 this.formatColumns.includes(item.prop)) {// 指定自定义格式化的字段return this.format(row, item, row[item.prop])} else {// 未指定的往下走value this.format(row, item, row[item.prop])}}if (isNumber(value)) {if (item.keepDecimals || item.keepDecimals 0) {// 保留小数位value keepDecimals(value, item.keepDecimals, item.division)}if (item.formatThousand) {value moneyFormat(value, item.division) // 千分位}if (item.unit) {// 是否带单位如万value value item.unit}}return value},/*** 列拖拽*/columnDrop() {// 页面多个表格 取到对应表格dom元素let wrapperClass .el-table__header-wrapperif (this.tableSign) {const elClass this.$parent.$el.getAttribute(class)if (!elClass.includes(this.tableSign)) {this.$parent.$el.setAttribute(class, ${elClass} ${this.tableSign})}wrapperClass .${this.tableSign} ${wrapperClass}}const wrapperTr document.querySelector(${wrapperClass} tr)this.sortable Sortable.create(wrapperTr, {animation: 100, // 过渡动画delay: 0, // 延迟多久可以拖动onEnd: (evt) {if (evt.oldIndex evt.newIndex) returnconst overviewColumns [...this.schemas]const visbleColumns overviewColumns.filter((v) v.visible) // 显示的列const empty this.empty // 不在schemas内并且在动态列之前的列数// 注意动态列表包含visible为false数据,需要进行特殊筛选处理const oldItem visbleColumns[evt.oldIndex - empty]const newItem visbleColumns[evt.newIndex - empty]const realOldIndex overviewColumns.findIndex((item) item.prop oldItem.prop)const realNewIndex overviewColumns.findIndex((item) item.prop newItem.prop)overviewColumns.splice(realOldIndex, 1) // 删除原来位置的数据overviewColumns.splice(realNewIndex, 0, oldItem) // 在新的位置插入该数据this.$emit(changeColumn, overviewColumns)}})}}
}
/script
style langscss scoped
.el-table__row .el-form-item {margin-bottom: 0px !important;
}.el-input,
.el-input.is-disabled,
.el-range-editor.el-input__inner,
.el-date-editor.el-input {width: 100%;
}::v-deep.el-select .el-input {width: 100%;
}::v-deep.el-input-number .el-input {width: 100%;
}
.el-input-number {width: 100%;
}.dy-router-link {color: #1890ff;display: inline-block;max-width: 100%;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;position: relative;:hover:after {content: ;position: absolute;top: 0;right: 0;bottom: 0;left: 0;border-bottom: 1px solid #1890ff;}
}::v-deep .el-table__row {border: 1px solid #1890ff;.el-table .cell.el-tooltip {display: flex;align-items: center;}
}
/style