flap2tree(arr, key = 'id', parentKey = 'pid') {
const result:any = [];
const mapObj = {};
const copyArr:any = [];
arr.forEach((item) => {
const newItem = { ...item };
copyArr.push(newItem);
mapObj[item[key]] = newItem;
});
copyArr.forEach((item) => {
const pid = item[parentKey];
let parent:any = null;
if (pid) {
parent = mapObj[pid];
if (parent) {
if (!parent.children) {
parent.children = [];
}
parent.children.push(item);
}
}
if (!parent) {
result.push(item);
}
mapObj[item[key]] = item;
});
return result;
}
// allMenuTreeData 树数据
// menuId 需要查找的节点
getFamilyData(allMenuTreeData, menuId) {
// 返回数据集合
const targetArr: any = [];
// 声明递归函数
const forFn = function(arr, id) {
// 遍历树
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (item.menuId.toString() === id.toString()) {
// 查找到指定节点加入集合
targetArr.push(item);
// 查找其父节点
forFn(allMenuTreeData, item.parentId);
// 不必向下遍历,跳出循环
break;
} else {
if (item.children) {
// 向下查找到id
forFn(item.children, id);
}
}
}
};
// 调用函数
forFn(allMenuTreeData, menuId);
// 返回结果
return targetArr;
}
<a-form-model
ref="gbFormRef"
:label-col="{span: 5}"
:wrapper-col="{span: 18}"
:model="gbForm"
:rules="gbFormRules">
<a-form-model-item>
<a-button
type="primary"
:loading="dialogLoading"
@click="submit()">
保存
a-button>
a-form-model-item>
a-form-model>
submit() {
(this.$refs.gbFormRef as any).validate((valid: any) => {
if (valid) {
// 校验成功
} else {
setTimeout(() => {
const isError:any = document.getElementsByClassName('has-error'); // antd为has-error
isError[0].querySelector('input').focus();
}, 1);
return false;
}
});
}
formRules = {
contactNo: [
{ required: true, message: '请输入联系人电话', trigger: 'blur' },
{ pattern: /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|16[0-9]|14[57])[0-9]{8}$/, message: '电话格式不正确', trigger: 'blur' }
],
telephone: [
{ required: false, message: '请输入联系方式', trigger: 'change' },
{
validator: this.telephoneValidate,
message: '请输入正确的手机号码',
trigger: 'change'
}
]
};
telephoneValidate = (rule, value, cb) => {
if (!value) {
return cb();
}
// 验证手机号的正则表达式
const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/;
if (regMobile.test(value)) {
return cb();
}
cb(new Error('请输入合法的手机号'));
}
fullscreen:false
screenShow() {
const element = this.$refs.dashboardRef; // 选中DOM
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
}
<style>
*::-webkit-scrollbar {
width: 6px;
height: 14px;
}
/*滚动条的滑轨背景颜色,可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果。*/
*::-webkit-scrollbar-track {
display: none;
background-color: #f5f5f5;
-webkit-box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
*::-webkit-scrollbar-thumb {
/* 滚动条 */
background-color: rgba(0, 0, 0, 0.2) !important;
border-radius: 5px;
}
*::-webkit-scrollbar-button {
/* 上下翻页的按钮 */
background-color: #eee;
display: none;
}
*::-webkit-scrollbar-corner {
background-color: black;
}
style>
dayjs().subtract(3, 'week').format('YYYY-MM-DD') //取前三个周的日期
dayjs().add(3, 'week').format('YYYY-MM-DD') //取三周以后的日期
.displayClass {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
在项目中使用
自身的上传功能时,会存在没有鉴权信息(请求不携带token)的问题,因此使用组件的customRequest 属性来解决。
customRequest:通过覆盖默认的上传行为,实现自定义自己的上传。
参考文献:
https://blog.csdn.net/qy8189/article/details/127547540
点此跳转
<a-upload
name="file"
accept=".xls,.xlsx"
:custom-request="uploadExecl"
>
<a-button
:loading="uploadLoading"
type="primary"
icon="upload"
>
<span v-if="uploadLoading">
导入中...
span>
<span v-else>
导入名单
span>
a-button>
a-upload>
uploadLoading: boolean = false
uploadExecl(info: any) {
// 使用提交form表单形式,渲染入参
const param: any = new FormData();
param.append('file', info.file);
param.append('orgId', '123456789');
this.uploadLoading = true;
uploadApi.uploadFile(param)
.then(res => {
this.$message.success('导入成功!')
this.uploadLoading= false;
})
.catch(err => {
this.uploadLoading= false;
this.$message.error(err);
});
}
exportByFileStream() {
exportApi.downExcel()
.then((res: any) => {
const filename = `人员导入模板.xls`;
const blob = new Blob([res], { type: 'application/octet-stream;' });
if ('download' in document.createElement('a')) {
const elink = document.createElement('a');
elink.download = filename;
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
} else {
(navigator as any).msSaveBlob(blob, filename);
}
})
.catch(err => {
this.$message.error(`下载失败:${err}`);
});
}
exportTable() {
if (this.selectedRowKeys.length === 0) {
this.$message.warn('请选择需要导出的数据!');
return;
}
const excelTitle = '预约列表';
const tHeader: any = [];
const filterVal: any = []; // 字段名称
this.columns.forEach(item => {
if (item.title !== '套餐项目') {
tHeader.push(item.title);
filterVal.push(item.dataIndex);
}
});
// selectedRows:选中的表格数据
const data = this.selectedRows.map(v => filterVal.map(j => v[j]));
import('@/utils/Export2Excel').then(excel => {
excel.export_json_to_excel({
header: tHeader, // 表头 可以指定表头,如['id','name']
data, // 表头所对应的数据 如['李四','张三']
filename: excelTitle // 文件标题
});
});
}
下载依赖xlsx、file-saver
npm i xlsx --save
npm i file-saver --save
新建文件 utils/Export2Excel
/* eslint-disable */
import { saveAs } from 'file-saver';
import XLSX from 'xlsx';
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
var ranges = [];
for (var R = 0; R < rows.length; ++R) {
var outRow = [];
var row = rows[R];
var columns = row.querySelectorAll('td');
for (var C = 0; C < columns.length; ++C) {
var cell = columns[C];
var colspan = cell.getAttribute('colspan');
var rowspan = cell.getAttribute('rowspan');
var cellValue = cell.innerText;
if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue;
//Skip ranges
ranges.forEach(function(range) {
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
}
});
//Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1;
colspan = colspan || 1;
ranges.push({
s: {
r: R,
c: outRow.length
},
e: {
r: R + rowspan - 1,
c: outRow.length + colspan - 1
}
});
}
//Handle Value
outRow.push(cellValue !== '' ? cellValue : null);
//Handle Colspan
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
}
out.push(outRow);
}
return [out, ranges];
}
function datenum(v, date1904) {
if (date1904) v += 1462;
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {};
var range = {
s: {
c: 10000000,
r: 10000000
},
e: {
c: 0,
r: 0
}
};
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C;
var cell = {
v: data[R][C]
};
if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({
c: C,
r: R
});
if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b';
else if (cell.v instanceof Date) {
cell.t = 'n';
cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
} else cell.t = 's';
ws[cell_ref] = cell;
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
return ws;
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook();
this.SheetNames = [];
this.Sheets = {};
}
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = 'SheetJS';
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
saveAs(
new Blob([s2ab(wbout)], {
type: 'application/octet-stream'
}),
'test.xlsx'
);
}
export function export_json_to_excel({ multiHeader = [], header, data, filename, merges = [], autoWidth = true, bookType = 'xlsx' } = {}) {
/* original data */
filename = filename || 'excel-list';
data = [...data];
data.unshift(header);
for (let i = multiHeader.length - 1; i > -1; i--) {
data.unshift(multiHeader[i]);
}
var ws_name = 'SheetJS';
var wb = new Workbook(),
ws = sheet_from_array_of_arrays(data);
if (merges.length > 0) {
if (!ws['!merges']) ws['!merges'] = [];
merges.forEach(item => {
ws['!merges'].push(XLSX.utils.decode_range(item));
});
}
if (autoWidth) {
/*设置worksheet每列的最大宽度*/
const colWidth = data.map(row =>
row.map(val => {
/*先判断是否为null/undefined*/
if (val == null) {
return {
wch: 10
};
} else if (val.toString().charCodeAt(0) > 255) {
/*再判断是否为中文*/
return {
wch: val.toString().length * 2
};
} else {
return {
wch: val.toString().length
};
}
})
);
/*以第一行为初始值*/
let result = colWidth[0];
for (let i = 1; i < colWidth.length; i++) {
for (let j = 0; j < colWidth[i].length; j++) {
if (result[j]['wch'] < colWidth[i][j]['wch']) {
result[j]['wch'] = colWidth[i][j]['wch'];
}
}
}
ws['!cols'] = result;
}
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {
bookType: bookType,
bookSST: false,
type: 'binary'
});
saveAs(
new Blob([s2ab(wbout)], {
type: 'application/octet-stream'
}),
`${filename}.${bookType}`
);
}
相比第一种更j简洁,代码量更少
npm install xlsx --save
import XLSX from 'xlsx';
exportExcel() {
if (!this.selectedRowsList || this.selectedRowsList.length === 0) {
this.$message.info('请选择导出人员!');
return;
}
const columns = this.column.filter((item: { exportFlag: any; }) => item.exportFlag).map((item: { title: any; }) => item.title)
const dataIndex = this.column.filter((item: { exportFlag: any; }) => item.exportFlag).map((item: { dataIndex: any; }) => item.dataIndex)
const data = this.selectedRowsList.map((v: { [x: string]: any; }) => dataIndex.map((j:any) => v[j]))
const param = [columns, ...data]
const excelName = '人员信息' + '.xlsx';
const ws = XLSX.utils.aoa_to_sheet(param);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, '人员信息');
XLSX.writeFile(wb, excelName);
}
原型以及数据结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/43ad2e3eceee4300a3b35ed642ece404.jpeg
exportData() {
if (this.selectedRowKeys.length === 0) return this.$message.warn('请勾选需要导出的数据!')
const selectedRowsList = this.tableData.filter(item => this.selectedRowKeys.findIndex((key: any) => key === item.ohOrderCheckId) > -1)
const columns = this.columns.map(item => item.title)
const parentDataIndex = this.columns.map((item: { dataIndex: any; }) => item.dataIndex)
const data:any = []
selectedRowsList.forEach(item => {
data.push(parentDataIndex.map((j:any) => item[j]))
if (item.children) {
const childDataIndex = this.childColumns.map((itm: any) => itm.dataIndex)
const cHeader = this.childColumns.map(itm => itm.title)
cHeader.unshift('')
data.push(cHeader)
item.children.forEach((cItem:any) => {
const cData = childDataIndex.map((j:any) => cItem[j])
cData.unshift('')
data.push(cData)
})
}
})
const param = [columns, ...data] //param数据结构如下图
console.log(param);
const excelName = '人员信息' + '.xlsx';
const ws = XLSX.utils.aoa_to_sheet(param);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, '人员信息');
XLSX.writeFile(wb, excelName);
}
columns = [
{
title: '登记状态',
dataIndex: 'regFlag',
customCell: (row:any) => {
return {
style: {
color: row.reviewStatus === 3 ? 'red' : ''
}
};
},
customRender: val => {
// customRender接收三个参数(val,row,index)
return val === 1 ? '已登记' : '未登记';
}
}
];
// 定义一个全局变量,存储重复的值,支持多列
temp:any ={}
columns = [
{
title: '性别',
dataIndex: 'sexName',
customRender: (value, row, index) => {
const obj = {
children: value,
attrs: {}
};
obj.attrs.rowSpan = this.mergeCells(row.sexName, this.tableData, 'sexName');
// 第一个参数:列对应的值
// 第二个参数:表格数据tableData
// 第三个参数:列名
return obj;
}
}
];
mergeCells(text, array, columns) {
// text:列对应的值 array:表格数据tableData columns:列名
let i = 0;
if (text !== this.temp[columns]) {
this.temp[columns] = text;
array.forEach(item => {
if (item[columns] === this.temp[columns]) {
i += 1;
}
});
}
return i;
}
<a-table
:row-class-name="row => (row.clicked ? 'selectedRowClass' : '')"
/>
.selectedRowClass {
background: #3b9dff5e;
}
.ant-table-tbody {
> tr:hover:not(.ant-table-expanded-row) > td,
.ant-table-row-hover,
.ant-table-row-hover > td {
background: #3b7cff !important;
}
}
.ant-table colgroup > col.ant-table-selection-col {
width: 45px;
}
const newData = resData.sort((item1, item2) => {
return item1.userName.localeCompare(item2.userName, 'zh');
})
renderPayUserData() {
const sortedArr = this.groupBy(this.selectedRows, item => {
return [item.groupId]; // 按照groupId进行分组
});
}
groupBy(array, f) {
const groups = {};
array.forEach(item => {
const group = JSON.stringify(f(item));
groups[group] = groups[group] || [];
groups[group].push(item);
});
return Object.keys(groups).map(group => {
return groups[group];
});
}
getUUid() {
let guid = '';
for (let i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
if (i === 8 || i === 12 || i === 16 || i === 20) {
guid += '-';
}
}
return guid;
}
使用场景:下拉框数据量大时,可只获取50条,通过输入关键词来调用接口来选择
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0;
}
<a-select
v-model="payForm.patName"
:show-search="true"
:not-found-content="null"
:filter-option="true"
@search="handleSearch"
@blur="handleBlur"
@change="handleChange"
>
<a-select-option
v-for="item of patNameList"
:key="item.patId"
:value="item.patName"
>
{{ item.patName }}
a-select-option>
a-select>
handleBlur(name) {
this.payForm.patName = name;
}
handleSearch(name) {
this.handleChange(name)
}
handleChange(value) {
this.healCertForm.healthOrgName = (value != null && value !== '') ? value : '' // 这里是重点
}
在这里插入代码片
<a-select
v-model="personListForm.industrialClassification"
show-search
:filter-option="false"
:not-found-content="workTypeLoading ? undefined : null"
@search="wokrTypeSelectSearch"
>
<a-spin
v-if="workTypeLoading"
slot="notFoundContent"
size="small" />
<a-select-option
v-for="d in industrialClassificationList"
:key="d.industryTypeId"
:value="d.industryTypeId">
{{ d.industryTypeName }}
a-select-option>
a-select>
wokrTypeSelectSearch(industryTypeName: any) {
this.workTypeLoading = true
basicMaintenance.dictIndustryType({
industryTypeName,
pageNum: 1,
pageSize: 100
})
.then((result:any) => {
this.industrialClassificationList = result.list
this.workTypeLoading = false
})
.catch(err => {
this.workTypeLoading = false
this.$message.error(`行业查询失败:${err}`)
})
}
文档地址 http://www.sortablejs.com/options.html
import Sortable from 'sortablejs'
mounted() {
this.initSortable()
}
initSortable() {
this.$nextTick(() => {
const el = document.querySelectorAll('.ant-table-tbody')[2]
// 创建拖拽对象
this.sortable = Sortable.create(el, {
sort: !this.tableCompDisabledFlag, // 是否可进行拖拽排序
animation: 150,// ms, number 单位:ms,定义排序动画的时间
// 拖拽完成,移除拖拽之前的位置上的元素,在拖拽之后的位置上添加拖拽元素
onEnd: ({ newIndex, oldIndex }) => {
// 注意:这里要直接操作原数据,不能深拷贝,否则存在缓存问题
// 业务代码自行忽略
const val = this.itemAdviceTableData[oldIndex]
this.itemAdviceTableData.splice(oldIndex, 1)
this.itemAdviceTableData.splice(newIndex, 0, val)
}
})
})
}
export function base64toFile(dataurl, filename = 'file') {
// base64转文件流 并下载
const arr = dataurl.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const suffix = mime.split('/')[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const file = new File([u8arr], `${filename}.${suffix}`, {
type: mime
})
// 下载文件流 ↓↓↓
const content = file;
const blob = new Blob([content], { type: 'application/octet-stream' });
if ('download' in document.createElement('a')) {
const elink = document.createElement('a');
elink.download = `${filename}.${suffix}`; // 文件名
elink.style.display = 'none';
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
}
}
解决a-moadal不可拖动、不可伸缩的问题
官方文档https://vxetable.cn/v3/#/table/module/modal
点此跳转
<vxe-modal
id="myModal6"
:value="true"
size="small"
:show-zoom="true"
resize
show-footer
fullscreen
esc-closable
width="70vw"
height="60vh"
remember
transfer
draggable
@hide="closeDialog"
@close="closeDialog"
>
<template #footer>
<a-button type="primary" @click="closeDialog">
关闭
a-button>
template>
<template #title>
总检诊台
template>
<template #default>
aaaaaaaa
template>
vxe-modal>
// @hide的作用是使用Esc方式退出时,会造成打不开的问题,所以需要对value绑定值进行重置
closeDialog() {
this.$emit('closeDetailDialog');
}
使用场景:解决数据量大,表格卡顿的问题
<vxe-table
:column-config="{resizable: true}"
ref="vxeTableRef"
class="vxeTableClass"
:data="peopleTableData"
:loading="peopleTableLoading"
:max-height="cardHeight - 190"
show-overflow
:row-class-name="rowClassName"
:row-config="{isHover: true}"
:checkbox-config="{trigger: 'row', highlight: false, range: false}"
@checkbox-all="selectAllEvent"
@checkbox-change="selectChangeEvent"
@cell-dblclick="dblClick"
>
<template #empty>
<a-empty />
template>
<vxe-table-column field="department" title="部门" width="110">
<template #default="{row}">
<a-tooltip>
<template slot="title">
{{ row.department }}
template>
<span class="displayClass">
{{ row.department }}
span>
a-tooltip>
template>
vxe-table-column>
vxe-table>
// API含义
@cell-dblclick="dblClick" //双击的回调
:column-config="{resizable: true}" // 列拖动
:max-height="cardHeight - 190" // show-overflow 两个组合使用,固定高度
:row-class-name="rowClassName" // 设置行的css样式,通过class名来进行修改 ->
:row-config="{isHover: true}" // 鼠标覆盖行变色
:checkbox-config="{trigger: 'row', highlight: false, range: false}" // 点击行选中,选中时高亮显示,按住ctrl可以拖动选中
@checkbox-all="selectAllEvent" // 全选按钮回调
@checkbox-change="selectChangeEvent" // 选择框 点击回调
<vxe-table
:span-method="mergeRowMethod"
>
mergeRowMethod({ row, _rowIndex, column, visibleData }) {
const fields = ['dept_name'];
const cellValue = row[column.property];
if (cellValue && fields.includes(column.property)) {
const prevRow = visibleData[_rowIndex - 1];
let nextRow = visibleData[_rowIndex + 1];
if (prevRow && prevRow[column.property] === cellValue) {
return { rowspan: 0, colspan: 0 };
} else {
let countRowspan = 1;
while (nextRow && nextRow[column.property] === cellValue) {
nextRow = visibleData[++countRowspan + _rowIndex];
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 };
}
}
}
}
transition-name=""
const arr = ['测试一', '测试二', '测试三'];
that.$message.open({
type: 'error',
content: h => {
return h(
'div',
{
domProps: {
innerHTML: arr.join('
')
}
},
[]
);
}
});
const arr = ['测试一', '测试二', '测试三'];
this.$confirm({
title: '是否继续操作?',
content: h => {
return h(
'div',
{
domProps: {
innerHTML: arr.join('
')
}
},
[]
);
},
onOk() {},
onCancel() {}
});
const echartBase64 = (document as any).getElementById('echartId').getElementsByTagName('canvas')[0].toDataURL()
<a-tooltip>
<span v-if="computeShowTip(inputContent)" slot="title">
{{ inputContent }}
span>
<input v-model="item4.inputContent" />
a-tooltip>
computeShowTip(inputContent){
const dom = document.createElement('span');
dom.style.display = 'inline-block';
dom.textContent = inputContent;
document.body.appendChild(dom);
const width = dom.clientWidth;
document.body.removeChild(dom);
return width >= 90 // 假设输入框的width:90px
}
使用场景:1、使用递归组件时,只能获取到第一次渲染的ref,后续递归出的组件或取不到,此时使用vue-ref插件。2、获取父子组件、兄弟组件的ref
// npm安装
npm install vue-ref --save
// main.js中
import ref from "vue-ref"
Vue.use(ref, { name: "ant-ref" }) // name是自定义api名称
父组件
provide() {
return {
setChildrenRef: (name, ref) => {
this.$set(this.domMap,name,ref)
},
getChildrenRef: name => {
return this[name];
}
}
},
data() {
return {
domMap: {}
}
}
子组件
<a-input v-model="input" v-ant-ref="dom => setChildrenRef('inpitItemRef', dom )" />
inject: ['setChildrenRef'], // 用到父组件的哪个方法就引用哪个
这样加载页面时,子组件中的v-ant-ref指令会调用父组件的方法,把子组件中的dom存储到父组件的domMap中.
vue-ref使用案例:点击链接跳转
<a-date-picker
v-model="searchForm.startRegTime"
:disabled-date="regDisabledStartDate"
/>
<a-date-picker
v-model="searchForm.endRegTime"
:disabled-date="regDisabledEndDate"
/>
regDisabledStartDate(startValue: any) {
const endValue = this.searchForm.endRegTime;
if (!startValue || !endValue) {
return false;
}
const data = new Date(endValue).getTime();
return data < startValue.valueOf();
}
regDisabledEndDate(endValue: any) {
const startValue = this.searchForm.startRegTime;
if (!startValue) {
return false;
}
const data = new Date(startValue).getTime();
return data >= endValue.valueOf();
}
eslint配置
{
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": false,
// 重新设定tabsize
"editor.tabSize": 2,
// #每次保存的时候自动格式化
// "editor.formatOnSave": true,
// #让prettier使用eslint的代码格式进行校验
// #去掉代码结尾的分号
"prettier.semi": false,
"prettier.trailingComma": "none",
// #使用带引号替代双引号
"prettier.singleQuote": true,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": false,
// #这个按用户自身习惯选择
"vetur.format.defaultFormatter.html": "js-beautify-html",
// #让vue中的js按编辑器自带的ts格式进行格式化
"vetur.format.defaultFormatter.js": "vscode-typescript",
"vetur.format.defaultFormatterOptions": {
"vetur.format.defaultFormatter.html": "js-beautify-html", //格式化.vue中html
"js-beautify-html": {
// "wrap_attributes": "aligned-multiple"
// "wrap_attributes": "force-expand-multiline" //属性强制换行对齐
// "wrap_attributes": "force-aligned" //属性强制折行对齐
}
},
"editor.suggestSelection": "first",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.fontLigatures": false,
"[vue]": {
"editor.defaultFormatter": "octref.vetur"
},
"workbench.colorTheme": "Monokai Dimmed+Vibrant", // 两个选择器中是否换行
/* 自定义主题颜色 */
"editor.tokenColorCustomizations": {
"[Monokai Dimmed+Vibrant]": {
"keywords": "#db00f8", //关键字
"types": "#42b983", //类型定义
"numbers": "#00e1ff", //数字
"textMateRules": [
{
"scope": "keyword.control", //if ,else, try 等控制符
"settings": {
"foreground": "#50c571",
"fontStyle": "italic bold "
}
},
{
"scope": "entity.name.tag",
"settings": {
// "foreground": "#ee258d",
"fontStyle": "bold italic"
}
},
{
"scope": "entity.other.attribute-name",
"settings": {
// "foreground": "#0066ff",
"fontStyle": "bold italic"
}
},
{
"scope": "variable.other.object",
"settings": {
"foreground": "#0099ff",
"fontStyle": ""
}
},
{
"scope": "keyword.operator",
"settings": {
// "foreground": "#fa3434",
// "fontStyle": "bold",
}
}
]
// "variables": "#9814ef",//变量
// "comments": "#beb9b9" //注释
// "functions": "#f10070f5",//函数
// "strings": "#e72499", // 字符串的颜色,
}
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "mohd-akram.vscode-html-format"
},
"[less]": {
"editor.defaultFormatter": "vscode.css-language-features"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// "editor.smoothScrolling": true, //使编辑器滚动变平
// 自定义vscode面板颜色
"workbench.colorCustomizations": {
// "tab.activeBackground": "#253046", // 活动选项卡的背景色
// "activityBar.background": "#253046", //活动栏背景色
// "sideBar.background": "#253046", //侧边栏背景色
// "activityBar.foreground": "#23f8c8", //活动栏前景色(例如用于图标)
// "editor.background": "#292a2c", //编辑器背景颜色
// "editor.foreground":"#ff0000", //编辑器默认前景色
// "editor.findMatchBackground":"#f83123", //当前搜索匹配项的颜色
// "editor.findMatchHighlightBackground":"#43ac93", //其他搜索匹配项的颜色
// "editor.lineHighlightBackground":"#ff0000", //光标所在行高亮文本的背景颜色
// "editor.selectionBackground":"#d3fd84", //编辑器所选内容的颜色
// "editor.selectionHighlightBackground":"#ff0000", //与所选内容具有相同内容的区域颜色
// "editor.rangeHighlightBackground":"#ff0000", //突出显示范围的背景颜色,例如 "Quick Open" 和“查找”功能
// "editorBracketMatch.background":"#edfc6a98", //匹配括号的背景色
// "editorCursor.foreground":"#ff0000", //编辑器光标颜色
// "editorGutter.background":"#ff0000", //编辑器导航线的背景色,导航线包括边缘符号和行号
// "editorLineNumber.foreground":"#ff0000", //编辑器行号颜色
// "sideBar.foreground":"#ff0000", //侧边栏前景色
// "sideBarSectionHeader.background":"#ff0000", //侧边栏节标题的背景颜色
// "statusBar.background":"#ff0000", //标准状态栏背景色
// "statusBar.noFolderBackground":"#ff0000", //没有打开文件夹时状态栏的背景色
// "statusBar.debuggingBackground":"#ff0000", //调试程序时状态栏的背景色
// "tab.activeForeground":"#ff0000", //活动组中活动选项卡的前景色
// "tab.inactiveBackground":"#ff0000", //非活动选项卡的背景色
// "tab.inactiveForeground":"#ff0000" // 活动组中非活动选项卡的前景色
},
}
eslintrc
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true
},
extends: ['eslint:recommended', 'plugin:vue/recommended', '@vue/standard', '@vue/typescript'],
rules: {
'camelcase': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'off' : 'off',
'no-prototype-builtins': 'off',
'no-unused-vars': 'off',
semi: 'off',
'space-before-function-paren': [2, 'never'],
// 'vue/html-closing-bracket-newline': 'off',
'vue/html-self-closing': 'off',
'vue/no-v-html': 'off',
'vue/array-bracket-spacing': 'error',
'vue/arrow-spacing': 'error',
'vue/block-spacing': 'error',
'vue/brace-style': 'error',
'vue/camelcase': 'error',
'vue/comma-dangle': 'error',
'vue/component-name-in-template-casing': 'error',
'vue/eqeqeq': 'error',
'vue/key-spacing': 'error',
'vue/match-component-file-name': 'error',
'vue/object-curly-spacing': 'error',
"vue/max-attributes-per-line": ["error", {
"singleline": 2,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/html-indent": ["error", 2, {
"attribute": 1,
"baseIndent": 1,
"closeBracket": 0,
"alignAttributesVertically": true,
"ignores": []
}],
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }]
},
globals: {
_: true,
dayjs: true,
$: true,
echarts: true,
Echarts: true
},
parserOptions: {
parser: '@typescript-eslint/parser'
},
overrides: [
{
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
env: {
jest: true
}
}
],
ignorePatterns: ['src/assets/font/iconfont.js']
};