jonmiles/bootstrap-treeview踩坑記錄(吐槽下checkNode和expandNode方法使用)


現在在2020年了,jonmiles/bootstrap-treeview 項目已經歸檔了,並且最后一次更新在2015年。但是,項目中使用到了這個庫,所以,沒得選擇,只能糞不顧身跳入坑里。

這篇文章主要吐槽bootstrap-treeview的兩個方法:checkNodeexpandNode 的使用。

checkNode 方法

顧名思義,這個方法用來勾選 node 節點。根據文檔說明:

checkNode 方法的第一個參數可以是 node 對象或者 nodeId 數字。這里要特別注意 nodeId 數字,並不是想當然的初始化 treeview 所傳入的 data 屬性中對象的 id 字段。原先我也先入為主的以為是 data 對象中的 id 字段,但是發現不是,於是閱讀了源代碼。

	/*
		Identifies a node from either a node id or object
	*/
	Tree.prototype.identifyNode = function (identifier) {
		return ((typeof identifier) === 'number') ?
						this.nodes[identifier] :
						identifier;
	};

identifyNode 方法,用來通過 identifier 標識來返回 node 對象。如果 identifier 是數字,就返回 this.nodes[identifier],否則原樣返回。

由於要找的是 identifier 是數字時所代表的含義,找到 setInitialStates 方法,它用來初始化所有節點及節點的狀態:

	Tree.prototype.setInitialStates = function (node, level) {

		if (!node.nodes) return;
		level += 1;

		var parent = node;
		var _this = this;
		$.each(node.nodes, function checkStates(index, node) {

			// nodeId : unique, incremental identifier
			node.nodeId = _this.nodes.length;

	// 中間代碼省略...

			// index nodes in a flattened structure for use later
			_this.nodes.push(node);

			// recurse child nodes and transverse the tree
			if (node.nodes) {
				_this.setInitialStates(node, level);
			}
		});
	};

從這兩行關鍵代碼可以看出來 nodeId 是從 0 開始的自增的整數,而並非 data 對象中的 id 字段:

			// nodeId : unique, incremental identifier
			node.nodeId = _this.nodes.length;

	// 中間代碼省略...

			// index nodes in a flattened structure for use later
			_this.nodes.push(node)

啰嗦一大堆,結論就是 nodeId 是 treeview 自動生成的從 0 開始的自增整數。那解決想通過 data 對象中的 id 字段來實現 checkNode 該怎么做呢?

分為兩步,要在 bootstrap-treeview 新增一行代碼,並且使用這一行新增的代碼:

#1

bootstra-treeview.js 的源碼里的 var Tree = function () { ... } 最后 return 返回的對象中新增一行代碼:

			findNodes: $.proxy(this.findNodes, this)

#2

完成 1 步驟后,我們就可以在源碼外調用 findNodes 方法。這個方法很強大,可以通過正則表達式查找 nodes 節點中的指定屬性的內容,並返回所有匹配的節點,findNodes 的源碼:

使用 findNodes 方法,就能夠根據 id 屬性查找所需的節點,然后傳入 checkNodes 方法里:

var node = $('#target').treeview('findNodes', ['^' + n + '$', 'g', 'id']);
if (!node || !node.length) {
    return;
}
$('#target').treeview('checkNode', node);

$('#target').treeview('findNodes', ['^' + n + '$', 'g', 'id']) 是含義是查找 nodes 節點中 id 屬性值等於變量 n 的所有節點。

expandNode 方法

expandNode 方法用來展開指定的 node 節點,根據文檔說明:

expandNode 方法的第一個參數和 checkNode 方法的一樣,可以接受 node 對象或者 nodeId 數字。第二個參數可選傳入 levels 指定要展開節點的層級。默認就是 1 了,只展開一層;如果 levels: 2,那么會展開兩層。

實際情況中,使用了 checkNode 方法勾選節點后,想要自動展開這些節點,按照 expandNode 方法的實現是完成不了這個需求的。比方說,勾選了第三層級的 C 節點,要實現自動展開這個節點,需要先展開 C 節點的父節點(位於第二層級的某節點),再展開 C 節點的父節點的父節點(位於第一層級的某節點)。

把這個需求用代碼實現,方法取名為 expandRealNode(這才是我心目中的展開節點方法:-D):

#1

Tree.prototype.expandNode = function (identifiers, options) { ... } 的后面加上如下代碼:

	Tree.prototype.expandRealNode = function (identifiers, options) {
		this.forEachIdentifier(identifiers, options, $.proxy(function (node, options) {
			var real = node;
			while (true) {
				real = this.getParent(real);
				console.log(real);
				if (!real || !real.hasOwnProperty('nodeId')) {
					break;
				}
				this.setExpandedState(real, true, options);
			}
		}, this));

		this.render();
	};

#2

bootstra-treeview.js 的源碼里的 var Tree = function () { ... } 最后 return 返回的對象中新增一行代碼:

expandRealNode: $.proxy(this.expandRealNode, this)

expandRealNode 的使用方法示例:

var node = $('#target').treeview('findNodes', ['^' + n + '$', 'g', 'id']);
if (!node || !node.length) {
    return;
}
$('#target').treeview('checkNode', node);

$('#target').treeview('expandRealNode', node);

總結

主要分析了 bootstrap-treeview 源碼里的 checkNodeexpandNode 方法的具體的含義,並按需改造成適合自己使用的場景。

<全文完>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM