提交
This commit is contained in:
251
src/views/components/transfer/transfer-panel.vue
Normal file
251
src/views/components/transfer/transfer-panel.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="el-transfer-panel">
|
||||
<p class="el-transfer-panel__header">
|
||||
<el-checkbox
|
||||
v-model="allChecked"
|
||||
@change="handleAllCheckedChange"
|
||||
:indeterminate="isIndeterminate">
|
||||
{{ title }}
|
||||
<span>{{ checkedSummary }}</span>
|
||||
</el-checkbox>
|
||||
</p>
|
||||
|
||||
<div :class="['el-transfer-panel__body', hasFooter ? 'is-with-footer' : '']">
|
||||
<el-input
|
||||
class="el-transfer-panel__filter"
|
||||
v-model="query"
|
||||
size="small"
|
||||
:placeholder="placeholder"
|
||||
@mouseenter.native="inputHover = true"
|
||||
@mouseleave.native="inputHover = false"
|
||||
v-if="filterable">
|
||||
<i slot="prefix"
|
||||
:class="['el-input__icon', 'el-icon-' + inputIcon]"
|
||||
@click="clearQuery"
|
||||
></i>
|
||||
</el-input>
|
||||
<el-checkbox-group
|
||||
v-model="checked"
|
||||
v-show="!hasNoMatch && data.length > 0"
|
||||
:class="{ 'is-filterable': filterable }"
|
||||
class="el-transfer-panel__list">
|
||||
<el-checkbox
|
||||
class="el-transfer-panel__item"
|
||||
:label="item[keyProp]"
|
||||
:disabled="item[disabledProp]"
|
||||
:key="item[keyProp]"
|
||||
v-for="item in filteredData">
|
||||
<option-content :option="item"></option-content>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<p
|
||||
class="el-transfer-panel__empty"
|
||||
v-show="hasNoMatch">{{ t('el.transfer.noMatch') }}</p>
|
||||
<p
|
||||
class="el-transfer-panel__empty"
|
||||
v-show="data.length === 0 && !hasNoMatch">{{ t('el.transfer.noData') }}</p>
|
||||
</div>
|
||||
<p class="el-transfer-panel__footer" v-if="hasFooter">
|
||||
<slot></slot>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ElCheckboxGroup from 'element-ui/packages/checkbox-group';
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import ElInput from 'element-ui/packages/input';
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
|
||||
export default {
|
||||
mixins: [Locale],
|
||||
|
||||
name: 'ElTransferPanel',
|
||||
|
||||
componentName: 'ElTransferPanel',
|
||||
|
||||
components: {
|
||||
ElCheckboxGroup,
|
||||
ElCheckbox,
|
||||
ElInput,
|
||||
OptionContent: {
|
||||
props: {
|
||||
option: Object
|
||||
},
|
||||
render(h) {
|
||||
const getParent = vm => {
|
||||
if (vm.$options.componentName === 'ElTransferPanel') {
|
||||
return vm;
|
||||
} else if (vm.$parent) {
|
||||
return getParent(vm.$parent);
|
||||
} else {
|
||||
return vm;
|
||||
}
|
||||
};
|
||||
const panel = getParent(this);
|
||||
const transfer = panel.$parent || panel;
|
||||
return panel.renderContent
|
||||
? panel.renderContent(h, this.option)
|
||||
: transfer.$scopedSlots.default
|
||||
? transfer.$scopedSlots.default({ option: this.option })
|
||||
: <span>{ this.option[panel.labelProp] || this.option[panel.keyProp] }</span>;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
renderContent: Function,
|
||||
placeholder: String,
|
||||
title: String,
|
||||
filterable: Boolean,
|
||||
format: Object,
|
||||
filterMethod: Function,
|
||||
defaultChecked: Array,
|
||||
props: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
checked: [],
|
||||
allChecked: false,
|
||||
query: '',
|
||||
inputHover: false,
|
||||
checkChangeByUser: true
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
checked(val, oldVal) {
|
||||
this.updateAllChecked();
|
||||
if (this.checkChangeByUser) {
|
||||
const movedKeys = val.concat(oldVal)
|
||||
.filter(v => val.indexOf(v) === -1 || oldVal.indexOf(v) === -1);
|
||||
this.$emit('checked-change', val, movedKeys);
|
||||
} else {
|
||||
this.$emit('checked-change', val);
|
||||
this.checkChangeByUser = true;
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
const checked = [];
|
||||
const filteredDataKeys = this.filteredData.map(item => item[this.keyProp]);
|
||||
this.checked.forEach(item => {
|
||||
if (filteredDataKeys.indexOf(item) > -1) {
|
||||
checked.push(item);
|
||||
}
|
||||
});
|
||||
this.checkChangeByUser = false;
|
||||
this.checked = checked;
|
||||
},
|
||||
|
||||
checkableData() {
|
||||
this.updateAllChecked();
|
||||
},
|
||||
|
||||
defaultChecked: {
|
||||
immediate: true,
|
||||
handler(val, oldVal) {
|
||||
if (oldVal && val.length === oldVal.length &&
|
||||
val.every(item => oldVal.indexOf(item) > -1)) return;
|
||||
const checked = [];
|
||||
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]);
|
||||
val.forEach(item => {
|
||||
if (checkableDataKeys.indexOf(item) > -1) {
|
||||
checked.push(item);
|
||||
}
|
||||
});
|
||||
this.checkChangeByUser = false;
|
||||
this.checked = checked;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredData() {
|
||||
return this.data.filter(item => {
|
||||
if (typeof this.filterMethod === 'function') {
|
||||
return this.filterMethod(this.query, item);
|
||||
} else {
|
||||
const label = item[this.labelProp] || item[this.keyProp].toString();
|
||||
return label.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
checkableData() {
|
||||
return this.filteredData.filter(item => !item[this.disabledProp]);
|
||||
},
|
||||
|
||||
checkedSummary() {
|
||||
const checkedLength = this.checked.length;
|
||||
const dataLength = this.data.length;
|
||||
const { noChecked, hasChecked } = this.format;
|
||||
if (noChecked && hasChecked) {
|
||||
return checkedLength > 0
|
||||
? hasChecked.replace(/\${checked}/g, checkedLength).replace(/\${total}/g, dataLength)
|
||||
: noChecked.replace(/\${total}/g, dataLength);
|
||||
} else {
|
||||
return `${ checkedLength }/${ dataLength }`;
|
||||
}
|
||||
},
|
||||
|
||||
isIndeterminate() {
|
||||
const checkedLength = this.checked.length;
|
||||
return checkedLength > 0 && checkedLength < this.checkableData.length;
|
||||
},
|
||||
|
||||
hasNoMatch() {
|
||||
return this.query.length > 0 && this.filteredData.length === 0;
|
||||
},
|
||||
|
||||
inputIcon() {
|
||||
return this.query.length > 0 && this.inputHover
|
||||
? 'circle-close'
|
||||
: 'search';
|
||||
},
|
||||
|
||||
labelProp() {
|
||||
return this.props.label || 'label';
|
||||
},
|
||||
|
||||
keyProp() {
|
||||
return this.props.key || 'key';
|
||||
},
|
||||
|
||||
disabledProp() {
|
||||
return this.props.disabled || 'disabled';
|
||||
},
|
||||
|
||||
hasFooter() {
|
||||
return !!this.$slots.default;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateAllChecked() {
|
||||
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]);
|
||||
this.allChecked = checkableDataKeys.length > 0 &&
|
||||
checkableDataKeys.every(item => this.checked.indexOf(item) > -1);
|
||||
},
|
||||
|
||||
handleAllCheckedChange(value) {
|
||||
this.checked = value
|
||||
? this.checkableData.map(item => item[this.keyProp])
|
||||
: [];
|
||||
},
|
||||
|
||||
clearQuery() {
|
||||
if (this.inputIcon === 'circle-close') {
|
||||
this.query = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user