forked from zhurui/management
247 lines
6.2 KiB
Vue
247 lines
6.2 KiB
Vue
<script>
|
|
import ElCheckbox from 'element-ui/packages/checkbox';
|
|
import ElRadio from 'element-ui/packages/radio';
|
|
import { isEqual } from 'element-ui/src/utils/util';
|
|
|
|
const stopPropagation = e => e.stopPropagation();
|
|
|
|
export default {
|
|
inject: ['panel'],
|
|
|
|
components: {
|
|
ElCheckbox,
|
|
ElRadio
|
|
},
|
|
|
|
props: {
|
|
node: {
|
|
required: true
|
|
},
|
|
nodeId: String
|
|
},
|
|
|
|
computed: {
|
|
config() {
|
|
return this.panel.config;
|
|
},
|
|
isLeaf() {
|
|
return this.node.isLeaf;
|
|
},
|
|
isDisabled() {
|
|
return this.node.isDisabled;
|
|
},
|
|
checkedValue() {
|
|
return this.panel.checkedValue;
|
|
},
|
|
isChecked() {
|
|
return this.node.isSameNode(this.checkedValue);
|
|
},
|
|
inActivePath() {
|
|
return this.isInPath(this.panel.activePath);
|
|
},
|
|
inCheckedPath() {
|
|
if (!this.config.checkStrictly) return false;
|
|
|
|
return this.panel.checkedNodePaths
|
|
.some(checkedPath => this.isInPath(checkedPath));
|
|
},
|
|
value() {
|
|
return this.node.getValueByOption();
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
handleExpand() {
|
|
const { panel, node, isDisabled, config } = this;
|
|
const { multiple, checkStrictly } = config;
|
|
|
|
if (!checkStrictly && isDisabled || node.loading) return;
|
|
|
|
if (config.lazy && !node.loaded) {
|
|
panel.lazyLoad(node, () => {
|
|
// do not use cached leaf value here, invoke this.isLeaf to get new value.
|
|
const { isLeaf } = this;
|
|
|
|
if (!isLeaf) this.handleExpand();
|
|
if (multiple) {
|
|
// if leaf sync checked state, else clear checked state
|
|
const checked = isLeaf ? node.checked : false;
|
|
this.handleMultiCheckChange(checked);
|
|
}
|
|
});
|
|
} else {
|
|
panel.handleExpand(node);
|
|
}
|
|
},
|
|
|
|
handleCheckChange() {
|
|
const { panel, value, node } = this;
|
|
panel.handleCheckChange(value);
|
|
panel.handleExpand(node);
|
|
},
|
|
|
|
handleMultiCheckChange(checked) {
|
|
this.node.doCheck(checked);
|
|
this.panel.calculateMultiCheckedValue();
|
|
},
|
|
|
|
isInPath(pathNodes) {
|
|
const { node } = this;
|
|
const selectedPathNode = pathNodes[node.level - 1] || {};
|
|
return selectedPathNode.uid === node.uid;
|
|
},
|
|
|
|
renderPrefix(h) {
|
|
const { isLeaf, isChecked, config } = this;
|
|
const { checkStrictly, multiple } = config;
|
|
|
|
if (multiple) {
|
|
return this.renderCheckbox(h);
|
|
} else if (checkStrictly) {
|
|
return this.renderRadio(h);
|
|
} else if (isLeaf && isChecked) {
|
|
return this.renderCheckIcon(h);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
renderPostfix(h) {
|
|
const { node, isLeaf } = this;
|
|
|
|
if (node.loading) {
|
|
return this.renderLoadingIcon(h);
|
|
} else if (!isLeaf) {
|
|
return this.renderExpandIcon(h);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
renderCheckbox(h) {
|
|
const { node, config, isDisabled } = this;
|
|
const events = {
|
|
on: { change: this.handleMultiCheckChange },
|
|
nativeOn: {}
|
|
};
|
|
|
|
if (config.checkStrictly) { // when every node is selectable, click event should not trigger expand event.
|
|
events.nativeOn.click = stopPropagation;
|
|
}
|
|
|
|
return (
|
|
<el-checkbox
|
|
value={ node.checked }
|
|
indeterminate={ node.indeterminate }
|
|
disabled={ isDisabled }
|
|
{ ...events }
|
|
></el-checkbox>
|
|
);
|
|
},
|
|
|
|
renderRadio(h) {
|
|
let { checkedValue, value, isDisabled } = this;
|
|
|
|
// to keep same reference if value cause radio's checked state is calculated by reference comparision;
|
|
if (isEqual(value, checkedValue)) {
|
|
value = checkedValue;
|
|
}
|
|
|
|
return (
|
|
<el-radio
|
|
value={ checkedValue }
|
|
label={ value }
|
|
disabled={ isDisabled }
|
|
onChange={ this.handleCheckChange }
|
|
nativeOnClick={ stopPropagation }>
|
|
{/* add an empty element to avoid render label */}
|
|
<span></span>
|
|
</el-radio>
|
|
);
|
|
},
|
|
|
|
renderCheckIcon(h) {
|
|
return (
|
|
<i class="el-icon-check el-cascader-node__prefix"></i>
|
|
);
|
|
},
|
|
|
|
renderLoadingIcon(h) {
|
|
return (
|
|
<i class="el-icon-loading el-cascader-node__postfix"></i>
|
|
);
|
|
},
|
|
|
|
renderExpandIcon(h) {
|
|
return (
|
|
<i class="el-icon-arrow-right el-cascader-node__postfix"></i>
|
|
);
|
|
},
|
|
|
|
renderContent(h) {
|
|
const { panel, node } = this;
|
|
const render = panel.renderLabelFn;
|
|
const vnode = render
|
|
? render({ node, data: node.data })
|
|
: null;
|
|
|
|
return (
|
|
<span class="el-cascader-node__label">{ vnode || node.label }</span>
|
|
);
|
|
}
|
|
},
|
|
|
|
render(h) {
|
|
const {
|
|
inActivePath,
|
|
inCheckedPath,
|
|
isChecked,
|
|
isLeaf,
|
|
isDisabled,
|
|
config,
|
|
nodeId
|
|
} = this;
|
|
const { expandTrigger, checkStrictly, multiple } = config;
|
|
const disabled = !checkStrictly && isDisabled;
|
|
const events = { on: {} };
|
|
|
|
if (expandTrigger === 'click') {
|
|
events.on.click = this.handleExpand;
|
|
} else {
|
|
events.on.mouseenter = e => {
|
|
this.handleExpand();
|
|
this.$emit('expand', e);
|
|
};
|
|
events.on.focus = e => {
|
|
this.handleExpand();
|
|
this.$emit('expand', e);
|
|
};
|
|
}
|
|
if (isLeaf && !isDisabled && !checkStrictly && !multiple) {
|
|
events.on.click = this.handleCheckChange;
|
|
}
|
|
|
|
return (
|
|
<li
|
|
role="menuitem"
|
|
id={ nodeId }
|
|
aria-expanded={ inActivePath }
|
|
tabindex={ disabled ? null : -1 }
|
|
class={{
|
|
'el-cascader-node': true,
|
|
'is-selectable': checkStrictly,
|
|
'in-active-path': inActivePath,
|
|
'in-checked-path': inCheckedPath,
|
|
'is-active': isChecked,
|
|
'is-disabled': disabled
|
|
}}
|
|
{...events}>
|
|
{ this.renderPrefix(h) }
|
|
{ this.renderContent(h) }
|
|
{ this.renderPostfix(h) }
|
|
</li>
|
|
);
|
|
}
|
|
};
|
|
</script>
|