问题分析
前端开发告诉我说【tree组件因为存了后台存储了全部的节点,页面回显时,因为父节点的关系,把子节点也全部勾上了,现在没法处理,必须要改接口加上半选节点的参数保存起来,再在回显时调用接口获取到半选的节点】。

不得不说,这的确是一个解决方案,但并不是一个好的解决方案。该接口固然能实现这个需求,但是要知道接口的改动会带来一系列意想不到的变化,比如数据库,缓存,接口参数和返回值,而且在已经集成好的接口上拓展新的变化,根据螺旋式开发规则的风险变化,BUG会随着螺旋的增大而急剧增大。虽然这个问题比较小,只是多存储了一些Service端用不上属性而已,但只是因为组件升级或bug,就需要改动功能无问题的接口,这并不是好的开发模式。作为一名优秀的开发者,首先想到的是应该用自己的办法去解决对接的问题,如果实在没有办法,再考虑两端协调的修改。

从业务分析来看 Service不论是check还是halfCheck都是必要的数据。但view端需要区分check,halfCheck来显示不同的图标,这就很矛盾了,可目的也很明确前端需要区分出半选节点。

那么怎么改才是最合理的呢?当然是利用JS处理回显的逻辑,这样即使组件变化或BUG依旧不会去改变接口。如果通过改接口修正好了,那若控件升级或bug,难道还要一改再改接口吗,当然不能。接口的设计不可能满足所有组件的需求,但它一定满足业务。既然可以通过自己控制,就没有必要去做一些更繁琐的工作,不是吗?

废话不多说了,下面看代码!

解决方案

new Vue({
	el: '#app',
	data: function() {
		return {
			data: [{
				id: "1",
				label: '1',
				children: [{
					id: "2",
					label: '2-1',
					children: [{
						id: "21",
						label: '2-1-1'
					}, {
						id: "22",
						label: '2-1-2'
					}]
				}, {
					id: "3",
					label: '2-2',
					children: [{
						id: "31",
						label: '2-2-1'
					}, {
						id: "32",
						label: ' 2-2-2'
					}]
				}]
			}],
			checkStrictly: true,
			defaultProps: {
				children: 'children',
				label: 'label'
			}
		}
	},
	mounted() {
    var that = this;
    ["1", "2", "22", "3", "31","32"].forEach((i,n) => {
      var node = that.$refs.menuListTree.getNode(i);
      console.log(node.isLeaf)
      if(node.isLeaf){
        that.$refs.menuListTree.setChecked(node, true);
      }
    });
	}
});

  

实现原理
利用tree组件渲染后带有的isLeaf(是否为叶子节点)属性,如果为叶子节点就选中。这样利用tree的API就实现了正确的回显效果。并没有过多的逻辑,只是利用tree本身的API 出BUG的概率也不会变高。手动设置node其实和prop的default-checked-keys原理是一样的,其实内部也都是循环,也不会出现效率的问题。所处理的也只是多了一层isLeaf的判断而已。

总结
我走过的弯路
看到的第一反应是之前遇到过,早些年在做ztree的时候也有这个问题,当时用API就解决了,el-tree应该也有。于是查了一大圈,发现有个函数叫setCheckedKeys(keys, leafOnly),设置leafOnly = false,就可以只设置子节点选中。以为有用,于是试了一下,发现果然是【子节点】选中啊…父节点一个都没选,于是失败了。
又找到一个属性叫做 check-strictly,设置check-strictly = true,赋值结束后再重置check-strictly = false表面上看起来是好试了,但仔细点看发现【父节点】不是半选的!!!又失败了…
说心里话,这点其实el-tree可能可以优化一下会更好,这个需求早在jquery的阶段就有了,ztree就解决过。el做为更新的vue组件,应该早就能设想到这种情况了,但却没有提供回显半选这样的设置属性或者函数,这也是美中不足的地方。

可爱的地方是即使如此,依然通过API的函数组合,可以达到想要的效果,虽然看起来不是特别优雅,好在没有花太多力气。

如果一个问题困扰自己很久,有几种可能:

API了解不够深入,并不熟练
走了弯路还不肯放弃,非要一条路走到黑,掉入自己画的圈中无法跳出
确实无法通过现有的方法实现
正确的解决问题的方式是应该灵活多变的,开发更多的提倡解耦,面向对象,而不是面向过程。就好比考试的时候遇到一个问题,答案可能有很多种。但再多的答案,都需要自己作答,而并不是去修改题目、添加条件,当然若题目出错了自然另当别论。答案的好坏才会关系到得分的高低,再多字数,再华丽的词汇,却没有得分点,那依旧是不得分的。

就我自己而言,也经常一条路跑到黑,很容易掉进坑里。一般这时候会选择仔细的查API和代码,终会有所发现。要么就换思路,要么就换组件。引用一句不知道谁说的话“妄图用代码解决一切问题的人,最终都会失败。”因为你所使用的库,不可能全部是自己写的,总会有自己的逻辑无法触及的地方,难道遇到一个就要改一份源码吗?当然不能。^_^