VUE cascader 异步加载 获取选中value&label 编辑回显处理

最近在项目中使用cascader来处理省市异步加载级联多选功能,在异步加载,获取选中value&label,编辑回显处理时遇到点小麻烦,最终经过一整天的处理,解决掉问题。我把所有的代码发出来,给也遇到同样问题的小伙伴一个参考:

<!-- 企业人才库(求职者档案) 未加企业微信的C端用户,如通过招聘小程序投简历过来的用户 -->
<template>
  <div class="app-container">
    <!-- 搜索表单 -->
    <el-form
      ref="buttonsForm"
      size="small"
      :inline="true"
    >
      <el-form-item>
        <el-button v-has-permission="['enterpriseservice:talentpool:add']" type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
        <el-button v-has-permission="['enterpriseservice:talentpool:edit']" type="success" icon="el-icon-edit" :disabled="single" @click="handleUpdate">修改</el-button>
        <el-button v-has-permission="['enterpriseservice:talentpool:delete']" type="danger" icon="el-icon-delete" :disabled="multiple" @click="handleDelete">删除</el-button>
      </el-form-item>
    </el-form>
    <!-- 数据表格 -->
    <div class="el-table-div">
      <el-table
        v-loading="loading"
        :data="pageList"
        border
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="50" align="center" />
        <el-table-column label="姓名" prop="name" />
        <el-table-column label="性别" prop="gender" align="center" />
        <el-table-column label="年龄" prop="age" align="center" />
        <el-table-column label="手机" prop="mobile" align="center" />
        <el-table-column label="期望工作地点" prop="workPlaces" align="center" width="150">
          <template slot-scope="scope">
            <p v-for="(item, index) in scope.row.workPlaces" :key="index">{{ item.provinceName + '/' + item.cityName }}</p>
          </template>
        </el-table-column>
        <el-table-column label="自我简介" prop="selfIntroduction" />
        <el-table-column label="求职意向" prop="jobIntention" />
        <el-table-column label="备注" prop="notes" />
        <el-table-column label="添加时间" prop="createTime" align="center" />
        <el-table-column label="操作" align="center" width="100">
          <template slot-scope="scope">
            <el-button
              v-has-permission="['enterpriseservice:talentpool:edit']"
              type="primary"
              icon="el-icon-edit"
              size="mini"
              circle
              plain
              @click.stop="handleUpdate(scope.row)"
            />
            <el-button
              v-has-permission="['enterpriseservice:talentpool:delete']"
              type="danger"
              icon="el-icon-delete"
              size="mini"
              circle
              plain
              @click.stop="handleDelete(scope.row)"
            />
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!--分页-->
    <pagination
      v-show="pagination.total>0"
      :total="pagination.total"
      :page.sync="pagination.page"
      :limit.sync="pagination.limit"
      @pagination="handleQuery"
    />

    <!-- 表单弹窗 -->
    <el-dialog :title="dialog.title" :visible.sync="dialog.visible" width="800px">
      <el-form ref="form" :model="form" :rules="rules" label-width="130px">

        <el-form-item label="姓名" prop="name">
          <el-input v-model="form.name" placeholder="请输入姓名" maxlength="5" show-word-limit />
        </el-form-item>

        <el-form-item label="性别" prop="gender">
          <el-radio-group v-model="form.gender">
            <el-radio :label="1">男</el-radio>
            <el-radio :label="2">女</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="年龄" prop="age">
          <el-input-number v-model="form.age" controls-position="right" :min="18" :max="99" />
        </el-form-item>

        <el-form-item label="手机" prop="mobile">
          <el-input v-model="form.mobile" placeholder="请输入手机" maxlength="11" show-word-limit />
        </el-form-item>

        <el-form-item label="期望工作地点" prop="workplaceIds">
          <el-cascader
            ref="cascader"
            v-model="form.workplaceIds"
            :options="workplaceOptions"
            :props="workplaceProps"
            style="width: 100%"
            clearable
            :show-all-levels="true"
            @change="cascaderChange"
          />
        </el-form-item>

        <el-form-item label="自我介绍" prop="selfIntroduction">
          <el-input v-model="form.selfIntroduction" placeholder="请输入自我介绍" maxlength="50" show-word-limit />
        </el-form-item>

        <el-form-item label="求职意向" prop="jobIntention">
          <el-input v-model="form.jobIntention" placeholder="请输入求职意向" maxlength="50" show-word-limit />
        </el-form-item>

        <el-form-item label="备注" prop="notes">
          <el-input v-model="form.notes" placeholder="请输入备注" maxlength="50" show-word-limit />
        </el-form-item>

      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handleSubmit">确 定</el-button>
        <el-button @click="dialog.visible=false">取 消</el-button>
      </div>

    </el-dialog>
  </div>
