Le travail ne s'arrête pas,Plus que le Code,J'ai encore un double.
La boîte de navette de liste et la boîte de navette d'arbre unique ont été implémentées auparavant,Cette fois, il s'agit principalement de réaliser un cadre de navette arborescent complet,Structure arborescente à gauche et à droite du cadre de la navette,Et les noeuds parents - enfants sont liés,Ou pour le choix de la ville.
L'effet de réalisation est montré dans la figure:
Principaux points fonctionnels:
Dans la présentation de code suivante,.Le traitement à gauche et à droite du cadre de navette est essentiellement le même,Prenons l'exemple de la boîte de données source gauche seulement
UI En gros, le style du site officiel imité,Les noms de style sont également directement tirés du site officiel,Pratique et rapide...
Le Code d'implémentation est le suivant:
<template>
<div class="tree-transfer ant-transfer ant-transfer-customize-list">
<!-- Boîte de données source -->
<div class="ant-transfer-list">
<!-- Barre de tête -->
<div class="ant-transfer-list-header">
<a-checkbox :indeterminate="from_is_indeterminate" v-model="from_check_all" @change="fromAllBoxChange" />
<span class="ant-transfer-list-header-selected">
<span >{{ from_check_keys.length || 0 }}/{{ from_all_keys.length }} {{
locale.itemUnit }}</span
>
<span class="ant-transfer-list-header-title">{{ fromTitle }}</span>
</span>
</div>
<!-- Contenu principal -->
<div class="ant-transfer-list-body ant-transfer-list-body-with-search">
<!-- Boîte de recherche -->
<div v-if="filter" class="ant-transfer-list-body-search-wrapper">
<div>
<a-input v-model="filterFrom" :placeholder="locale.searchPlaceholder" class="ant-transfer-list-search" />
<a class="ant-transfer-list-search-action">
<a-icon type="close-circle" theme="filled" v-if="filterFrom && filterFrom.length > 0" @click="filterFrom = ''" />
<a-icon type="search" v-else />
</a>
</div>
</div>
<!-- Liste des arbres -->
<div class="ant-transfer-list-body-customize-wrapper">
<a-tree ref="from-tree" class="tt-tree from-tree" blockNode checkable :checked-keys="from_check_keys" :expanded-keys="from_expand_keys" :tree-data="self_from_data" @check="fromTreeChecked" @expand="fromTreeExpanded" :style="{ height: treeHeight + 'px' }" />
</div>
</div>
</div>
<!-- Barre d'action -->
<div class="ant-transfer-operation">
<a-button type="primary" @click="addToAims(true)" shape="circle" :disabled="from_disabled" icon="right" ></a-button>
<a-button type="primary" @click="removeToSource" shape="circle" :disabled="to_disabled" icon="left" ></a-button>
</div>
<!-- Boîte de données cible -->
<!-- Omis ici, Comme les données sources -->
</div>
</template>
Copier le Code
L'effet de réalisation est montré dans la figure:
Affichage à gauche et à droite du cadre de navette ,Essentiellement le traitement des données, Ensuite, concentrez - vous sur la façon dont les données sont traitées .
dataSource
Et de la zone de données cible targetKeys
Ensemble(Ici.targetKeys
Seulement pour les villes id, À l'exclusion des provinces id)targetKeys
( Sélectionnez à droite key Ensemble)Nom du paramètre | Type | Est - ce nécessaire? | Remarques |
---|---|---|---|
dataSource | Array | Y | Source des données |
targetKeys | Array | Y | Données de la boîte de droite key Ensemble |
titles | Array | N | Titre de la tête ,Par défaut[" Liste des sources ", "Liste des objectifs"] |
locale | Object | N | Éléments de configuration |
filter | Boolean | N | Afficher la boîte de recherche |
replaceFields | Object | N | Remplacer treeData Champ correspondant dans |
data() {
return {
data_source: [...this.dataSource], // Source des données
target_keys: [], // Données de la boîte de droite key Ensemble
from_is_indeterminate: false, // Si les données sources sont à moitié sélectionnées
from_check_all: false, // Si toutes les données sources sont sélectionnées
to_is_indeterminate: false, // Si les données cibles sont à moitié sélectionnées
to_check_all: false, // Si toutes les données cibles sont sélectionnées
from_disabled: true, // Si le bouton Ajouter est désactivé
to_disabled: true, // Si le bouton Supprimer est désactivé
from_check_keys: [], // Données sources sélectionnées keyTableau Associer le bouton navette à cette propriété , Sélection générale 、 Demi - sélection
to_check_keys: [], // Données cibles sélectionnées keyTableau Associer le bouton navette à cette propriété , Sélection générale 、 Demi - sélection
from_expand_keys: [], // Expansion des données sources keyTableau
to_expand_keys: [], // Expansion des données cibles keyTableau
from_all_keys: [], // Données sources toutes les key
to_all_keys: [], // Données cibles toutes les key
filterFrom: "", // Filtrage des données sources
filterTo: "", // Filtrage des données cibles
};
}
Copier le Code
target_keys
Et filterFrom
Filtrer les données. (1) Filtre de données source contenant target_keys
Données. (2) Les données cibles ne sont conservées que pour contenir target_keys
Donnéescomputed: {
// Données sources
self_from_data() {
// Filtrage des données sources
let from_array = filterSourceTree(
this.data_source,
this.target_keys,
this.filterFrom,
this.replaceFields
);
// === Pour sélectionner tout 、 Traitement de l'état semi - sélectionné ====
// Obtenir les données de la source tous les keyEnsemble
this.from_all_keys = this.getAllKeys(from_array);
// Obtenir toutes les données sources sélectionnées keyEnsemble
this.from_check_keys = this.from_check_keys.filter((key) =>
this.from_all_keys.includes(key)
);
return from_array;
},
// Nom du menu de données source
fromTitle() {
let [text] = this.titles;
return text;
}
}
Copier le Code
watch: {
/* Gauche Surveillance de l'état */
from_check_keys(val) {
if (val.length > 0) {
// Si le bouton navette est désactivé
this.from_disabled = false;
// Demi - sélection totale ouverte
this.from_is_indeterminate = true;
// Sélection totale ouverte ou non : Selon que le nombre de noeuds racine dans le noeud sélectionné est égal à la longueur des données source
// Obtenir toutes les provinces keyEnsemble
let allParentKeys = this.self_from_data.map(
(item) => item[this.replaceFields.key]
);
// Obtenir tous les keyEnsemble
let allCheck = val.filter((item) => allParentKeys.includes(item));
// 1. Afficher toutes les sélections lorsqu'elles sont égales
if (allCheck.length == this.self_from_data.length) {
// Éteignez les demi - sélections Activer la sélection complète
this.from_is_indeterminate = false;
this.from_check_all = true;
} else {
// 2. Sinon, Sélection partielle
this.from_is_indeterminate = true;
this.from_check_all = false;
}
} else {
// 3. Quand elle n'est pas sélectionnée , Statut non sélectionné
this.from_disabled = true;
this.from_is_indeterminate = false;
this.from_check_all = false;
}
}
}
Copier le Code
/* Données sources Sélection générale checkbox */
fromAllBoxChange(val) {
if (this.self_from_data.length == 0) {
return;
}
if (val.target.checked) {
this.from_check_keys = this.getAllKeys(this.self_from_data);
} else {
this.from_check_keys = [];
}
this.$emit("left-check-change", this.from_check_all);
}
Copier le Code
getAllKeys(data) {
let result = [];
data.forEach((item) => {
result.push(item[this.replaceFields.key]);
if (item.children && item.children.length) {
item.children.forEach((o) => {
result.push(o[this.replaceFields.key]);
});
}
});
return result;
}
Copier le Code
Déclenché lorsque la case à cocher est cliquée ,Utilisation directeTree
De@check
Gestion des événements
fromTreeChecked(checkedKeys, e) {
this.from_check_keys = checkedKeys;
}
Copier le Code
Déploiement/ Déclenché lorsque le noeud est arrimé ,Utilisation directeTree
De@expand
Gestion des événements
fromTreeExpanded(expandedKeys) {
this.from_expand_keys = expandedKeys;
}
Copier le Code
[
{
id: "1000",
pid: "0",
value: "Province de Hubei",
label: "Province de Hubei",
children: [
{ id: "1001", pid: "1000", label: "Wuhan" },
{ id: "1020", pid: "1000", label: "Xianning" },
{ id: "1022", pid: "1000", label: "Sens de la piété filiale" },
{ id: "1034", pid: "1000", label: "Xiangyang" },
{ id: "1003", pid: "1000", label: "Yichang" },
],
},
{
id: "1200",
pid: "0",
value: "Province du Jiangsu",
label: "Province du Jiangsu",
children: [
{ id: "1201", pid: "1200", label: "Nanjing" },
{ id: "1202", pid: "1200", label: "Suzhou" },
{ id: "1204", pid: "1200", label: "Yangzhou" },
],
},
];
Copier le Code
Les données déjà sélectionnées n'apparaissent pas dans la zone de données source , Filtrez - le juste
const filterSourceTree = ( tree = [], targetKeys = [], keyword = "", replaceFields ) => {
if (!tree.length) {
return [];
}
const result = [];
for (let item of tree) {
if (item[replaceFields.title].includes(keyword)) {
if (item.children && item.children.length) {
let ele = { ...item, children: [] };
for (let o of item.children) {
if (targetKeys.includes(o[replaceFields.key])) continue;
ele.children.push(o);
}
if (ele.children.length) {
result.push(ele);
}
}
} else {
if (item.children && item.children.length) {
let node = { ...item, children: [] };
for (let o of item.children) {
if (
!(
!targetKeys.includes(o[replaceFields.key]) &&
o[replaceFields.title].includes(keyword)
)
)
continue;
node.children.push(o);
}
if (node.children.length) {
result.push(node);
}
}
}
}
return result;
};
let leftSource = filterSourceTree(
this.provinceData,
// Wuhan,Xianning,Nanjing
["1001", "1020", "1201"],
"",
this.replaceFields
);
console.log(leftSource);
Copier le Code
Les données déjà sélectionnées n'apparaîtront que dans la zone de données cible
const filterTargetTree = ( tree = [], targetKeys = [], keyword = "", replaceFields ) => {
if (!tree.length) {
return [];
}
const result = [];
for (let item of tree) {
if (item[replaceFields.title].includes(keyword)) {
if (item.children && item.children.length) {
let ele = { ...item, children: [] };
for (let o of item.children) {
if (!targetKeys.includes(o[replaceFields.key])) continue;
ele.children.push(o);
}
if (ele.children.length) {
result.push(ele);
}
}
} else {
if (item.children && item.children.length) {
let node = { ...item, children: [] };
for (let o of item.children) {
if (
!(
targetKeys.includes(o[replaceFields.key]) &&
o[replaceFields.title].includes(keyword)
)
)
continue;
node.children.push(o);
}
if (node.children.length) {
result.push(node);
}
}
}
}
return result;
};
// Traitement des données cibles
let rightSource = filterTargetTree(
this.provinceData,
["1001", "1020", "1201"],
"",
this.replaceFields
);
console.log(rightSource);
this.provinceData = rightSource;
Copier le Code
Fonctions précédentes filterSourceTree
,filterTargetTree
Les mots clés et les données cibles sont filtrés simultanément , Plus grossier , Et seulement pour la structure de l'arbre secondaire ,Faible extensibilité. Ensuite, il a été optimisé .
Les fonctions spécifiques sont visibles : Résumé des opérations courantes pour les données de structure de l'arbre frontal
computed: {
// Données sources
self_from_data() {
// Filtre de données sélectionné
let from_array = filterSourceTreeFn(this.data_source, this.target_keys);
// Filtrage des mots clés
if (this.filterFrom) {
from_array = filterKeywordTreeFn(from_array, this.filterFrom);
}
return from_array;
},
}
Copier le Code
computed: {
// Données cibles
self_to_data() {
// Conservation des données sélectionnée
let to_array = filterTargetTreeFn(this.data_source, this.target_keys);
// Filtrage des mots clés
if (this.filterTo) {
to_array = filterKeywordTreeFn(to_array, this.filterTo);
}
return to_array;
},
}
Copier le Code