<template>  <div class="cascader-wrapper">    <crec-popover      placement="bottomLeft"      trigger="click"      :popper-class="popOverClass"      v-model="showPopover"    >      <!-- <div slot="reference"> -->      <!-- multiple        mode="tags" -->      <crec-select        v-model="selectedLabels"        :default-value="defaultLabels"        :placeholder="placeholder"        :disabled="disabled"        :size="size"        :showArrow="true"        style="width: 100%;"        popper-class="hide-popper"        :open="false"        @focus="handleFocus"        @dropdown-visible-change="visibleChange"      ></crec-select>      <!-- </div> -->      <template slot="content">        <div          class="cascader-menu-wrapper"          v-clickoutside="hidePopover"        >          <template v-if="options.length > 0">            <ul              class="crec-cascader-menu cascader-menu"              :style="{'width': panelWidth === 'auto' ? 'auto' : panelWidth + 'px'}"              v-for="(cas, index) in casTree"              :key="index"            >              <!--  -->              <!-- 'can-load-children': !item.isLeaf && !item[childrenKey] && allowLoadChildren && showLoadingIndicator, -->              <!-- 'loading-children': !item.isLeaf && item.loading && allowLoadChildren && showLoadingIndicator, -->              <!-- 'crec-cascader-menu-item-expand': item[childrenKey] && item[childrenKey].length > 0, -->              <li                :class="{                  'crec-cascader-menu-item': true,                  'crec-cascader-menu-item-expand': true,                  'has-checked-child': item.indeterminate || item.hasCheckedChild,                  'crec-cascader-menu-item-active': item.checked,                }"                @click="spreadNext(item[childrenKey], index, item)"                v-for="(item, itemIdx) in cas"                :key="itemIdx"                :title="item[labelKey]"              >                <crec-checkbox                  class="cascader-checkbox"                  @click.native.stop                  :disabled="item.disabled"                  v-model="item.checked"                  :indeterminate="item.indeterminate"                  @change="({target}) => { checkedChange(item, target.checked) }"                ></crec-checkbox>                <span>{{ item[labelKey] }}</span>                <span                  v-if="item[childrenKey] && item[childrenKey].length > 0"                  class="crec-cascader-menu-item-expand-icon"                >                  <crec-icon type="right"></crec-icon>                </span>              </li>            </ul>          </template>          <template v-else>            <ul class="crec-cascader-menu cascader-menu">              <li class="crec-cascader-menu-item dropdown__empty">                {{ noDataText }}              </li>            </ul>          </template>        </div>      </template>    </crec-popover>  </div></template><script>import Clickoutside from './clickoutside'import { props, hasArrayChild, deepClone, getId, fireEvent, isPromise } from './utils'export default {  name: 'TagSelect',  props,  watch: {    selectedLabels: {      deep: true,      handler () {        console.log(this.selectedLabels)        if (this.selectedLabels === '') {          this.selectedLabels = this.defaultLabels        }      }    },    options: {      deep: true,      handler () {        this.initOpts()        this.initDatas()      }    },    defaultOptions: {      deep: true,      handler () {        console.log(this.defaultOptions)        this.defaultLabels = this.defaultOptions.map(e => e.organId)[0]      }    },    value: {      deep: true,      handler () {        console.log(this.selectedValues, this.value)        if (this.selectedValues !== this.value) {          this.initOpts()          this.initDatas()        }      }    },    disabled (disabled) {      if (disabled) {        this.hidePopover()      }    },    showPopover (flag) {      if (flag) {        console.log(this.value)        this.$emit('focus')      }    }  },  directives: { Clickoutside },  created () {    this.classRef = `popper-class-${getId()}`    this.popOverClass = `cascader-popper ${this.classRef} ${this.popperClass}`    this.initOpts()    this.initDatas()  },  mounted () {    // 设置弹出层宽度    this.elWidth = this.$el.offsetWidth  },  destroyed () {    this.clonedOpts = null    this.casTree = null    this.selectedItems = null    this.selectedLabels = null    this.selectedvalues = null  },  data () {    return {      elWidth: '',      popperWidth: '',      popOverClass: '',      classRef: '',      showPopover: false,      clonedOpts: [],      casTree: [],      selectedItems: {},      selectedLabels: '',      selectedValues: '',      loadChildrenPromise: null,      defaultLabels: ''    }  },  methods: {    initOpts () {      console.log(this.defaultOptions)      this.defaultLabels = this.defaultOptions.map(e => e.organId)[0]      console.log(this.defaultLabels)      this.clonedOpts = deepClone(this.options)      this.casTree = [this.clonedOpts]      console.log(this.casTree)    },    /**     * 初始化数据     * 空值初始化,两个绑定不统一的状况     */    initDatas () {      this.pickCheckedItem(this.clonedOpts)    },    /**     * 依据以后节点 checked     * 更改所有子孙节点 checked     * 依赖 this.selectChildren     */    markChildrenChecked (node) {      const vm = this      function loop (children, status) {        if (children) {          children.map(child => {            if (!child.disabled) {              child.checked = status              if (child.checked) {                child.indeterminate = false              }            }            if (hasArrayChild(child, vm.childrenKey)) {              loop(child[vm.childrenKey], status)            }          })        }      }      if (node && hasArrayChild(node, vm.childrenKey) && this.selectChildren) {        loop(node[vm.childrenKey], node.checked)      }    },    /**     * 标记父节点 checked、indeterminate 状态     * 依赖 this.selectChildren     */    markParentChecked (node) {      const vm = this      node.indeterminate = false      function loop (node) {        let checkCount = 0        if (hasArrayChild(node, vm.childrenKey)) {          const childIndeterminate = node[vm.childrenKey].some(child => child.indeterminate)          node[vm.childrenKey].map(child => {            if (child.checked) {              checkCount++            }          })          // 子节点全副被选中          if (checkCount === node[vm.childrenKey].length) {            node.checked = true            node.indeterminate = false          } else {            node.checked = false            if (checkCount > 0 || childIndeterminate) {              node.indeterminate = true            } else {              node.indeterminate = false            }          }        }        if (node.parent) {          loop(node.parent)        }      }      if (node && node.parent && this.selectChildren) {        loop(node.parent)      }    },    /**     * 标记是否有被选子项     * 依赖 this.selectChildren     */    markParentHasCheckChild (node) {      const vm = this      node.hasCheckedChild = false      function loop (node) {        let checkCount = 0        if (hasArrayChild(node, vm.childrenKey)) {          const childHasCheckedChild = node[vm.childrenKey].some(child => child.hasCheckedChild)          node[vm.childrenKey].map(child => {            if (child.checked) {              checkCount++            }          })          // 子节点有被选中          node.hasCheckedChild = (checkCount > 0) || childHasCheckedChild        }        if (node.parent) {          loop(node.parent)        }      }      if (node && node.parent && !this.selectChildren) {        loop(node.parent)      }    },    // 展现标签所有层级    getLevel (node, key, leveled) {      const levels = []      function loop (data) {        levels.push(data[key])        if (data.parent) {          loop(data.parent)        }      }      if (leveled) {        loop(node)        return levels.reverse().join(this.separator)      } else {        return node[key]      }    },    /**     * 解决已选中     * 从新遍历tree,pick除已选中我的项目     */    pickCheckedItem (tree) {      const vm = this      /**       * 移除parent援用       */      function removeParent (node) {        const obj = {}        Object.keys(node).forEach(key => {          if (key !== 'parent') {            obj[key] = node[key]          }        })        if (hasArrayChild(obj, vm.childrenKey)) {          obj[vm.childrenKey] = obj[vm.childrenKey].map(child => {            return removeParent(child)          })        }        return obj      }      vm.selectedItems = {}      vm.selectedLabels = ''      vm.selectedValues = ''      function loop (data) {        if (Array.isArray(data)) {          data.map(item => {            if (item.checked) {              const newItem = removeParent(item)              vm.selectedItems = (newItem)              vm.selectedLabels = vm.getLevel(item, vm.labelKey, vm.showAllLevels)              vm.selectedValues = vm.getLevel(item, vm.valueKey, vm.outputLevelValue)            }            if (hasArrayChild(item, vm.childrenKey)) {              loop(item[vm.childrenKey])            }          })        }      }      loop(tree)    },    clearTag () {      const vm = this      function loop (nodeArr) {        nodeArr.forEach(node => {          node.checked = false          node.indeterminate = false          if (hasArrayChild(node, vm.childrenKey)) {            loop(node[vm.childrenKey])          }        })      }      // 敞开全副状态      loop(this.clonedOpts)      this.selectedLabels = ''      this.selectedValues = ''      this.selectedItems = {}      this.$emit('clear')      this.syncData()    },    // 菜单选中变动    checkedChange (item, checked) {      this.defaultLabels = ''      this.clearTag()      console.log(item, checked)      item.checked = checked      this.$emit('clickItem', item)      this.markChildrenChecked(item)      this.markParentChecked(item)      this.markParentHasCheckChild(item)      this.pickCheckedItem(this.clonedOpts)      this.refresPopover()      this.syncData()    },    // 同步数据到下层    syncData () {      console.log(this.selectedValues)      this.$emit('input', this.selectedValues)      this.$emit('change', this.selectedValues, this.selectedItems)    },    // 开展下一级    async spreadNext (children, index, item) {      const vm = this      if (        vm.allowLoadChildren &&        !children && !item[vm.childrenKey] &&        vm.loadChildrenMethod &&        vm.loadChildrenMethod.constructor === Function &&        !vm.loadChildrenPromise && // promise 不存在        !item.isLeaf      ) {        const isPromiseMethod = this.loadChildrenMethod(item)        if (isPromise(isPromiseMethod)) {          vm.loadChildrenPromise = isPromiseMethod          this.$set(item, 'loading', true)          const result = await vm.loadChildrenPromise.catch(e => {            this.$set(item, 'loading', false)          })          this.$set(item, 'loading', false)          vm.loadChildrenPromise = null          if (result && result.constructor === Array) {            this.$set(item, vm.childrenKey, result)            children = result            this.initDatas()          } else {            console.warn('The resolved value by loadChildrenMethod must be an Option Array !')          }        } else {          console.warn('You must return a Promise instance in loadChildrenMethod !')        }      }      if (index || index === 0) {        if (vm.casTree.indexOf(children) === -1) {          if (children && children.length > 0) {            vm.casTree.splice(index + 1, vm.casTree.length - 1, children)          } else {            vm.casTree.splice(index + 1, vm.casTree.length - 1)          }          vm.$emit('spread', item)        }      }    },    visibleChange (visible) {      if (visible) {        this.showPopover = true      }    },    handleFocus (evt) {      if (this.disabled) return      this.$emit('focus', evt)    },    hidePopover (evt) {      this.showPopover = false      this.$emit('blur', evt)    },    refresPopover () {      setTimeout(() => {        fireEvent(window, 'resize')      }, 66)    }  }}</script><style lang="less">.hide-popper {  display: none;}.cascader-popper {  padding: 0px;}.crec-popover-inner-content {  padding: 0;}.cascader-menu-wrapper {  white-space: nowrap;  .crec-cascader-menu {    padding: 8px 0;    height: 240px;  }}.cascader-menu-wrapper .cascader-checkbox {  margin-right: 10px;  font-weight: 500;  font-size: 14px;  cursor: pointer;  user-select: none;}.crec-cascader-menu-item.has-checked-child {  background-color: #f5f7fa !important;}.dropdown__empty {  height: 100%;  padding-top: 50%;  margin: 0;  text-align: center;  color: #999;  font-size: 14px;}.can-load-children {  position: relative;}.can-load-children::after {  content: '';  display: inline-block;  position: absolute;  width: 5px;  height: 5px;  background: #a5d279;  right: 20px;  top: 50%;  border-radius: 50%;  transform: translateY(-50%);  -webkit-transform: translateY(-50%);}.can-load-children.loading-children::after {  animation: loading 0.22s infinite alternate;  -moz-animation: loading 0.22s infinite alternate; /* Firefox */  -webkit-animation: loading 0.22s infinite alternate; /* Safari 和 Chrome */  -o-animation: loading 0.22s infinite alternate; /* Opera */}@keyframes loading {  from {    background: #a5d279;  }  to {    background: #334d19;  }}</style>