</template>

<script>
import Pagination from '@/components/Pagination'
import { getProvince, getCity, getAllCity } from '@/api/platform/address'
import { pagelist, detail, update, add, batchDelete } from '@/api/enterpriseservice/talentpool'
export default {
  components: { Pagination },
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      selectParams: {
      },
      multiple: true,
      pagination: {
        page: 1,
        limit: 10,
        total: 0
      },
      pageList: [],
      dialog: {
        title: undefined,
        visible: false,
        type: undefined // type 操作类型:1-新增 2-修改
      },
      // 表单参数
      form: {
        id: undefined,
        name: undefined,
        gender: undefined,
        age: undefined,
        mobile: undefined,
        workplaceIds: undefined,
        selfIntroduction: undefined,
        notes: undefined,
        createTime: undefined,
        // 向后台提交的完整数据
        workplaceFullData: []
      },
      // 表单校验
      rules: {
        name: [
          { required: true, message: '姓名不能为空', trigger: 'blur' }
        ],
        gender: [
          { required: true, message: '请选择性别', trigger: 'blur' }
        ],
        age: [
          { required: true, message: '年龄不能为空', trigger: 'blur' }
        ],
        mobile: [
          { required: true, message: '电话不能为空', trigger: 'blur' },
          {
            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
            message: '请输入正确的手机号码',
            trigger: 'blur'
          }
        ],
        notes: [
          { required: true, message: '备注不能为空', trigger: 'blur' }
        ]
      },
      workplaceProps: {
        that: this,
        value: 'id',
        label: 'name',
        multiple: true,
        expandTrigger: 'click',
        // checkStrictly: true, // 选择任意一级
        lazy: true,
        lazyLoad(node, resolve) {
          const { value, level } = node
          // level=1是因为城市数据只能选到第2级(市),第1级加载第2级数据
          if (level === 1) {
            setTimeout(() => {
              getCity(value).then(response => {
                const cities = response.data.map(item => {
                  // leaf必须加,就是让组件识别是不是最后一级 必须给最后一级加上leaf属性,不然识别不了是最后一级,所以无法选中默认值
                  item.leaf = true
                  return item
                })

                if (node.hasChildren && node.children.length) {
                  const newChildren = []
                  cities.forEach(city => {
                    if (node.children.findIndex(x => x.value === city.id) === -1) {
                      newChildren.push(city)
                    }
                  })
                  resolve(newChildren)
                } else {
                  resolve(cities)
                }
              })
            }, 500)
          } else {
            // 这里不再加载下级数据了,如果加载区就是:else if (level === 2) {}
            resolve([])
          }
        }
      },
      // 回显必须要把需要回显的都写到 options 里面,且最后一项要加上 leaf:true, 表示无下级了才可以回显;
      workplaceOptions: [{
        label: undefined,
        value: undefined,
        children: [{
          label: undefined,
          value: undefined
        }]
      }],
      citiesAll: []
    }
  },
  async created() {
    // 初始化表格数据
    this.handleQuery()
  },
  methods: {
    handleQuery() {
      this.selectParams.page = this.pagination.page
      this.selectParams.limit = this.pagination.limit
      pagelist(this.selectParams).then(response => {
        this.pageList = response.data.list
        this.pagination.total = response.data.total
        this.loading = false
      })
    },
    handleInitProvince() {
      getProvince().then(response => {
        const { data } = response
        this.workplaceOptions = data
      })
    },
    handleReset() {
      this.pagination = {
        page: 1,
        limit: 10,
        total: 0
      }
      this.handleQuery()
    },
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id)
      this.single = selection.length !== 1
      this.multiple = !selection.length
    },
    handleAdd() {
      this.resetForm()
      this.dialog = {
        title: '新增',
        visible: true,
        type: 'add'
      }
      // 解决问题:级联选择器点击但未选中时,再次点击触发打开时,还是上次点击的选项
      const _cascader = this.$refs['cascader']
      if (_cascader) {
        _cascader.$refs.panel.checkedValue = []
        _cascader.$refs.panel.activePath = []
        _cascader.$refs.panel.syncActivePath()
      }
      this.handleInitProvince()
    },
    handleUpdate(row) {
      this.resetForm()
      // 取所有的市数据
      getAllCity().then(response => {
        const { data } = response
        this.citiesAll = data
        this.dialog = {
          title: '修改',
          visible: true,
          type: 'edit'
        }
        // 解决问题:级联选择器点击但未选中时,再次点击触发打开时,还是上次点击的选项
        const _cascader = this.$refs['cascader']
        if (_cascader) {
          _cascader.$refs.panel.checkedValue = []
          _cascader.$refs.panel.activePath = []
          _cascader.$refs.panel.syncActivePath()
        }

        const id = row.id || this.ids
        detail(id).then(response => {
          const { data } = response
          this.form = data

          // 处理已选中的ID,便于回显
          const selectedWorkplaceIds = []
          // 处理已选中的Options
          const selectedWorkplaceOptions = []
          response.data.workPlaces.forEach(element => {
            const selectedIds = []
            selectedIds.push(element.provinceId)
            selectedIds.push(element.cityId)
            selectedWorkplaceIds.push(selectedIds)
            // 先把已选中的省市数据写到 Options
            if (selectedWorkplaceOptions.findIndex(item => item.id === element.provinceId) === -1) {
            // 找已选中省下的市数据
              const cityChildren = []
              // 找到当前这个省下的所有市
              const selectedCities = this.citiesAll.filter(city => city.parentId === element.provinceId)
              selectedCities.forEach(cityElement => {
                cityChildren.push({ id: cityElement.id, name: cityElement.name, leaf: true, children: [] })
              })
              // 省市数据写到 Options
              selectedWorkplaceOptions.push(
                {
                  id: element.provinceId,
                  name: element.provinceName,
                  leaf: false,
                  children: cityChildren
                }
              )
            }
          })
          this.form.workplaceIds = selectedWorkplaceIds
          this.workplaceOptions = selectedWorkplaceOptions
          // 加载省数据,把未选中的省数据追加到 Options
          getProvince().then(response => {
            response.data.forEach(element => {
              if (selectedWorkplaceOptions.findIndex(item => item.id === element.id) === -1) {
                this.workplaceOptions.push({
                  id: element.id,
                  name: element.name,
                  leaf: false,
                  children: []
                })
              }
            })
          })
        })
      })
    },
    handleDelete(row) {
      const ids = [row.id || this.ids].join(',')
      this.$confirm('确认删除已选中的数据项?', '警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        batchDelete(ids).then(() => {
          this.$message.success('删除成功')
          this.handleQuery()
        })
      }).catch(() =>
        this.$message.info('已取消删除')
      )
    },
    handleSubmit: function() {
      this.$refs['form'].validate(valid => {
        if (valid) {
          // 处理期望工作地点
          this.form.workplaceFullData = []
          const checkedNodes = this.$refs['cascader'].getCheckedNodes()
          checkedNodes.forEach(element => {
            if (element.parent) {
              this.form.workplaceFullData.push({
                provinceId: element.parent.value,
                provinceName: element.parent.label,
                cityId: element.value,
                cityName: element.label
              })
            }
          })

          if (this.dialog.type === 'edit') {
            update(this.form).then(() => {
              this.$message.success('修改成功')
              this.closeDialog()
              this.handleQuery()
            })
          } else {
            add(this.form).then(() => {
              this.$message.success('新增成功')
              this.closeDialog()
              this.handleQuery()
            })
          }
        }
      })
    },
    resetForm() {
      this.form = {
        id: undefined,
        name: undefined,
        gender: undefined,
        age: undefined,
        mobile: undefined,
        workplaceIds: undefined,
        selfIntroduction: undefined,
        notes: undefined,
        createTime: undefined,
        // 向后台提交的完整数据
        workplaceFullData: []
      }
      if (this.$refs['form']) {
        this.$refs['form'].resetFields()
      }
    },
    closeDialog() {
      this.dialog = {
        title: undefined,
        visible: false,
        type: undefined
      }
    },
    cascaderChange(val) {
      console.log('cascaderChanged')
    }
  }
}
</script>

<style lang="scss" scoped>
  ::-webkit-scrollbar {
    width: 5px;
    height: 1px;
  }
  ::-webkit-scrollbar-thumb { //滑块部分
    border-radius: 5px;
    background-color: rgb(201, 201, 201);
  }
  ::-webkit-scrollbar-track { //轨道部分
    box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
    background: #ededed;
    border-radius: 5px;
  }
  .el-table-div{
    height: 70vh;
    overflow: hidden;
    overflow-y: auto;
    padding-right: 15px;
    line-height: 25px;
  }
</style>

总结一下思路

1)cascader编回显需要在数据即workplaceOptions一、二级都有(编辑时查出来的详情数据)且workplaceIds设置了回显的ID(一个二维数组)的情况下才可以回显;

2)一个细节:比如用户选了河北省 - 唐山市 ,注意,河北省只选了唐山,其他市并未选,但编辑回显时需要把选中的河北省下所有市都查出来,不能只查询选中了的唐山,这样会造成编辑时再次点河北重新加载河北省下的所有市,数据变化了,默认回显项也就消失了;

3)未选中的省份在回显时不处理;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值