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
|
||
});
|
||
}
|
||
}
|
||
});
|