目次
3. 追加要件: ラジオ ボタンをクリックしてノードを選択すると、次のレベルのオプションが同時にロードされます。
4. 追加要件: ラベルをクリックすると、ノードを直接選択できます。
インターネットで調べてみると、オプションレベルが何層ではなく3層に固定されている記事が多く、まだ不明な点が多いのですが、ピットを踏んだ経験をまとめてみました。みんなの役に立つように。
要件の説明
フロントエンドは el-cascader コンポーネントを使用して階層セレクターを実装し、ノードの単一または複数の選択をサポートできます。ノードの階層関係と名前はバックエンドによって定義および制御され、フロントエンドはデータに従ってレンダリングしますバックエンドによって提供されます。
この効果を実現するには、バックエンドと連携して 2 つのインターフェイスを提供する必要があります。
1. インターフェイス 1: フロント エンドは指定されたノード ID を渡し、バック エンドはノードの次の層にあるすべてのノード ID 情報のリストを返します。
2. インターフェイス 2: フロント エンドは指定されたノード ID を渡し、バック エンドは最上位の親ノードからそのノードまでのノードのすべてのパス ノード ID のリストを返します。
カスケード セレクター el-cascader は、
最も重要なのは、v-model バインディング値と props 構成項目の 2 つの項目のみです。
<el-cascader
v-model="IdList"
:props="props"
></el-cascader>
1. 動的読み込みオプションを実装する
一般的な props 構成:
動的読み込みオプションには次のオプション構成は必要ありません。通常は静的オプション構成が使用されます。
- checkStrictly: true トランクノードをオプションとして選択できるかどうか (実際のニーズに応じて選択してください)
- Lazy: true ノードを動的にロードするかどうか (もちろん、これが必要なものです)
- LazyLoad: this.loadTreeNode はノードをロードするメソッドを指定します。ここでは、loadTreeNodeという名前を定義します。
- multiple: true 複数選択をサポートするかどうか
props: {
checkStrictly: true, //是否可以选择树干节点作为选项
lazy: true, // 是否动态加载子节点
// lazyLoad加载动态数据的方法(仅在 lazy 为 true 时有效)
lazyLoad: this.loadTreeNode,
},
loadTreeNode 、ノードをロードするカスタム メソッド (具体的なロジックはコメントで確認できます):
//加载树节点 首次加载页面时就会执行一次,之后每选中一个节点也会调用,来渲染下一层
loadTreeNode(node, resolve) {
console.log(node);
// 首次加载时 node为{root:true,level:0}
// node 节点数据 获取node的level字段的值
const { level } = node;
//下一层节点
const nodes = [];
//如果有子节点 或者 为根节点(即首次进入level为0)
//也有人写成 node.level == 0 作用是一样的
if (node.hasChildren || node.root) {
// 0 代表第一次请求
let nodeId = level == 0 ? null : node.value;
//这里setTimeout的目的是 显示加载动画
setTimeout(() => {
//调用后端接口 获得返回数据
let ret = this.api(nodeId);
if (ret && ret.succeeded) {
//ret.reulst为后端返回的数据
let nodes = ret.result;
// 回调渲染下一层
resolve(nodes);
} else {
//后端报错 弹窗提示失败
this.$message({
type: "error",
message: "部门层级加载失败,请联系管理员!",
});
}
}, 1);
} else {
//如果没有子节点就不发起请求,直接渲染,也避免了点击叶子节点仍然有加载动画的问题
resolve(nodes);
}
},
リーフ ノード - 意味: 子ノードのないノード。最下層です。
ここで、 this.api は呼び出し元のバックエンドによって提供される最初のインターフェイスを指します。
インターフェイス 1: フロント エンドは、指定されたノード ID を渡し、ノードの次の層のすべてのノード ID 情報のリストを返します (nodeId が空の場合は、最初の層のノードを返します)。
返されるデータはリストである必要があり、バックエンドによって返されるデータ List<UserGroupTreeNode> は次のようになります。
JAVA バックエンドのノード定義は以下を参照できます。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserGroupTreeNode {
/**
* 节点值
*/
private String value;
/**
* 节点标签
*/
private String label;
/**
* 是否为叶子节点(即没有子节点) true 没有子节点 false 有子节点
*/
private Boolean leaf;
}
このうち、valueはノードのID、labelは表示名、leafは子ノードを含むかどうか、Bool型です。
値、ラベル、およびリーフ変数名は一貫している必要があります。そうでない場合は、フロントエンドがデータを取得した後、それを独自にこの変数名に変換する必要があります。
現時点では、このコンポーネントは通常どおり使用できます。
2. データエコー問題
問題の説明: 階層セレクターのデータレンダリングの問題は上記で解決されており、クエリまたは新規追加には十分です。しかし、データを変更する必要がある場合、「変更」をクリックして開くポップアップ ウィンドウ内の対応するフィールドは正しくエコーできません。
理想的な状況: レイヤーごとに表示され、クリックして変更すると、レイヤー セレクター コンポーネントがデフォルトで境界値を選択する必要があります。
実際の状況: 開いた後、レイヤーごとに選択する必要がありますが、これは明らかに実際のニーズを満たしていません。
解決策:
1. まず、データを追加するとき、カスケード セレクター v-model によってバインドされるパラメーターはリストです。
例: ノード [sub-1-2-3] を選択すると、
実際にバインドされる値は ["root","sub-1","sub-1-2","sub-1-2-3"] です。
実際にバックエンドに保存される値は通常、選択したノードの ID、つまり「sub-1-2-3」です。
2. el-cascader コンポーネントにバインドされた値はリストであることが知られているため、正しくエコーする必要がある場合は、それに配列を割り当てる必要もあります。
したがって、バックエンドと合意された2 番目のインターフェイスが必要です
インターフェイス 2: フロント エンドは指定されたノード ID を渡し、バック エンドは最上位の親ノードからそのノードまでのすべてのパスのノード ID リストを返します。
形式は次の図に示すとおりですが、順序は実際のノード階層の順序と一致している必要があることに注意してください。
ここで返されるのはノードの ID 配列リストです。
フロントエンドがそれを取得した後、el-cascader コンポーネントの v-model にバインドされた変数に直接割り当てることができます。
そうすれば普通に表示できるようになりますよ!
こうして処理は完了しましたが、element-uiのバグと言うべき問題がまだ残っています。
シナリオの説明:初めてページをロードした後のみ、データ A を編集するとき、データ A のエコーは正常ですが、ポップアップ ウィンドウを閉じてから、他のデータを編集します。このとき、エルのテキスト ボックスに-cascader コンポーネントを変更ポップアップ ウィンドウに追加すると、エコーがすべて空になり、正常にエコーされなくなります。
なぜなら:
初めてデータを編集するとき、el-cascader は v-model に従ってパラメーター値をバインドします。
例: ["1","2","3","4"] この配列
ツリー構造全体を取得するには、Layer Load をレイヤーごとに呼び出します。
つまり、「1」、「2」、「3」、「4」をパラメータとして順番に受け取り、lazyLoad を呼び出して、ヘッド ノード「1」、ヘッド ノードの次の層、およびその ID を持つ次のノードをそれぞれレンダリングします。は「2」のレイヤー、その次のレイヤーにはID「3」のレイヤーがあり、最後にそれらをマージします。
プロセス全体はコンポーネントによって自動的に実行されます。
したがって、正しくエコーすることができます。
ただし、編集ポップアップ ウィンドウが閉じられ、他のデータが編集されると、el-cascader コンポーネントの v-model にバインドされたパラメーター値が変更されても、lazyLoad メソッドの呼び出しはトリガーされず、バックエンドを使用して、構造ツリー全体をレイヤーごとにレンダリングします。
現在、オンライン ソリューションには一般に 2 つのアイデアがあります。
- 1. options オプションを el-cascader コンポーネントにバインドします。v-model バインディング パラメーターの値、つまり配列の値に従って、手動でバックエンド インターフェイスを呼び出し、次のレイヤーのオプションを取得します。それらを 1 つずつ結合してツリー構造にし、ツリーを生成します。この構造は、正しくエコーできるように el-cascader によって使用されます。このアイデアは、実際には、lazyLoad のロジックを自分で記述し、公式の LayLoad メソッドの使用を放棄することです (推奨されません)。
- 2. el-cascaderコンポーネントを再レンダリングする 初回ロード時はlazyLoadが正しく呼び出せるので、初回ロード時と同じように毎回やり直すのが良い という考え方です。 v-if を使用して解決します (推奨)。
方法 1 は実装するには複雑すぎますが、方法 2 ははるかに簡単なので、方法 2 をお勧めします。
また、公式の element-ui でこの問題が修正され、心配する必要がなくなることを願っています。
方法 2:
v-if="editCascaderVisible" を el-cascader コンポーネントに追加します
<el-cascader
v-if="editCascaderVisible"
v-model="IdList"
:props="props"
></el-cascader>
次に editRow で、つまり変更ポップアップ メソッドを開いたときに、一度更新するように手動で制御します。
キーコード:
this.editCascaderVisible = false;
// 这里搞个定时器重新载入一下组件就可以触发组件拉取数据
setTimeout(() => {
this.editCascaderVisible = true;
}, 1);
完全なコード:
editRow(rowData) {
this.editCascaderVisible = false;
// 这里搞个定时器重新载入一下组件就可以触发组件拉取数据
setTimeout(() => {
this.editCascaderVisible = true;
}, 1);
this.IdList= [];
//在编辑的时候等到DOM更新完成再赋值
this.$nextTick(() => {
//将选中数据的值 赋值给表单
this.dataForm = Object.assign({}, rowData);
});
//调用后端接口,获取自顶向下逐个层级ID的列表 这里我el-cascader绑定的变量是IdList
this.IdList= this.api_getIdList(rowData.groupId);
//打开修改弹窗
this.dialogVisible = true;
}
このようにして、編集をクリックするたびに正しくエコーすることができます。
3. 追加要件: ラジオ ボタンをクリックしてノードを選択すると、次のレベルのオプションが同時にロードされます。
シナリオ説明: [万州出張所]ラベルの左側にあるラジオボタンを直接クリックすると、選択操作のみが実行され、この時点では[万州出張所]の下部機関は読み込まれません。しかし、実際の使用では、クリックして選択すると、次のレベルの制度オプションを確認しますか?
LazyLoad モードを使用しているため、ラジオ ボタンをクリックしても、図に示すように、次のレベルのオプションの読み込みはトリガーされません。
問題解決のアイデア:
既知: オプションのテキスト ラベル、ラベル、コンポーネントをクリックすると、次のレベルのノードの読み込みがトリガーされます。
したがって、ノードを選択するときに、change メソッドを使用して次のレベルのノードを手動でロードできます。
選択したノードが変更されると、変更メソッドがトリガーされますが、このとき、テキスト ラベル、つまり Label のクリックをシミュレートするメソッドをカスタマイズして問題を解決します。ページ レイアウトでは、ラジオ ボタンの同じレベルにある次の要素はラベルであるため、domを使用して同じレベルにある次の要素を取得し、クリックイベントを手動で実行します。
実装コード:
<el-cascader
@change="handleChange"
v-if="editCascaderVisible"
v-model="IdList"
:props="props"
></el-cascader>
//处理单选点击事件
handleChange(e) {
this.$nextTick(() => {
const dom = document.getElementsByClassName("el-radio is-checked");
//这里我把dom打出来看了 最后一个选项才是我选中的节点 即[length-1] 有的博主写的是 第一个元素 即[0] 大家自行尝试
let radioDom = dom[dom.length - 1];
const brother = radioDom.nextElementSibling;
brother.click();
});
},
4. 追加要件: ラベルをクリックすると、ノードを直接選択できます。
シナリオの説明: 単一選択の場合、特定のノード オプションを選択するには、ラジオ ボタンをクリックする必要がありますが、ラジオ自体が小さいため、クリックできる領域も小さくなります。直接クリックしたい場合は、良い目をもつために そうですね、それはあまり便利ではありません。タブをクリックして直接選択できればいいのですが。
解決策: クリック領域は非常に小さいため、CSS を使用して本体を拡大します。ラジオ ボックスの範囲をラベル範囲全体に拡大します。ラベルをクリックすると、ラジオ ボックスをクリックするのと同じになります。
実装コード:
<style>
/*单选的级联选择器,点击标签页就可以选中*/
.el-cascader-menu .el-radio {
display: table;
vertical-align: middle;
width: 100%;
height: 100%;
position: absolute;
box-sizing: border-box;
margin-left: -25px;
padding-left: 15px;
margin-top: 6px;
}
.el-cascader-menu .el-radio .el-radio__input {
display: table-cell;
vertical-align: middle;
}
</style>
添付します(記録してください。読む必要はありません):
解決プロセス中の el-cascader コンポーネントの理解を記録します 。
<el-cascader
ref="editCascader"
v-model="departmentIdList"
:props="propsSearch"
placeholder="请选择业务部门"
style="width: 15vw"
></el-cascader>
refを追加すると、使用できます
this.$refs.editCascader.panel
el-cascader オブジェクトを取得する
使える
this.$refs.editCascader.panel.lazyLoad(cqbankNode);
LazyLoad バインディング メソッドをアクティブに呼び出します。受信ノードには chidren フィールドがあるか、直接
let cqbankNode = this.$refs.editCascader.panel.menus[0][0];
メニューはメニュー項目です
メニュー[0]は最初のドロップダウン ボックス リストです。
メニュー[1] は 2 番目のドロップダウン ボックス リストです。メニューを変更してドロップダウン ボックスの表示列を変更できます。
しかし、取得するメニュー[0][0]によると、ノードの子が空である場合があります。別の属性を使用して取得する必要があるかもしれません。このアイデアも可能なはずです。その時点では、値属性のソースが間違っていました。空だと書けない、と考えが変わりました。