单选 联动
Posted 叶为花而生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单选 联动相关的知识,希望对你有一定的参考价值。
<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>
以上是关于单选 联动的主要内容,如果未能解决你的问题,请参考以下文章