243 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| // components/path-view/index.js
 | ||
| import toTree from './toTree';
 | ||
| Component({
 | ||
|   properties: {
 | ||
|     value: {
 | ||
|       type: Array,
 | ||
|       value: [],
 | ||
|       observer() {
 | ||
|         this.initView();
 | ||
|       }
 | ||
|     },
 | ||
|     // 非树形数据,仅在value无传参时生效
 | ||
|     unnormalizedValue: {
 | ||
|       type: Array,
 | ||
|       value: [],
 | ||
|       observer() {
 | ||
|         this.initView();
 | ||
|       }
 | ||
|     },
 | ||
|     fatherKey: {
 | ||
|       type: String,
 | ||
|       value: 'pid'
 | ||
|     },
 | ||
|     selfKey: {
 | ||
|       type: String,
 | ||
|       value: 'id'
 | ||
|     },
 | ||
|     rootValue: {
 | ||
|       type: null,
 | ||
|       value: null
 | ||
|     },
 | ||
|     pathMode: {
 | ||
|       type: String,
 | ||
|       value: 'mode1'
 | ||
|     },
 | ||
|     firstFloorTxt: {
 | ||
|       type: String,
 | ||
|       value: '顶级'
 | ||
|     },
 | ||
|     btnTxt: {
 | ||
|       type: String,
 | ||
|       value: '选择'
 | ||
|     },
 | ||
|     contentKey: {
 | ||
|       type: String,
 | ||
|       value: 'name'
 | ||
|     },
 | ||
|     // 保持位置
 | ||
|     // 如果开启,数据动态更新后,会保持和更新前父元素对应的界面一致
 | ||
|     // 这里是通过记录下更新前的父元素的唯一标识符:id(或是selfKey中设定的键对应的值),在更新后找回显示出来
 | ||
|     // 所以就算更新后路径变了(父元素本来在第四层,变成了第二层之类),仍然能显示父元素的相应界面
 | ||
|     keepLoc: {
 | ||
|       type: Boolean,
 | ||
|       value: false
 | ||
|     }
 | ||
|   },
 | ||
|   data: {
 | ||
|     outValue: [],
 | ||
|     currentPath: [],
 | ||
|     // 判断当前是否已正在执行修改路径的方法
 | ||
|     isChange: false,
 | ||
|     // 映射value值,存放树形数据
 | ||
|     normalValue: [],
 | ||
|     currentFatherId: null
 | ||
|   },
 | ||
|   methods: {
 | ||
|     initView() {
 | ||
|       if (this.properties.keepLoc) {
 | ||
|         if (this.data.outValue.length > 0) {
 | ||
|           // 记录下当前界面元素的父节点id
 | ||
|           let fatherId = this.properties.fatherKey;
 | ||
|           this.setData({
 | ||
|             currentFatherId: this.data.outValue[0][fatherId] || null
 | ||
|           });
 | ||
|         }
 | ||
|       }
 | ||
|       // 优先使用value
 | ||
|       if (this.properties.value.length > 0) {
 | ||
|         this.setData({
 | ||
|           normalValue: this.properties.value
 | ||
|         });
 | ||
|       } else {
 | ||
|         // 将unnormalizedValue标准化
 | ||
|         this.setData({
 | ||
|           normalValue: this.normalizeValue()
 | ||
|         });
 | ||
|       }
 | ||
| 
 | ||
|       if (this.properties.keepLoc && this.data.currentFatherId !== null) {
 | ||
|         // 得到父元素的位置
 | ||
|         let fatherNodeLocation = this.searchLocById(this.data.currentFatherId);
 | ||
|         // 父元素的位置即是我们希望得到的当前路径
 | ||
|         let currentPath = fatherNodeLocation;
 | ||
|         this.switchPath(currentPath);
 | ||
|       } else {
 | ||
|         // 设置初始的输出值
 | ||
|         this.setData({
 | ||
|           outValue: this.data.normalValue,
 | ||
|           currentPath: []
 | ||
|         });
 | ||
|       }
 | ||
|     },
 | ||
|     tapItem(e) {
 | ||
|       // 如果正在执行修改路径的方法
 | ||
|       if (this.data.isChange) {
 | ||
|         return;
 | ||
|       }
 | ||
|       this.setData({
 | ||
|         isChange: true
 | ||
|       });
 | ||
|       // 获取当前点击的索引
 | ||
|       const currentIndex = e.currentTarget.dataset.index;
 | ||
|       const currentText = e.currentTarget.dataset.text;
 | ||
|       // 如果当前点击的标签还有下一级,就将路径改变
 | ||
|       if (this.data.outValue[currentIndex].children) {
 | ||
|         // 添加索引如路径
 | ||
|         this.setData({
 | ||
|           currentPath: [
 | ||
|             ...this.data.currentPath,
 | ||
|             { text: currentText, index: currentIndex }
 | ||
|           ]
 | ||
|         });
 | ||
|         this.selPath();
 | ||
|       }
 | ||
|       this.setData({
 | ||
|         isChange: false
 | ||
|       });
 | ||
|     },
 | ||
|     // 选择路径
 | ||
|     // pathsIndex 是 paths 的索引
 | ||
|     selPath(pathsIndex = this.data.currentPath.length - 1) {
 | ||
|       // 判断是否在第一级
 | ||
|       if (this.data.currentPath.length === 0) {
 | ||
|         return;
 | ||
|       }
 | ||
|       // 根据路径修改 outValue
 | ||
|       let tmpValue = this.data.normalValue;
 | ||
|       // 如果 pathsIndex 是 -1 就应该要回到第一级
 | ||
|       if (pathsIndex === -1) {
 | ||
|         this.setData({
 | ||
|           currentPath: [],
 | ||
|           outValue: tmpValue
 | ||
|         });
 | ||
|         return;
 | ||
|       }
 | ||
|       for (let i = 0; i <= pathsIndex; i++) {
 | ||
|         let item = this.data.currentPath[i].index;
 | ||
|         tmpValue = tmpValue[item]['children'];
 | ||
|       }
 | ||
|       // 更新 outValue , currentPath
 | ||
|       let endIndex = pathsIndex + 1;
 | ||
|       this.setData({
 | ||
|         outValue: tmpValue,
 | ||
|         currentPath: this.data.currentPath.slice(0, endIndex)
 | ||
|       });
 | ||
|     },
 | ||
|     toPath(e) {
 | ||
|       // 如果正在执行修改路径的方法
 | ||
|       if (this.data.isChange) {
 | ||
|         return;
 | ||
|       }
 | ||
|       this.setData({
 | ||
|         isChange: true
 | ||
|       });
 | ||
|       // 获取当前点击的索引
 | ||
|       const index =
 | ||
|         e.currentTarget.dataset.index != undefined
 | ||
|           ? e.currentTarget.dataset.index
 | ||
|           : this.data.currentPath.length - 1;
 | ||
|       this.selPath(index - 1);
 | ||
|       this.setData({
 | ||
|         isChange: false
 | ||
|       });
 | ||
|     },
 | ||
|     tapBtn(e) {
 | ||
|       this.triggerEvent('tapBtn', e.currentTarget.dataset.item);
 | ||
|     },
 | ||
|     // 将非标准值标准化
 | ||
|     normalizeValue() {
 | ||
|       return toTree({
 | ||
|         value: this.properties.unnormalizedValue,
 | ||
|         fatherKey: this.properties.fatherKey,
 | ||
|         selfKey: this.properties.selfKey,
 | ||
|         rootValue:
 | ||
|           this.properties.rootValue === null
 | ||
|             ? undefined
 | ||
|             : this.properties.rootValue
 | ||
|       });
 | ||
|     },
 | ||
|     // 通过唯一标识符找到元素的所在位置
 | ||
|     // 这里特意用了loc(location)表示位置而不是path,二者的区别是loc还包括了元素自身,而path不包括元素自身
 | ||
|     // 如树形数据[{id:1,name:'1'}],id:1的位置是[1],而它的路径是[]
 | ||
|     searchLocById(id) {
 | ||
|       if (id == null) {
 | ||
|         return null;
 | ||
|       }
 | ||
|       let tree = JSON.parse(JSON.stringify(this.data.normalValue));
 | ||
|       for (let i = 0; i < tree.length; i++) {
 | ||
|         tree[i].__location = [i];
 | ||
|         if (id === tree[i][this.properties.selfKey]) {
 | ||
|           return tree[i].__location;
 | ||
|         }
 | ||
|       }
 | ||
|       var stark = [];
 | ||
|       stark = stark.concat(tree);
 | ||
|       while (stark.length) {
 | ||
|         var temp = stark.shift();
 | ||
|         if (temp.children) {
 | ||
|           for (let j = 0; j < temp.children.length; j++) {
 | ||
|             temp.children[j].__location = [...temp.__location, j];
 | ||
|             if (id === temp.children[j][this.properties.selfKey]) {
 | ||
|               return temp.children[j].__location;
 | ||
|             }
 | ||
|           }
 | ||
|           // 当前节点有子节点时,将子节点放到当前的栈的前面
 | ||
|           stark = temp.children.concat(stark);
 | ||
|         }
 | ||
|       }
 | ||
|       // 如果找不到对应id的位置
 | ||
|       return null;
 | ||
|     },
 | ||
|     // 直接跳转到指定路径
 | ||
|     switchPath(pathArr = []) {
 | ||
|       let tmpValue = JSON.parse(JSON.stringify(this.data.normalValue));
 | ||
|       let currentPath = [];
 | ||
|       for (let i = 0; i < pathArr.length; i++) {
 | ||
|         let index = pathArr[i];
 | ||
|         let text = tmpValue[index][this.properties.contentKey];
 | ||
|         tmpValue = tmpValue[index]['children'];
 | ||
|         currentPath.push({
 | ||
|           text,
 | ||
|           index
 | ||
|         });
 | ||
|       }
 | ||
|       // 更新 outValue , currentPath
 | ||
|       this.setData({
 | ||
|         outValue: tmpValue,
 | ||
|         currentPath
 | ||
|       });
 | ||
|     }
 | ||
|   }
 | ||
| });
 |