Недавно столкнулся с требованием, чтобы содержимое челночной коробки было древовидной структурой данных. Убедитесь, что компонент передачи elementUI не поддерживает древовидные данные, поэтому его нельзя использовать напрямую. Но компонент el-tree это поддерживает, было бы не идеально, если бы компонент дерева и компонент передачи были совмещены.
Подготовить
cloneодна порцияelementисходный код, найтиpackage/tansfer/srcПапка, файл vue внутри — наша цель. Сделать копию в свой проект (скопировать заодно)mixinsвнутреннийemitter.jsа такжеmigrating.js), а затем изменить его.
|-- components
| |-- mixins
| | |-- emitter.js
| | |-- migraing.js
| |-- main.vue
| |-- transfer-panel.vue
использовать
Перед использованиемmain.vue,transfer-panel.vueДва файла для простой модификации. удалятьlocaleсвязанный код.emitter.jsа такжеmigrating.jsПотому что изменение пути должно быть введено повторно. Затем импортируйте его в другие компонентыmain.vueВы можете использовать его (так же, как и при непосредственном использовании el-transfer).
<i-el-transfer v-model="value" :data="data"></i-el-transfer>
...
import iElTransfer from '../components/main'
export default {
name: 'home',
components: {
iElTransfer
},
data () {
return {
data: [
{ key: 1, label: '备选项1', disabled: false },
{ key: 2, label: '备选项2', disabled: false }
...
]
}
}
...
}
Модернизация
Преобразование исходной однослойной структуры в древовидную, у нас есть готовыеel-treeИспользуйте, чтобы заменить область, где отображается исходный контент, наel-treeкомпонентный вид.
# transfer-panel.vue
...
<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>
...
Не волнуйся так, просто замени его на эль-дерево
...
<div v-show="data.length > 0"
:class="{ 'is-filterable': filterable }"
class="el-transfer-panel__list">
<el-tree ref="tree" :data="filteredData"
:node-key="keyProp"
show-checkbox
default-expand-all
:default-checked-keys="checked">
</el-tree>
</div>
...
БудуdataВ структуру дерева, обратитесь к странице
Это тот результат, который нам нужен.Хотя в настоящее время она стала древовидной структурой, которую мы хотим, мы можем найти проблему с помощью одной операции. Продолжайте смотреть код.
sourceData() {
return this.data.filter(item => this.value.indexOf(item[this.props.key]) === -1);
},
targetData() {
if (this.targetOrder === 'original') {
return this.data.filter(item => this.value.indexOf(item[this.props.key]) > -1);
} else {
return this.value.reduce((arr, cur) => {
const val = this.dataObj[cur];
if (val) {
arr.push(val);
}
return arr;
}, []);
}
},
sourceDataа такжеtargetDataиспользуются для отображения данных слева и справа соответственно.this.valueпередается при использовании компонентаv-modelсвязанные данные. здесь черезthis.valueОтфильтруйте данные слева и справа. Затем мы делаем модификацию здесь:
sourceData () {
const data = deepCopy(this.data)
// 有children继续筛选
const filterData = (list) => {
return list.filter(item => {
if (item[this.props.children] && item[this.props.children].length > 0) {
item[this.props.children] = filterData(item.children)
}
return this.value.indexOf(item[this.props.key]) === -1
})
}
return filterData(data)
},
targetData () {
const data = deepCopy(this.data)
const filterData = (list) => {
const res = []
list.forEach(item => {
if (this.value.indexOf(item[this.props.key]) > -1) {
res.push(item)
}
if (item[this.props.children] && item[this.props.children].length > 0) {
const result = filterData(item[this.props.children])
if (result.length > 0) {
item[this.props.children] = result
const find = res.find(i => i.key === item.key)
// res 中没有找到 item,需将 item 加入 res。
// 避免当选中子元素,父元素未选中的时候出现问题
if (find === undefined) {
res.push(item)
}
}
}
})
return res
}
return filterData(data)
},
Я хочу, чтобы данные, добавленные справа, сохраняли ту же структуру, что и данные слева, поэтому я удалил их.targetOrderопции. мы пытаемся изменитьv-modelПривяжите значение, чтобы увидеть эффект.
Вроде так, но добавленных слева и справа функций все же мало. Измените эту часть функции ниже. оказатьсяaddToRightфункция, которая отфильтровывает данные, выбранные пользователем для добавления справа, и данные, которые уже существуют справа, и$emit()Исправлятьthis.valueценность .
addToRight () {
let currentValue = this.value.slice()
const itemsToBeMoved = []
const findSelectkey = (list) => {
const key = this.props.key
const itemsToBeMoved = []
list.forEach(item => {
const itemKey = item[key]
if (
this.leftChecked.indexOf(itemKey) > -1 &&
this.value.indexOf(itemKey) === -1
) {
itemsToBeMoved.push(itemKey)
}
if (item[this.props.children] && item[this.props.children].length > 0) {
itemsToBeMoved.push(...findSelectkey(item[this.props.children]))
}
})
return itemsToBeMoved
}
itemsToBeMoved.push(...findSelectkey(this.data))
currentValue = currentValue.concat(itemsToBeMoved)
this.$emit('input', currentValue)
this.$emit('change', currentValue, 'right', this.leftChecked)
},
По сути, идея та же, если естьchildrenПродолжайте находить младшие данные. Затем изменитеaddToLeftфункция.
addToLeft () {
let currentValue = this.value.slice()
const list = this.rightChecked.concat(this.rightFalfChecked)
list.forEach(item => {
const index = currentValue.indexOf(item)
if (index > -1) {
currentValue.splice(index, 1)
}
})
this.$emit('input', currentValue)
this.$emit('change', currentValue, 'left', this.rightChecked)
},
Я думаю, что если не все дочерние элементы элемента выбраны, то элемент не выбран, поэтому я хочу удалить элемент справаkey. Вот новыйrightFalfCheckedДанные, используемые для представления правильного полувыбранного состояния.
лицевой стороной вверхmain.vueМодификация файла в основном сделана. Мы обнаружили, что также необходимо получитьrightChecked,leftChecked,rightFalfCheckeценность . Исправлятьtransfer-panel.vueфайл, чтобы получить их.el-treeкомпонент имеетcheckсобытие, через которое мы можем получить текущийel-treeкоторые выбраны.
check: срабатывает при нажатии флажка; есть два параметра, по порядку: объект, соответствующий узлу в массиве, переданном в атрибут данных, текущий выбранный объект состояния дерева, включая checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys четыре атрибуты
<el-tree ref="tree" :data="filteredData"
:node-key="keyProp"
show-checkbox
default-expand-all
:default-checked-keys="checked"
@check="handleCheck">
</el-tree>
...
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, this.halfChecked)
} else {
this.$emit('checked-change', val)
this.checkChangeByUser = true
}
}
}
...
handleCheck (cur, checkedInfo) {
const { checkedKeys, halfCheckedKeys } = checkedInfo
this.checked = checkedKeys
this.halfChecked = halfCheckedKeys
}
Суммировать
На этом базовая реализация функции завершена, но есть еще некоторые детали, такие как выбор всего, фильтрация и т. д., которые здесь описываться не будут. по сравнению с оригиналомtransferкомпоненты, удаленные здесьtargetOrder,formatсвойства, другие зарезервированы или изменены. Надеюсь, эта статья поможет вам, вы можете просмотреть полный код по ссылке ниже. Добро пожаловать на общение 🎉️.
Гитхаб:Связь