# 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>

参考链接 (opens new window)

# 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 = ''
      }
     
    }

# el-collapse-transition

最后更新: 9/14/2022, 7:43:01 AM