# element
# el-input
禁止输入时有的颜色不同一,在disabled状态里修改。
::v-deep input[disabled],input:disabled,input.disabled{
-webkit-text-fill-color:#606266;
background: #F5F7FA;
-webkit-opacity:1;
opacity: 1;
cursor: not-allowed;
}
# 表格 el-table
<el-table border class="table" :data="tableData" style="width: 100%" stripe>
<!-- <el-table-column type="selection" width="55" ></el-table-column> 加多选框-->
<!-- 如果要给数据加序号type="index" -->
<el-table-column type="index" label="序号" sortable :width="80">
</el-table-column>
<el-table-column prop="synCount" label="同步条数" >
</el-table-column>
<el-table-column prop="synStatus" label="同步状态" :min-width="180" >
<!-- 将数据转化格式 -->
<template slot-scope="scope">
{{scope.row.synStatus | formatStatus}}
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<!-- handlecheck中的参数,操作相应的行 -->
<el-button
type="text"
icon="el-icon-edit"
@click="handlecheck(scope.$index, scope.row)">
导出
</el-button>
</template>
</el-table-column>
</el-table>
filters: {
formatType: function (val) {
console.log(val)
return val ==0?'天机同步数据':val==1?'蚂蚁同步数据':'银行同步数据'
// return val == 0 ? '激活' : val == 2 ? '未激活' : '未知';
}
提示
- 在表格中,:data=tabledata,把tabledata赋给表格
- el-table-column来接受数据,prop为接受的参数名,如name等,如果要给表格加个序号,则是使用type=“index”来获取
- 需要转化的值用template包裹,并且加上slot-scope='scope'
- 在操作对应行的数据也要加上上述内容,并且可以传参,对应的index用scope.$index来获取,而具体的内容信息scope.row可以获取
# table中的formatter
用来格式化内容:Function(row, column, cellValue, index)
<el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"></el-table-column>
statusFormat(row, column) {
if(row.status === 'OK'){
return '正常'
}else if(row.status === 'DISABLE'){
return '停用'
}
},
# 表格多选时数据接收
<el-table
ref="multipleTable"
:data="tableData"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
@select="onRowClick"
>
<el-table-column
fixed
type="selection"
width="55"
/>
<el-table-column
label="设备类型"
width="120"
prop="deviceType"
>
</el-table-column>
<el-table-column
prop="name"
label="状态/启用状态"
width="120"
>
<template slot-scope="scope">{{ scope.row.onlineState }} / {{ scope.row.state }} </template>
</el-table-column>
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width operationBtn" fixed="right">
<template slot-scope="{row}">
<el-button size="mini" type="primary" class="btn" @click="handerQuery(row)">查看</el-button>
<el-button size="mini" type="danger" class="btn" @click="handerSolve(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
handleSelectionChange(val) {
console.log(val)
this.multipleSelection = val
}
onRowClick(val,select){
console.log(val,select)
}
提示
elemnt中el-table使用多选框时,select方法与selection-change
- select:当用户手动勾选数据行的CheckBox时,触发的事件,参数:selection,row
- selection-change:当选项发生变化时会触发该事件,参数:selection
可以定义好这两个方法打印下看看什么时候会触发
- 当勾选住一个选项时,两个方法都会触发,当勾选全选时,只有selection-change方法触发,
- 两个方法传递的selection参数就是:渲染该行的对象数据
# el-table表格某一行默认高亮和取消
<el-table
:data="tableData"
style="width: 100%;height='400px'"
@row-click="handle"
highlight-current-row
ref='table'
></el-table
- 手动取消
this.$refs.table.setCurrentRow(-1);
- 自定义高亮颜色
/* 用来设置当前页面element全局table的内间距 */
.el-table__row td{
padding: 0;
}
/* 用来设置当前页面element全局table 选中某行时的背景色*/
.el-table__body tr.current-row>td{
background-color: #f19944 !important;
/* color: #f19944; */ /* 设置文字颜色,可以选择不设置 */
}
/* 用来设置当前页面element全局table 鼠标移入某行时的背景色*/
.el-table--enable-row-hover .el-table__body tr:hover>td {
background-color: #f19944;
/* color: #f19944; */ /* 设置文字颜色,可以选择不设置 */
}
# 表格多选默认选中某些数据
- 利用toggleRowSelection
enterpriseSystemList(data).then(res => {
console.log(res);
this.queryArr = res.data;
this.queryArr.forEach((item, index) => {
if (item.isSelect == 1) {
// 等表格数据加载完成后
this.$nextTick(() => {
// 注意:toggleRowSelection(item, true) 中 item 必须是行数据
this.$refs.multipleTable.toggleRowSelection(this.queryArr[index], true)
this.systemIds.push(this.queryArr[index].systemId)
})
}
})
});
# 合并表格需求
- 先将获取的数据按名称排序 mysort方法
- 合并单元格,利用span-method方法
<template>
<div>
<el-table
:data="tableData"
border
:span-method="firstSpanMethod"
style="width: 100%; margin-top: 20px"
>
<el-table-column
prop="functions"
label="功能"
width="180"
align="center"
/>
<el-table-column
prop="topic"
label="topic类"
/>
<el-table-column
prop="operateType"
label="操作权限"
width="180"
align="center"
/>
<el-table-column
prop="topicDesc"
label="描述"
/>
</el-table>
</div>
</template>
<script>
import { productTopic } from '@/api/IOT-product'
export default {
data() {
return {
tableData: [],
spanArr:[]
}
},
mounted() {
productTopic(data).then(res => {
this.tableData = res.data//即为下方的json内容
const data=res.data;
this.tableData.sort(mysort)
function mysort(a,b){
if(a.functions !== b.functions){
return a.functions < b.functions ? -1 : 1;
}
}
let contactDot = 0;
let spanArr = [];
this.tableData.forEach((item, index) => {
if (index === 0) {
console.log(spanArr)
spanArr.push(1)
} else {
if (item.functions === this.tableData[index - 1].functions) {//对比functions字段
spanArr[contactDot] += 1;
spanArr.push(0)
} else {
contactDot = index
spanArr.push(1)
}
}
})
this.spanArr = spanArr;
console.log(spanArr)//[4, 0, 0, 0, 1, 2, 0, 2, 0, 4, 0, 0, 0, 3, 0, 0, __ob__: Observer]
})
},
methods: {
firstSpanMethod:function ({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {//表示是要对第一行的内容进行合并
if(this.spanArr[rowIndex]){
return {
rowspan:this.spanArr[rowIndex],
colspan:1
}
}else{
return {
rowspan: 0,
colspan: 0
}
}
}
}
}
}
</script>
{
"data": [{
"functions": "时钟同步",
"id": "2510248f1a46ea11e27d5f75cfb82b27",
"operateType": "发布",
"productId": "",
"topic": "/ext/ntp/request/测试产品/{deviceName}",
"topicDesc": "NTP 时钟同步请求"
}, {
"functions": "时钟同步",
"id": "2971dc4e42b2c6047b5fb5eb91c496f1",
"operateType": "订阅",
"productId": "",
"topic": "/ext/ntp/response/测试产品/{deviceName}",
"topicDesc": "NTP 时钟同步响应"
}, {
"functions": "OTA 升级",
"id": "3cb1a467f0b8b09b2e7ebb8699fa100b",
"operateType": "订阅",
"productId": "",
"topic": "/ota/device/upgrade/测试产品/{deviceName}",
"topicDesc": "固件升级信息下行"
}, {
"functions": "配置更新",
"id": "46354b12039773dacedeeb89e8dcf9ef",
"operateType": "订阅",
"productId": "",
"topic": "/sys/thing/config/push/测试产品/{deviceName}",
"topicDesc": "云端主动下推配置信息"
}, {
"functions": "设备标签",
"id": "467f8955b71f76bc349eb1ffcdd42e9a",
"operateType": "订阅",
"productId": "",
"topic": "/sys/thing/deviceinfo/update_reply/测试产品/{deviceName}",
"topicDesc": "云端响应标签上报"
}, {
"functions": "OTA 升级",
"id": "546a1d5aeae09f07585e1a2a63b7ffae",
"operateType": "发布",
"productId": "",
"topic": "/ota/device/progress/测试产品/{deviceName}",
"topicDesc": "设备上报固件升级进度"
}, {
"functions": "设备标签",
"id": "655773f50f706c52e16bda8821804e6a",
"operateType": "发布",
"productId": "",
"topic": "/sys/thing/deviceinfo/update/测试产品/{deviceName}",
"topicDesc": "设备上报标签数据"
}, {
"functions": "OTA 升级",
"id": "6e3aedecae8c9ce5ebb747b0528558da",
"operateType": "发布",
"productId": "",
"topic": "/ota/device/request/测试产品/{deviceName}",
"topicDesc": "设备主动拉取固件升级信息"
}, {
"functions": "设备影子",
"id": "7926c826a3712f64b9c9a99a1122a735",
"operateType": "订阅",
"productId": "",
"topic": "/shadow/get/测试产品/{deviceName}",
"topicDesc": "设备接收影子变更"
}, {
"functions": "OTA 升级",
"id": "a54490fe3732362e46050ad0a62cef2b",
"operateType": "发布",
"productId": "",
"topic": "/ota/device/inform/测试产品/{deviceName}",
"topicDesc": "设备上报固件升级信息"
}, {
"functions": "配置更新",
"id": "c04f705cacbeaea439ef1e1f722874b6",
"operateType": "发布",
"productId": "",
"topic": "/sys/thing/config/get/测试产品/{deviceName}",
"topicDesc": "设备端查询配置信息"
}, {
"functions": "广播",
"id": "cb7da6efbece17fca14c8a6a89f69a49",
"operateType": "订阅",
"productId": "",
"topic": "/broadcast/测试产品/{deviceName}",
"topicDesc": "广播 Topic,identifier 为用户自定义字符串"
}, {
"functions": "设备影子",
"id": "cdd4262b2b0b0706fc5f5a0dae3f33b5",
"operateType": "发布",
"productId": "",
"topic": "/shadow/update/测试产品/{deviceName}",
"topicDesc": "设备影子发布"
}, {
"functions": "配置更新",
"id": "f1490880ea0a43b6af466e99a45954d0",
"operateType": "订阅",
"productId": "",
"topic": "/sys/thing/config/get_reply/测试产品/{deviceName}",
"topicDesc": "云端响应配置信息"
}, {
"functions": "设备标签",
"id": "f44b9e061ead5540a92a4dfcb4344281",
"operateType": "订阅",
"productId": "",
"topic": "/sys/thing/deviceinfo/delete/测试产品/{deviceName}",
"topicDesc": "设备删除标签信息"
}, {
"functions": "设备标签",
"id": "f4ea190ac420b851af68719bee662855",
"operateType": "发布",
"productId": "",
"topic": "/sys/thing/deviceinfo/delete_reply/测试产品/{deviceName}",
"topicDesc": "云端响应标签删除"
}],
"loggerParams": null,
"returnCode": "0",
"returnMsg": "success",
"success": true
}
# 合并表格多表格多层级合并功能
:span-method="(val)=>{return firstSpanMethod(val,index)}" 多个表格处理,因为表格是动态的,所以不可能为每个合并行列的方法添加方法,需要封装一层
return返回对应的函数
- 递归给数据补充层级id和name(如No1id,No1),后续展示需要依赖这两个变量
- 数据返回的格式是树状结构,而不是扁平式,所以需要打平
- 合并第五层级,因为第五层级是需要当成数组去处理,btnArr
- 因为第五层级的直系父级不一定是第四级,所以还需要先判断
- 填充数据,同时使用合并行的方法
<template>
<div class="jp_card_container">
<div v-loading="loading" class="container">
<div class="container_item" v-if="userPermissionFun(['personInformation:message'])">
<little-title title="权限信息" class="mb24" />
<div class="myquanxian">
<template v-for="(qxArrchild,index) in qxArr">
<div class="tableheader" :key="index+'header'">{{ qxArr[index][0].No1 }}</div>
<el-table
:data="qxArrchild"
:show-header="false"
border
:key="index"
:span-method="(val)=>{return firstSpanMethod(val,index)}"
>
<el-table-column prop="No2" :formatter="formatter" />
<el-table-column prop="No3" :formatter="formatter" />
<el-table-column prop="No4" :formatter="formatter" />
<el-table-column min-width="300">
<template slot-scope="{row}">
<template v-if="row.btnArr&&row.btnArr.length">
<a v-for="(item,idx) in row.btnArr" :key="idx" style="margin-right:10px">
<el-checkbox checked disabled />
<span>
{{ item.No5 }}
</span>
</a>
</template>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
import { checkPermi } from '@/utils/permission' // 权限判断函数
import { getUserProfile, updateUserProfile } from '@/api/system/userApi'
import { validEmail, validTelPhone, validNum, validUnChinese } from '@/utils/validate'
import PasswordChange from '@/layout/components/PasswordChange/index'
import { getMenuInfoforUser } from '@/api/system/menuApi.js'
export default {
name: 'Profile',
components: { PasswordChange },
data() {
return {
qxArr: [],
qxidArr: [],
btnLoading: false,
colArr: []
}
},
created() {
this.getUser()
getMenuInfoforUser().then(res => {
console.log(res)
// 添加level
const arr = res.data && res.data.menus
arr.forEach((el, index) => {
el.level = 1
el.No1 = el.label
el.No1id = el.id
const children = el.children
this.digui(children, 2)
})
// const temArr = []
arr.forEach((el, index) => {
this.dp(el)
})
console.log(arr)
// 合并最后一个层级
const reduceArr = []
arr.forEach((el, index) => {
if (el.children) {
this.mergeFun(reduceArr, el.children, index)
} else {
// 如果没有子元素,那么就直接赋值
reduceArr[index] = [{ No1: el.No1, No1id: el.No1id }]
}
})
this.qxArr = reduceArr
console.log(this.qxArr)
// 合并纵向列
if (this.qxArr.length) {
this.mergeCol(this.qxArr, 0)
}
})
},
methods: {
checkPermi,
digui(value, index) {
if (value instanceof Array) {
} else {
return
}
value.forEach((el, i) => {
if (el.children) {
el.level = index
if (index === 2) {
el.No2 = el.label
el.No2id = el.id
} else if (index === 3) {
el.No3 = el.label
el.No3id = el.id
} else if (index === 4) {
el.No4 = el.label
el.No4id = el.id
} else if (index === 5) {
el.No5 = el.label
el.No5id = el.id
}
this.digui(el.children, index + 1)
} else {
el.level = 5
el.No5 = el.label
el.No5id = el.id
}
})
},
// 通过列表而来的el,一级权限,el.childrem二级权限
dp(el, val = 0) {
if (el.children) {
const myarr = []
const temobj0 = {}
for (const i in el) {
if (i.includes('No')) {
temobj0[i] = el[i]
}
}
let istrue = false
// if (true) {
el.children.forEach((e, index) => {
const temobj = {}
for (const i in e) {
if (i.includes('No')) {
temobj[i] = e[i]
}
}
if (e.children) {
e.children.forEach((echild, idx1) => {
myarr.push({ ...temobj0, ...temobj, ...echild })
})
istrue = true
} else {
myarr.push({ ...temobj0, ...temobj })
}
})
el.children = myarr
if (istrue) {
const s = el.children.some(e => e.children)
if (s) {
this.dp(el)
}
}
}
},
fatherId(v) {
// console.log(v)
if (v.No4) {
return 'No4id'
} else if (v.No3) {
return 'No3id'
} else if (v.No2) {
return 'No2id'
} else {
return 'No1id'
}
},
mergeFun(reduceArr, originArr, idx, num = 0) {
// reduceArr[idx]
// originArr[0]
const tem = this.fatherId(originArr[0])
if (!num) {
reduceArr[idx] = []
}
reduceArr[idx][num] = {
No1: originArr[0].No1,
No1id: originArr[0].No1id,
No2: originArr[0].No2,
No2id: originArr[0].No2id,
No3: originArr[0].No3,
No3id: originArr[0].No3id,
No4: originArr[0].No4,
No4id: originArr[0].No4id,
btnArr: []
}
const temId = originArr[0][tem]
const delArr = []
originArr.forEach((el, index) => {
if (el[tem] === temId) {
reduceArr[idx][num].btnArr.push({ No5: el.No5, No5id: el.No5id })
delArr.push(el.No5id)
}
})
originArr = originArr.filter(e => {
return !delArr.includes(e.No5id)
})
if (originArr[0]) {
this.mergeFun(reduceArr, originArr, idx, num + 1)
}
},
formatter(row, column, cellValue) {
if (cellValue === '0' || cellValue === 0) {
return cellValue
}
if (!cellValue) {
return '-'
} else {
return cellValue
}
},
// 合并列计算
mergeCol(qxArr, i) {
let contactDot = 0
let contactDot1 = 0
const spanArr = []
const spanArr1 = []
qxArr[i].forEach((item, index) => {
if (index === 0) {
// console.log(spanArr)
spanArr.push(1)
} else {
if (item.No2id === qxArr[i][index - 1].No2id) {
spanArr[contactDot] += 1
spanArr.push(0)
} else {
contactDot = index
spanArr.push(1)
}
}
})
qxArr[i].forEach((item, index) => {
if (index === 0) {
spanArr1.push(1)
} else {
if (item.No3id === qxArr[i][index - 1].No3id && (item.No3id !== undefined)) {
spanArr1[contactDot1] += 1
spanArr1.push(0)
} else {
contactDot1 = index
spanArr1.push(1)
}
}
})
this.colArr.push([spanArr, spanArr1])
if (qxArr.length - 1 > i) {
this.mergeCol(qxArr, i + 1)
}
// console.log(this.colArr)
},
// 合并列
firstSpanMethod: function(val, index) {
// console.log(rowIndex, columnIndex,val1)
// console.log(val,val1)
const { rowIndex, columnIndex } = val
// console.log(val, rowIndex)
if (columnIndex === 0) { // 表示是要对第一行的内容进行合并
if (this.colArr[index][0][rowIndex]) {
return {
rowspan: this.colArr[index][0][rowIndex],
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
if (columnIndex === 1) { // 表示是要对第一行的内容进行合并
if (this.colArr[index][1][rowIndex]) {
return {
rowspan: this.colArr[index][1][rowIndex],
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
}}
</script>
<style lang="scss" scoped>
.jp_card_container {
display: flex;
align-items: flex-start;
.container {
margin-left: 31px;
width: 100%;
padding-right: 56px;
box-sizing: border-box;
justify-content: flex-start;
&_item {
position: relative;
}
}
}
.mytable{
border-collapse:collapse;
border-spacing:0;
border:1px solid #E8E8E8;
width:100%;
font-size:14px;
color:#333;
}
.mytable tr{
height:40px;
width: 100% !important;
}
.mytable td{
border:1px solid #E8E8E8;
padding-left:12px;
}
.tableheader{
padding-left:12px;
font-size:14px;
font-weight: bold;
color:#333;
height:40px;
line-height: 40px;
background: #F9F9FB;
border-left:1px solid #dfe6ec;
border-right:1px solid #dfe6ec;
// border-top:none ;
&:hover{
background: #F7F9FB
}
}
::v-deep .el-checkbox__input.is-disabled .el-checkbox__inner{
border-color:#999;
background: #f9f9fa;
}
::v-deep .el-checkbox__input.is-disabled .el-checkbox__inner::after{
border-color:#666
}
::v-deep .myquanxian .tableheader:first-of-type{
border-top:1px solid #dfe6ec;
}
</style>
# el-table页面切换对不齐解决办法
场景:
//重新渲染这个el-table,使用内置doLayout,或者还有更合理解决方案
this.$refs.tableRef.doLayout();
# 表格选中功能设置部分禁用 selectable
<template>
<el-table
:data="arr"
@selection-change="handleSelectionChange"
>
<!-- align="center" :整列都居中,要不然有轻微的偏移 -->
<el-table-column
fixed
type="selection"
width="50"
class="jp_table"
align="center"
:selectable='checkboxT'
/>
<el-table-column label="序号" prop="x" width="50"/>
</el-table>
</template>
<script>
export default {
data(){
return{
arr: [{ x: 3,status:0 }, { x: 1 ,status:0}, { x: 1 ,status:1}, { x: 1 ,status:0}, { x: 1 ,status:0}],
}
},
methods: {
handleSelectionChange(v){
console.log(v)
},
checkboxT(row,index){
if(row.status==0){
return 1;
}else{
return 0;
}
}
},
}
</script>
# table分页记住选择
一般来说勾选后,点下一页,上一页的所选中的东西都会被清空。
在el-table中添加: row-key="getId"
然后第一列,即有多选框的一列,添加: reserve-selection="true" (注意 type="selection" 必须这样写)
<el-table
ref="form"
:model="form"
:row-key="getId"
<el-table-column type="selection" :reserve-selection="true">
</el-table-column>
</el-table>
在methods中添加函数:
getId(row) {
return row.id //这个id需要换成自己所绑定的Key
}
完成后需要清空选中,不然会在下一个批量操作中记录上一次选中的数据
this.$nextTick(()=>{
this.$refs.form.clearSelection()
})
# el-table有层级
- default-expand-all:默认层级全部展开
- :tree-props:绑定层级元素,children指向children1,tableData返回的子元素有children1数组,
hasChildren去掉未报错,加不加都可以呈现效果,暂时不知作用。 - 默认是第一列,显示折叠展开的符号 通过 type="" 来指定拿列显示 符号,比如 想指定第4列,就把前边3列都加上 type =""
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
default-expand-all
:tree-props="{children: 'children1', hasChildren: 'hasChildren'}">
# el-table伸缩与flex布局的问题
如果页面采取的是flex布局,左边一块固定,右边flex:1,然后在右边写了个table,那么当页面扩展时,表格会扩大,当页面缩小时,表格间距不会变化。可以考虑用float布局尝试改变这种现状
# el-table动态生成
<template>
<div class="wrap">
<el-table
v-loading="listLoading"
ref="multipleTable"
class="jp_table"
height="calc(100% - 112px)"
:data="arr"
stripe
>
<el-table-column label="序号" type="index" width="80" align="center">
<template scope="scope">
<span>{{ (pageNo - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column
v-for="col in tagarr"
:key="col.label"
:prop="col.props"
:label="col.label"
:width='col.width'
:formatter="formatter"
:show-overflow-tooltip="true"
>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
props: {
arr: {
type: Array,
default: () => {
return []
}
},
tagarr:{
type:Array,
default:()=>[]
},
listLoading:{
type:Boolean,
default:false
}
},
data() {
return {
pageNo: 1,
pageSize: 10
}
},
watch:{
arr(){
this.$nextTick(()=>{
this.$refs.multipleTable.doLayout()
})
}
}
}
</script>
arr: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}]
cols: [
{prop: 'date', label: '日期'},
{prop: 'name', label: '姓名'},
]
# el-table 合计
- 添加show-summary,会自动合计该行数据
<el-table
show-summary
>
</el-table>
- 自定义合计
<template>
<el-table
v-loading="loading"
id="drag-table"
ref="table"
:data="data"
:height="theight"
:summary-method="getSummaries"
show-summary
resizable
border
style="width: 100%"
/>
</template>
props:{
// 后台返回的合计信息
totalData1:{
type:Object,
default:_=>{}
}
},
getSummaries(val){
this.val =val
// colums:列 data数据
const {columns, data} =val
// 解决elementUI table合计行初始页面不显示问题 this.height由父组件传递过来 this.theight未表格绑定的高度
//延时执行 要不然会一直刷新
/*window.setTimeout(() => {
if (this.theight === this.height) {
this.theight -= 0.5
} else {
this.theight = this.height
}
}, 1000)
*/
const sums = [];
columns.forEach((column, index) => {
console.log(column.property)// 列表字段名称
switch (column.property) {
case undefined:
sums[index] = '总计'
break;
case 'buildingArea':
sums[index] = this.totalData1.buildingArea||'-'
break;
case 'useStatus':
sums[index] = (this.totalData1.useStatus||'-') + '个已入住'
break;
default:
sums[index] = '-'
break;
}
});
return sums;
}
getSummaries(val){
const {columns, data} =val
console.log(columns,data)
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "总计";
// index 表示表格的第几列开始计算
} else if (index === 6) {
const values = data.map((item) => Number(item[column.property]));
if (!values.every((value) => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return Number(prev.toFixed(2)) + curr;
} else {
return prev;
}
}, 0);
} else {
sums[index] = "1000";
}
} else {
sums[index] = "--";
}
});
return sums;
}
# el-table的大数据不卡顿
- 借助padding的实现一种方法
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container {
width: 300px;
height: 600px;
overflow: auto;
border: 1px solid;
margin: 100px auto;
}
.item {
height: 29px;
line-height: 30px;
border-bottom: 1px solid #aaa;
padding-left: 20px;
}
</style>
</head>
<body>
<div id="app">
<button @click="add">增加</button>
<div class="container" ref="container">
<div class="scroll-wrapper" :style="style">
<div v-for="(item, index) in scrollList" :key="index" class="item">{{item}}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#app',
data: {
list: [
'测试数据'
],
startIndex: 0,
endIndex: 60,
paddingTop: 0,
paddingBottom: 0,
allHeight: 0
},
computed: {
scrollList() {
return this.list.slice(this.startIndex, this.endIndex)
},
style() {
return {
paddingTop: this.paddingTop + 'px',
paddingBottom: this.paddingBottom + 'px'
}
}
},
watch: {
list(val) {
const valLen = val.length
this.allHeight = valLen * 30
this.paddingBottom = this.allHeight - this.scrollList.length * 30
}
},
mounted() {
const container = this.$refs.container
container.addEventListener('scroll', () => {
const top = container.scrollTop
this.startIndex = Math.floor(top / 30)
this.endIndex = this.startIndex + 21
this.paddingTop = top
if (this.endIndex >= this.list.length - 1) {
this.paddingBottom = 0
return
}
console.log(this.paddingBottom)
this.paddingBottom = this.allHeight - 600 - top
})
},
methods: {
add() {
let arr = new Array(50000).fill(0)
arr = arr.map((item, index) => {
return index
})
this.list = [
...this.list,
...arr
]
}
}
})
</script>
</body>
</html>
# el-transfer 穿梭框
# el-transfer和el-table结合来控制字段显示隐藏
| 事件名称 | 说明 | 回调参数 |
|---|---|---|
| change | 右侧列表元素变化时触发 | 当前值、数据移动的方向('left' / 'right')、发生移动的数据 key 数组 |
| left-check-change | 左侧列表元素被用户选中 / 取消选中时触发 | 当前被选中的元素的 key 数组、选中状态发生变化的元素的 key 数组 |
| right-check-change | 右侧列表元素被用户选中 / 取消选中时触发 | 当前被选中的元素的 key 数组、选中状态发生变化的元素的 key 数组 |
<el-dialog :title="title" :visible.sync="open" append-to-body>
<el-transfer
:titles="['显示', '隐藏']"
v-model="value"
:data="columns"
@change="dataChange"
></el-transfer>
</el-dialog>
// 右侧列表元素变化
dataChange(data) {
for (var item in this.columns) {
const key = this.columns[item].key;
this.columns[item].visible = !data.includes(key);
}
}
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
</el-table>
# 分页器 Pagination
<el-pagination
background
:current-page.sync="currentPage1"
:page-size="pageSize"
layout="sizes, prev, pager, next,total"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
// 换每页多少条展示
handleSizeChange(res) {
this.pageSize=res;
}
------------------------
// 当前页
handleCurrentChange(res) {
this.pageNo=res
}
TIP
total 为总数
page-size 每页条目数
current-change 翻页时触发,回调参数即为当前页
size-change 修改一页多少条,回调即为条数
# el-switch
在表格中的switch
<el-table-column prop="locked" label="禁用状态" >
<template slot-scope="scope">
<el-switch
v-model="scope.row.locked"
active-color="#EF4F4F"
inactive-color="#409EFF"
@change="changeSwitch(scope.$index,scope.row)"
>
</el-switch>
</template>
</el-table-column>
# el-cascader级联菜单
级联选择器控制宽度,超出省略号,并且悬浮增加:避免跳动
<el-cascader :options="cascaderoptions" :disabled="disabledPro" v-model="baseInfoForm.chargeCode" @change="handleCharge" :show-all-levels="false" clearable style="width:300px;">
<template slot-scope="{data}">
<el-tooltip class="item" effect="dark" placement="bottom" v-if='data.label.length>5'>
<div slot="content">{{data.label}}</div>
<span>{{data.label}}</span>
</el-tooltip>
<span v-else>{{data.label}}</span>
</template>
</el-cascader>
<style>
.el-cascader-menu{
min-width:150px !important;
width:150px !important;
}
</style>
# el-drawer
<el-drawer
title="项目详情"
class="eldrawer"
:visible.sync="drawer"
size="60%">
<div class="tabtopic">
<span :class="{ topicactive: isActive1}" @click="topic(1)">基本信息</span>|
<span :class="{ topicactive: isActive2}" @click="topic(2)">表管理</span>|
<span :class="{ topicactive: isActive3}" @click="topic(3)">同步日志</span>
</div>
</el-drawer>
侧边滑出,但是页面高度不方便滚动,需要另外设置!
this.$refs.tabbottom1.style.height=window.innerHeight-xxx+"px"
# 其他解决思路
可以去设置样式el-drawer__body,overflow设为auto或者height设为0都可,注意,这段css要放在 没有scoped的style标签 下才会生效
.el-drawer__body{
overflow-y: auto;
/* height: 0; */
}
# el-select
<el-select v-model="newform.source"
multiple
placeholder="来源"
class="createselect mr10"
clearable
>
<template v-for="item in originlist">
<el-option :key="item.id" :label="item.name" :value="item.id"></el-option>
</template>
</el-select>
value是传给后台的值,而label则是看到的标签 multiple 多选 clearable用来清空
注意:渲染的for循环数据要和v-model给出的数据 全等
# el-radio
当传递的是Boolean,可以采用el-radio-group包裹
<el-radio-group v-model="form.lineloss">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
<!-- <el-radio v-model="form.lineloss" label="1">是</el-radio>
<el-radio v-model="form.lineloss" label="2">否</el-radio> -->
# el-checkbox
<el-col :span="24">
<el-form-item label="可开票类型">
<el-checkbox v-model="form.canReceipt" >收据</el-checkbox>
<el-checkbox v-model="form.canInvoice" :disabled='!form.canReceipt'>发票</el-checkbox>
</el-form-item>
</el-col>
<template>
<div class="index">
<div>
<p class="modelList">模型列表</p>
<template>
<el-checkbox :indeterminate="isIndeterminate"
v-model="checkAll" @change="handleCheckAllChange" class="all">全选</el-checkbox>
<div style="margin: 15px 0;"></div>
<el-checkbox-group v-model="checkedArr" @change="handleCheckedChange">
<div v-for="item in tem" :key="item.key" class="checkbox">
<el-checkbox :label="item.key" :key="item.key" class="checkbox">
{{item.value}}
</el-checkbox>
</div>
</el-checkbox-group>
</template>
</div>
</div>
</template>
<script>
export default {
data() {
return {
checkAll: false,
tem:[{key:1,value:"模板1"}, {key:2,value:"模板2"}, {key:3,value:"模板3"}],
isIndeterminate:false,
checkedTem: [{key:1,value:"模板1"}],
checkedArr:[]
};
},
mounted() {
this.checkedArr=this.checkedTem.map(el=>{
return el.key
})
console.log(this.checkedArr)
},
methods: {
handleCheckAllChange(val) {
this.checkedTem = val ? this.tem : [];
this.checkedArr=this.checkedTem.map(el=>{
return el.key
})
this.isIndeterminate = false;
},
handleCheckedChange(value) {
console.log(value)
let checkedCount = value.length;
this.checkAll = checkedCount === this.tem.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.tem.length;
},
}
};
</script>
一般对于checkbox,给的应该有个key和value组成的对象作为数组的每一项,而不是一个简单的数组,所以如果需要默认选中的时候,需要自己进行简单的变换;当然可以更简洁的省区checkedTem这个中间值
<el-checkbox label="全部权限" class="selectAll" @change='selectAll'></el-checkbox>
selectAll(v){
//返回true或者false
if(v){
let arr=this.data.map(e=>{
return e.id
})
this.$refs.tree.setCheckedKeys([...arr]);
}else{
this.$refs.tree.setCheckedKeys([]);
}
}
- checkbox多选和回显设置,多选和单选功能根据具体的业务处理
<template>
<el-dialog
title="添加抄送人员"
:visible.sync="dialogVisible"
height:600px
:before-close="handleClose"
:close-on-click-modal="false"
>
<div class="dialog-body">
<div class="dialog-between-body" v-loading='leftloading'>
<div class="body-title">组织选择</div>
<div class='jiagou' v-if='useTreeBreadcrumb.length'>
<div class='part' v-for='(item,index) in partArr' :key='item.dingDeptId' @click='handpart(item.dingDeptId,index)' :class='index==isActive?"isActive":""'>
{{item.deptName}}
</div>
<div class='person' v-for='item in personArr' :key='item.id'>
<el-checkbox v-model='checkList' :label="item.id" @change="(checked)=>selectChange(checked,item)">
<img :src="item.avatar" alt="头像" v-if='item.avatar' class='avatar'>
<img src="~@/assets/images/moren.jpg" alt="" class='avatar' v-else>
{{item.name}}
</el-checkbox>
</div>
</div>
<div class='jiagou' v-else>
<template v-if='searchList.length'>
<div class='searchlist' v-for='(item,index) in searchList' :key='index' >
<el-checkbox v-model='checkList' :label="item.id" @change="(checked)=>selectChange(checked,item)">
<img :src="item.avatar" alt="头像" v-if='item.avatar' class='avatar1'>
<img src="~@/assets/images/moren.jpg" alt="" class='avatar1' v-else>
<div class='searchright'>
<section class='sectiontop'> {{item.name}}</section>
<section class='sectionbottom'>{{item.deptName}}</section>
</div>
</el-checkbox>
</div>
</template>
<div v-else class="loading">没有符合的数据…</div>
</div>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="confirm" :loading='isconloding'>确 定</el-button>
</span>
</el-dialog>
</template>
<script>
import { getDeptList,getUserList,ccUserSave } from '@/api/task/person'
export default {
props:['father'],
data() {
return {
dialogVisible:false,
tree: {
show: false,
breadcrumb: [],
data: [],
checkbox: false,
props: {
children: 'treeChildren',
label: 'orgName'
}
},
filterText:'',
checkListArr:[],
partArr:[],
personArr:[],
breadcrumbArr:[],
isActive:'',
selectperson:[],
//选中的人员id
checkList:[],
leftloading:false,
timer:null,
searchList:[],
isconloding:false
}
},
mounted(){
this.init()
},
computed: {
useTreeBreadcrumb() {
if(this.breadcrumbArr.length>3){
let tem = JSON.parse(JSON.stringify(this.breadcrumbArr))
// console.log(tem)
return [tem[0],tem[tem.length-2],tem[tem.length-1]]
}else{
console.log(this.breadcrumbArr,111111111)
return this.breadcrumbArr
}
}
},
methods: {
init(){
this.$nextTick(()=>{
const data={
deptId:1
}
getDeptList(data).then(res=>{
// console.log(res)
if(this.breadcrumbArr.length){
}else{
this.breadcrumbArr.push({deptName:res.data.deptName,dingDeptId:res.data.dingDeptId})
}
this.partArr =res.data.deptList
this.personArr =res.data.userList
})
})
},
handleInput(val){
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
if(val != ''){
this.breadcrumbArr =[]
this.partArr=[]
this.personArr=[]
this.getSearchData();
}else{
this.init()
}
}, 300)
},
clickBreadAjax(v){
const data={
deptId:v
}
this.leftloading =true
getDeptList(data).then(res=>{
// console.log(res)
this.partArr =res.data.deptList
this.personArr =res.data.userList
this.leftloading =false
}).catch(e=>{
this.leftloading =true
})
},
handleBreadcrumbClick(index,v) {
this.breadcrumbArr.splice(index + 1)
this.clickBreadAjax(v.dingDeptId)
},
// 左侧树节点选择框发生变化时
selectChange(checked, val){
console.log(this.checkList)
console.log(checked,val)
// this.checkList.length=0;
// this.checkList[0]=val.deptId
if(checked){
if(this.father =='person'){
this.checkListArr.push(val)
}else if(this.father == 'admin'){
this.checkListArr.push(val)
if(this.checkListArr.length>1){
this.checkListArr= [this.checkListArr[1]]
this.checkList=[this.checkList[1]]
}
}
}else{
if(val && val.id){
this.checkListArr = this.checkListArr.filter(i=>{return i.id!== val.id})
}
}
console.log(this.checkListArr.length)
},
handleCancelSelect(v){
if(v){
console.log(this.checkListArr)
console.log(this.checkList)
this.checkListArr = this.checkListArr.filter(i=>{return i.id !== v})
this.checkList = this.checkList.filter(i=>{return i !== v})
}
},
handpart(v,i){
this.isActive=i
const data={
deptId:v
}
this.leftloading =true
getDeptList(data).then(res=>{
console.log(res)
this.breadcrumbArr.push({deptName:res.data.deptName,dingDeptId:res.data.dingDeptId})
this.partArr =res.data.deptList
this.personArr =res.data.userList
this.leftloading =false
}).catch(e=>{
this.leftloading =false
})
},
// 确定
confirm(){
if(!this.checkListArr.length){
return this.$message.warning('请选择人员后再提交')
}
console.log(this.checkListArr)
let maparr=this.checkListArr.map(el=>el.id)
const data={
userIds:maparr
}
this.isconloding =true
ccUserSave(data).then(res=>{
this.$message.success('操作成功')
this.handleClose()
this.$parent.init()
this.isconloding =false
}).catch(e=>{
this.isconloding =false
})
}
},
}
</script>
# el-tree
<template>
<div class="menu">
<el-input class="search" placeholder="搜索" v-model="filterText"></el-input>
<el-tree :data="data"
:props="defaultProps"
class="tree"
default-expand-all
ref="tree"
:filter-node-method="filterNode"
@node-click="handleNodeClick">
</el-tree>
</div>
</template>
<script>
export default {
name: 'tabs',
data() {
return {
data: [{
label: '金融反诈模型',
id:1,
children: [{
label: '江苏银行',
id:2,
children: [{
label: '江苏银行模型'
}]
}]
}, {
label: '黑名单模型',
id:3,
children: [{
label: '案件黑名单',
id:4,
children: [{
label: '案件模型',
id:5,
}]
}, {
label: '洗钱黑名单',
id:6,
children: [{
label: '洗钱黑名单模型',
id:7
}]
}]
}, {
label: '灰名单模型',
id:8,
children: [{
label: '灰名单接口',
id:9,
children: [{
label: '接口模型',
id:10,
},{
label: '测试模型',
id:11
}]
}]
}],
defaultProps: {
children: 'children',
label: 'label',
id:"id"
},
filterText:""
}
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods: {
handleNodeClick(data) {
console.log(data);
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
}
},
}
</script>
@node-click:点击到的内容节点返回相对应的信息
- el-tree树结构,还可以添加本地搜索功能
<template>
<div class="wrap">
<el-form :model="form">
<el-row>
<section>
<span class='setting'>菜单权限</span>
<el-input
class="search"
placeholder="输入关键字进行过滤"
v-model="filterText" />
<el-checkbox label="全部权限" class="selectAll" @change='selectAll'></el-checkbox>
<el-tree
class="eltree"
:data="data"
:props="defaultProps"
default-expand-all
node-key="id"
:filter-node-method="filterNode"
show-checkbox
ref="tree">
</el-tree>
</section>
</el-row>
</el-form>
</div>
</template>
<script>
export default {
data(){
return {
form:{
rolename:'',
roledes:''
},
filterText: '',
data: [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
}
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
methods:{
filterNode(value, data,node) {
console.log(value,data,node)
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
selectAll(v){
if(v){
let arr=this.data.map(e=>{
return e.id
})
this.$refs.tree.setCheckedKeys([...arr]);
}else{
this.$refs.tree.setCheckedKeys([]);
}
},
}
}
</script>
总结
- 本地过滤搜索功能需要依赖 :filter-node-method="filterNode"
- filter-node-method需要通过this.$refs.tree.filter(val)来实时调用
- 本地过滤的方法传递三个参数对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏 Function(value, data, node)
filterNode(value, data,node) {
console.log(value,data,node)
if (!value) return true;
return data.label.indexOf(value) !== -1;
}
# el-tree本地搜索
本地搜索默认只搜到自己,所以如果有子节点需要做以下的处理
export default {
install: function(Vue, options) {
Vue.mixin({
methods: {
// 优化之后的代码 不管有多少级都适用
filterNode(value, data, node) {
if (!value) {
return true
}
try {
value = value.trim()
} catch (error) {
console.log(error)
}
// let level = node.level;
const arr = []
this.mygetNode(node, arr, value)
let result = false
arr.forEach((item) => {
result = result || item
})
return result
},
mygetNode(node, arr, value) {
let isFlag = false
if ((node.data && node.data.label && node.data.label.indexOf(value)) !== -1) {
isFlag = true
} else {
isFlag = false
}
if (isFlag) {
arr.push(isFlag)
}
// isFlag ? arr.push(isFlag) : ''
if (!isFlag && node.level !== 1 && node.parent) {
this.mygetNode(node.parent, arr, value)
}
}
}
})
}
}
# el-tree修改默认树结构的字段 defaultProps
从后台拿过来的数据,并不一定符合children和label这些完全相同的字段,在项目开发中本地搜索会报错。(lable代表的部门名实际为orgName)
defaultProps: {
children: "children",
label: "orgName"
},
[Vue warn]: Error in callback for watcher "orgNamexxx": "TypeError: Cannot read property 'indexOf' of undefined"
//orgNamexxx为watch监听名
- 解决方案:添加一个label字段:加过之后,label的内容值为label或者orgName都行
orgList(data).then(response=>{
const data=response.data;
data.forEach(el=>{
el.label=el.orgName;
})
this.deptOptions = this.handleTree(data, "orgId");
})
# 默认某行高亮el-tree
this.$nextTick(()=>{
this.$refs.tree.setCurrentKey(nodeData.nodeData.id)
})
# el-tree 动态树添加子节点 updateKeyChildren append
- 更新当前节点下所有的子节点:对象数组,会覆盖当前选择的目标节点的子节点
| updateKeyChildren | - |
|---|---|
| 通过 keys 设置节点子元素,使用此方法必须设置 node-key 属性 | (key, data) 接收两个参数,1. 当前节点 key 2. 节点数据的数组 |
this.$refs.tree.updateKeyChildren(data.id,temdata)
- 往选择的目标节点添加 一个子节点 (所以不是数组) , 可以嵌套 ,append只追加不覆盖
| append | - |
|---|---|
| 为 Tree 中的一个节点追加一个子节点 | (data, parentNode) 接收两个参数,1. 要追加的子节点的 data 2. 子节点的 parent 的 data、key 或者 node |
this.$refs.tree.append({label:299,id:93,children:[{label:9000,id:95},{label:9001,id:87}]},data)
注意
切记子树可能node-key(假如父树的名为id,而子树也许叫uid那么就需要手动将子树的x.id=x.uid),否则可能会出现updateKeyChildren每次都不能覆盖的情况
# el-tree子节点多层节点的情况下x轴滚动条
::v-deep .el-tree {
overflow-x: auto;
height: 100%;
font-size:14px;
}
::v-deep .el-tree > .el-tree-node {
display: inline-block;
min-width: 100%;
}
# el-image
不仅可以预览preview-src-list,还可以懒加载lazy,加载失败等情况
<el-image
style="width: 100px; height: 100px"
:src="url"
:preview-src-list="srcList">
</el-image>
<div class="demo-image__lazy">
<el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
</div>
<script>
export default {
data() {
return {
urls: [
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
]
}
}
}
</script>
# el-image-viewer
ElImageViewer是Image组件的内置组件,主要实现图片的预览功能.
<el-image-viewer v-if="showViewer" :on-close="showViewerClose" :url-list="[guidePic]" />
<script>
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
components: {
ElImageViewer
}
</script>
# 点击图片不预览,点击特定按钮预览
因为功能改变,当悬浮到图片上,会展示查看和删除两个按钮,那么就不能使用原来的图片预览办法,需要稍作变通
<!--创建一个备用的el-image-->
<div class="demo-image__preview">
<el-image class="my-img" :src="previewUrl" :preview-src-list="previewUrlList" ref="preview">
</el-image>
</div>
图片必须在页面上存在,不能设置display:none,也不能设置width:0;height:0,否则不能触发,可以设置定位让看不见
.my-img {
width: 100px;
height: 100px;
opacity: 0;
position: fixed;
left:-1000px;
top:0;
}
.my-img .el-image__inner,
.el-image__error {
visibility: hidden;
}
//myurl即为此刻的图片路径
this.$refs.preview.showViewer = true;
this.previewUrl =this.myurl
this.previewUrlList=[this.myurl]
# el-form 校验
Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。
<template>
<el-drawer>
<div class="drawer-content">
<el-form :model='form' :rules="formRules" style="flex: 1">
<el-form-item label="名称" prop="username" :label-width="formLabelWidth" >
<el-input v-model="form.username" autocomplete="off" placeholder="请填写租户名称" clearable/>
</el-form-item>
</div>
</el-drawer>
</template>
<script>
export default {
data() {
return {
formLabelWidth:'80px',
form:{
username:'',
},
formRules:{
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
},
}
}
}
</script>
:label-width="formLabelWidth" 出现空隙====> :inline="true"
<el-form :inline="true">
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
}
});
# 自定义校验
自定义校验一定要有返回callback!!! 否则验证时会出现不执行this.$refs.form.validate方法
// 检验数字包括有小数
export function validNumdot(val) {
const num = /^[+-]?(0|([1-9]\d*))(\.\d+)?$/
return !num.test(val)
}
const checkNum = (rule, value, callback) => {
if (validNumdot(value)) {
return callback(new Error('请输入正确的数字'))
}
callback()//当一切正常时返回的callback
}
rules: {
INTRODUCTION2: [
{ required: true, message: '请输入社区面积', trigger: 'blur' },
{ min: 0, max: 10, message: '长度在10个字符以内' },
{ validator: checkNum, trigger: 'blur' }],
},
# 利用正则校验
rules10: {
email:[{
pattern: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
message: '请输入正确格式的邮箱',
trigger: 'blur',
required: true
}]
}
# 切换校验在不同的条件切换必填
<template>
<drawer :visible.sync="show" :size="500" :buttons="buttons" :title="title">
<el-form ref="form" :model="form" :rules="rules" label-width="124px" class="jp_form_container">
<el-row :gutter="36">
<el-col :span="24">
<el-form-item label="是否使用优惠政策">
<el-radio-group v-model="form.isDiscount">
<el-radio :label="0">否</el-radio>
<el-radio :label="1">是</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-show="form.isDiscount!==''&&Number(form.isDiscount) !== 0">
<el-form-item label="增值税特殊管理" prop="specialTaxManagement" ref="specialTaxManagement">
<el-input v-model.trim="form.specialTaxManagement" clearable placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</drawer>
</template>
<script>
export default {
name: 'AddDialog',
data() {
return {
form: {
isDiscount: 0,
zeroRatedType: '',
specialTaxManagement: ''
},
rules: {
specialTaxManagement: [{ required: true, message: '请输入增值税特殊管理', trigger: 'change' }]
},
}
},
watch: {
'form.isDiscount': {
handler(newval) {
let tem = false
if (Number(newval) === 1) {
this.rules.specialTaxManagement[0].required = true
} else {
this.rules.specialTaxManagement[0].required = false
if (!this.form.specialTaxManagement) {
try {
this.$refs.specialTaxManagement.clearValidate()
} catch (error) {
}
}
}
},
deep: true,
immediate: true
}
}
}
</script>
- this.rules.specialTaxManagement[0].required = true 控制是否必填
- this.$refs.specialTaxManagement.clearValidate() 清空校验
- 因为选择不同模式,必填项可能需要隐藏,
注意这里需要用v-show而不是v-if,v-if不会有校验必填项
# element内置校验选项
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
]
}
可以内置的type类型
Indicates the type of validator to use. Recognised type values are:
+ string: Must be of type string. This is the default type.
+ number: Must be of type number.
+ boolean: Must be of type boolean.
+ method: Must be of type function.
+ regexp: Must be an instance of RegExp or a string that does not generate an exception when creating a new RegExp.
+ integer: Must be of type number and an integer.
+ float: Must be of type number and a floating point number.
+ array: Must be an array as determined by Array.isArray.
+ object: Must be of type object and not Array.isArray.
+ enum: Value must exist in the enum.
+ date: Value must be valid as determined by Date
+ url: Must be of type url.
+ hex: Must be of type hex.
+ email: Must be of type email.
+ any: Can be any type.
# 校验某个选项
validateField的值必须是这个选项的prop,否则无效
<el-form-item label="管辖区:" prop="jurisdiction">
<treeselect
v-model="form.jurisdiction"
:multiple="true"
:options="menuOptions"
:limitText="count => `+${count}`"
:limit="1"
placeholder="选择管辖区"
no-results-text="暂无查询结果"
@input = 'tfun("jurisdiction")'
/>
</el-form-item>
-----------------
tfun(v){
this.$nextTick(()=>{
this.$refs.form.validateField(v)
})
},
# 取消校验报红resetFields|clearValidate
- 如果关闭了el-form所在的页面或者弹框,再开启仍有检验信息,则需要清除,使用 this.$refs.form.resetFields(),form为el-from上的ref, 结合$nextTick使用 ;也可以使用this.$refs.form.clearValidate()
- resetFields可以恢复初始值,但是如果是select可能就不会恢复了
this.$refs.editPropertiesFormRef.resetFields()
# el-upload
- 如果既要填图标又要绑定按钮触发图片上传功能,可使用
this.$refs['uploadimg'].$children[0].$refs.input.click() - 可能会上传失败,那么久取之前的图片,或者再初始化一次,需多调一次接口。
<template>
<section>
<slot />
<el-upload
ref="uploadimg"
v-loading.fullscreen.lock="fullscreenLoading"
class="avatar-uploader"
:action="uploadapi"
:headers="token"
:show-file-list="false"
:on-error="handleError"
accept=".jpeg, .png, .bmp, .jpg"
element-loading-text="加载中......"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="avatar1" :src="avatar1" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-button v-if="isbtn" icon="el-icon-upload2" @click="updateimg">更换图片</el-button>
</section>
</template>
<script>
import { getToken } from '@/utils/auth'
export default {
props: ['avatar', 'isbtn', 'tableName'],
data() {
return {
token: {
'User-Token': getToken()
},
fullscreenLoading: false,
imageUrl: '',
uploadapi: '',
avatar1: ''
}
},
watch: {
// avatar(v,v1){
// console.log(v)
// this.avatar1=v;
// this.imageUrl=v
// }
avatar: {
immediate: true,
handler(v, v1) {
console.log(v)
this.avatar1 = v
this.imageUrl = v
}
}
},
mounted() {
this.uploadapi = process.env.VUE_APP_BASE_API + `/wise-operator/upload/uploadPicture?tableName=${this.tableName}`
},
methods: {
handleError(res, file) {
console.log(res)
this.imageUrl = ''
this.avatar1 = ''
this.fullscreenLoading = false
this.$message.error('上传失败' + res)
},
handleAvatarSuccess(res, file) {
console.log(res)
this.fullscreenLoading = false
if (res.returnCode == '0') {
this.imageUrl = res.data
this.avatar1 = URL.createObjectURL(file.raw)
this.$emit('changepic', res.data)
} else if (res.returnCode == '5') {
this.$message.error(res.returnMsg)
setTimeout(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index'
})
})
} else {
this.$message.error(res.returnMsg)
this.avatar1 = this.imageUrl
}
},
beforeAvatarUpload(file) {
this.fullscreenLoading = true
let isJPG
if (
file.type.includes('jpg') ||
file.type.includes('jpeg') ||
file.type.includes('png') ||
file.type.includes('bmp')
) {
isJPG = true
} else {
isJPG = false
this.$message.error('上传头像图片只能是 JPG 格式!')
this.fullscreenLoading = false
}
const isLt5M = file.size / 1024 / 1024 < 5
if (!isLt5M) {
this.$message.error('上传头像图片大小不能超过 5MB!')
this.fullscreenLoading = false
}
return isJPG && isLt5M
},
updateimg() {
this.$refs['uploadimg'].$children[0].$refs.input.click()
}
}
}
</script>
<style lang="scss" scoped>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
margin-top: 10px;
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
border: 1px solid rgba(140,147,157,0.8);
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.el-button{
margin-top: 10px;
width: 120px;
margin-left: 30px;
}
</style>
# el-picker 日期插件
通过value-format来确定返回值格式
<el-date-picker
clearable
v-model="createtime"
@change="getDate"
value-format="yyyy-MM-dd hh:mm:ss"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
getDate(data) {
console.log('时间', data)
if(data.length){
this.startTime = data[0]
this.endTime = data[1]
}else{
this.startTime = ''
this.endTime = ''
}
}