1.需求:
数据库中有一张表,表名为itemType,记录的是商品类型,其中有一个字段是父级id,对应的也是本表中的id字段,所以这里类型数据应该是以一种树装结构json来显示的。
结构如图:
image.png image.png2.json结构图:
image.png转化后:
image.png3.控制层代码:(递归)
递归这玩意不懂别去强行理解,多写多练,别指望一次就会用。用的多了自然就会明白了,要不然就直接看源码。
1).初始数据=> List<ItemType> itemTypes = ...
2).json格式拼装方法:
private List<Map<String,Object>> covertToTree(List<ItemType> itemTypes){
Map<Integer,ItemType> typeMap = new HashMap<>();
for(ItemType type:itemTypes){
typeMap.put(type.getId(),type);
}
return recursionCovertToTree(null,typeMap);
}
private recursionCovertToTree(Integer parentId,Map<Integer,ItemType> typeMap){
List<Map<String,Object>> list = new ArrayList<>();
for(Integer key : typeMap){
//通过key拿到单个ItemType实例
ItemType type = typeMap.get(key);
if((parentId==null && type.getParentId()==null) || ()){
Map<String,Object> entity = new HashMap<>();
entity.put("type",type);
List<Map<String,Object>> children = recursionCovertToTree(type.getId(),typeMap);
entity.put("children",children);
list.add(entity) ;
}
}
return list;
}
4.vue递归组件应用场景:
image.png
选择一个类型,如果这个类型有父级就会接着选择。
image.png
无父级之后:
image.png5.页面布局:
<div class="form-group" style="width:500px !important;">
<!-- todo -->
<label>商品类型</label>
<div id="item-type-container">
<item-type v-bind:options="tree" v-bind:id-path="path" v-bind:id-pos="0"></item-type>
</div>
</div>
组件:
Vue.component('item-type', {
template: "" +
"<div style='display: inline-block;'>\n" +
" <select @change='change($event.target.value)' :disabled='disabled' v-if='showSelector'>\n" +
" <option value='-1'>请选择</option>\n" +
" <option v-for='opt in options' :key='opt.type.id' :value='opt.type.id' :selected='idPath[idPos] == opt.type.id'>{{opt.type.typeName}}</option>\n" +
" </select>\n" +
" <item-type v-if='childOptions && childOptions.length !== 0' :options='childOptions' :id-path='idPath' :id-pos='idPos + 1' :disabled='disabled'></item-type>\n" +
"</div>",
props: ['options', 'idPath', 'idPos', 'disabled'],
data: function () {
return {
childOptions: []
}
},
computed: {
showSelector: function () {
if (!this.disabled) {
return true
}
var curId = this.idPath[this.idPos]
for (var i = 0, len = this.options.length; i < len; ++i) {
if (this.options[i].type.id == curId) {
return true
}
}
return false
}
},
methods: {
change: function (id) {
for (var i = 0, len = this.options.length; i < len; ++i) {
var opt = this.options[i]
if (opt.type.id == id) {
this.$set(this.idPath, this.idPos, id)
this.childOptions = opt.children
return
}
}
this.childOptions = []
this.idPath.splice(this.idPos)
}
},
mounted: function () {
this.change(this.idPath[this.idPos])
}
});
实例:
function createItemTypeSelector(id, itemTypeId, itemTypes, onItemTypeChanged) {
new Vue({
el: id,
data: function() {
var path = [];
this.getPath(path, itemTypeId, itemTypes);
return {
tree: itemTypes,
itemTypeId: itemTypeId,
path: path
}
},
watch: {
path: function (value) {
typeof onItemTypeChanged === 'function' && onItemTypeChanged(value[value.length - 1])
}
},
methods: {
getPath: function (path, typeId, children) {
for (var i = 0, len = children.length; i < len; ++i) {
var child = children[i]
if (this.getPath(path, typeId, child.children)) {0
path.unshift(child.type.id)
return true
} else if (child.type.id == typeId) {
path.unshift(child.type.id)
return true
}
}
return false
}
}
});
}
网友评论