knockout.js实现一个级联下拉框
之前面试时碰上一道knockout.js的面试题,网上没有太多的相关资料,所以这里就记录一下。
题目
用knockout实现一个级联下拉,数据受前面的下拉控制(注意:下拉可能不是级联中下拉(可能是文本框)控制)。数据可以直接写死在页面中。下拉层级不少于4级。
A是完全级联例如(总公司-分公司-部门----人员姓名),B是其中有不是属于级联的 例如(总公司-分公司-部门、入职年份(非级联中字段) ---控制 人员姓名)
原方法
根据之前所按照网上原有的方法进行修改后:
完全级联A:
不完全级联B:
代码如下:
完全级联A:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>document</title>
</head>
<body>
<div>
<div style="width:500px;"></div>
<div>
<span>完全级联</span>
<div style="display: inline-block">
<span id="container">
<select
data-bind="options:ch_array, optionsText:'name', optionsValue:'id',optionsCaption: 'Choose...',value:selected,event:{change:OnSelected}"
></select>
<!--ko if:typeof ch_array ==='function' && ch_array().length>0-->
<span
data-bind="template: { name: 'ko_ch_array',foreach:ch_array }"
></span>
<!--/ko-->
</span>
<script type="text/html" id="ko_ch_array">
<!--ko if:id()==$parentContext.$data.selected() && typeof ch_array ==='function' && ch_array().length>0-->
<select
data-bind="options:ch_array, optionsText:'name', optionsValue:'id',optionsCaption: 'Choose...',value:selected"
></select>
<!--ko if:ch_array().length>0-->
<span
data-bind="template: { name: 'ko_ch_array',foreach:ch_array }"
></span>
<!--/ko-->
<!--/ko-->
</script>
</div>
</div>
</div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
<script src="./knockout.mapping-latest.js"></script>
<script type="text/javascript">
// 初始化数据
function initData() {
let create_comps_data = [
{
id: 1,
name: "教育总公司",
ch_array: [
{
id: 2,
name: "教育总公司重庆分公司",
ch_array: [
{
id: 3,
name: "教育总公司重庆分公司采购部门",
ch_array: [
{ name: "王大锤1111111", id: 4 },
{ name: "吴大勇111111", id: 5 },
{ name: "圣埃蒂安11111111", id: 6 },
],
},
{
id: 7,
name: "教育总公司重庆分公司研发部门",
ch_array: [
{ name: "阿斯顿当过官发", id: 8 },
{ name: "的发射点", id: 9 },
{ name: "是德国商代给", id: 10 },
{ name: "阿三大苏打撒旦法发是", id: 111 },
{ name: "啊实打实打算人", id: 101 },
{ name: "月台与用途很广泛", id: 1011 },
],
},
],
},
{
id: 11,
name: "教育总公司深圳分公司",
ch_array: [
{
id: 12,
name: "教育总公司深圳分公司采购部门",
ch_array: [
{ name: "分割符号", id: 13 },
{ name: "啊实打实的", id: 14 },
{ name: "嘀咕嘀咕附件", id: 15 },
],
},
{
id: 16,
name: "教育总公司深圳分公司研发部门",
ch_array: [
{ name: "的说法是大哥", id: 17 },
{ name: "快乐和快乐", id: 18 },
{ name: "啊实打实啊实打实", id: 191 },
{ name: "啊实打实阿斯弗", id: 192 },
{ name: "啊实打实地方", id: 193 },
{ name: "啊实打实大师傅", id: 194 },
],
},
],
},
{
id: 20,
name: "教育总公司北京分公司",
ch_array: [],
},
],
},
{
id: 21,
name: "食品总公司",
ch_array: [
{
id: 22,
name: "食品总公司深圳分公司",
ch_array: [],
},
{
id: 23,
name: "食品总公司重庆分公司",
ch_array: [],
},
{
id: 24,
name: "食品总公司北京分公司",
ch_array: [],
},
],
},
{
id: 25,
name: "科技总公司",
ch_array: [
{
id: 26,
name: "科技总公司深圳分公司",
ch_array: [],
},
{
id: 27,
name: "科技总公司重庆分公司",
ch_array: [],
},
],
},
];
let data = {};
let model = create_comps_data;
initSelected(model);
data.ch_array = model;
data.selected = "";
return data;
}
function initSelected(list) {
for (var i = 0, n = list.length; i < n; i++) {
list[i].selected = "";
list[i].id = Math.random(100000); // 随机赋值 防止id相同出现bug
if (
list[i].ch_array &&
list[i].ch_array instanceof Array &&
list[i].ch_array.length > 0
)
initSelected(list[i].ch_array);
}
}
var VM = ko.mapping.fromJS(initData());
ko.applyBindings(VM, document.getElementById("container"));
function OnSelected($data, event) {
cleanUpSelected($data.ch_array());
}
// 还原初始化selected
function cleanUpSelected(item) {
item.forEach(function (value, index, array) {
if (typeof value.selected === "function") value.selected("");
if (typeof value.ch_array === "function")
cleanUpSelected(value.ch_array());
});
}
</script>
不完全级联B:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>document</title>
</head>
<body>
<div>
<div style="width: 500px"></div>
<div>
<span>不完全级联</span>
<div style="display: inline-block">
<span id="container">
<select
data-bind="options:ch_array, optionsText:'name', optionsValue:'id',optionsCaption: 'Choose...',value:selected,event:{onblur:OnSelected}"
></select>
<!--ko if:typeof ch_array ==='function' && ch_array().length>0-->
<span
data-bind="template: { name: 'ko_ch_array',foreach:ch_array }"
></span>
<!--/ko-->
</span>
<script type="text/html" id="ko_ch_array">
<!--ko if:id()==$parentContext.$data.selected() && typeof ch_array ==='function' && ch_array().length>0-->
<!--ko if:ch_array()[0].time-->
<input
type="number"
data-bind="value:$data.selectedyear,event:{change:inputChange($data,$root,$parent)}"
/>
<select
data-bind="visible:$root.show,options:$root.search, optionsText:'name', optionsValue:'id',optionsCaption: 'Choose...',value:selected"
></select>
<!--/ko-->
<!--ko ifnot:ch_array()[0].time-->
<select
data-bind="options:ch_array, optionsText:'name', optionsValue:'id',optionsCaption: 'Choose...',value:selected"
></select>
<!--/ko-->
<!--ko if:ch_array().length>0-->
<span
data-bind="template: { name: 'ko_ch_array',foreach:ch_array }"
></span>
<!--/ko-->
<!--/ko-->
</script>
</div>
</div>
</div>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
<script src="./knockout.mapping-latest.js"></script>
<script type="text/javascript">
// 初始化数据
function initData() {
let create_comps_data = [
{
id: 1,
name: "教育总公司",
ch_array: [
{
id: 2,
name: "教育总公司重庆分公司",
ch_array: [
{
id: 3,
name: "教育总公司重庆分公司采购部门",
ch_array: [
{ name: "王大锤", id: 4, time: 1991 },
{ name: "吴大勇", id: 5, time: 1991 },
{ name: "大苏打", id: 6, time: 1991 },
{ name: "刘大力", id: 7, time: 1995 },
{ name: "阿萨大大", id: 8, time: 1997 },
{ name: "阿斯顿", id: 9, time: 1997 }
],
},
{
id: 10,
name: "教育总公司重庆分公司研发部门",
ch_array: [
{ name: "王大锤1111111", id: 8, time: 1991 },
{ name: "吴大勇222222222", id: 9, time: 1991 },
{ name: "圣埃蒂安33333333333", id: 10, time: 1991 },
],
},
],
},
{
id: 11,
name: "教育总公司深圳分公司",
ch_array: [
{
id: 12,
name: "教育总公司深圳分公司采购部门",
ch_array: [
{ name: "王大爷44444444", id: 13, time: 1990 },
{ name: "张大侠1111111111", id: 14, time: 1995 },
{ name: "刘老铁22222222222", id: 15, time: 1991 },
],
},
{
id: 16,
name: "教育总公司深圳分公司研发部门",
ch_array: [
{ name: "深圳王大锤44", id: 17, time: 2000 },
{ name: "深圳吴大勇22", id: 18, time: 2001 },
{ name: "深圳圣埃蒂安44", id: 19, time: 2002 },
],
},
],
},
{
id: 20,
name: "教育总公司北京分公司",
ch_array: [ {
id: 3,
name: "教育总公司北京分公司采购部门",
ch_array: [
{ name: "王大锤21", id: 4, time: 1991 },
{ name: "吴大勇12", id: 5, time: 1991 },
{ name: "大苏打212", id: 6, time: 1991 },
{ name: "刘大力", id: 7, time: 1995 },
{ name: "阿萨大大12", id: 8, time: 1997 },
{ name: "阿斯顿12", id: 9, time: 1997 }
],
},
{
id: 10,
name: "教育总公司北京分公司研发部门",
ch_array: [
{ name: "王大锤123", id: 8, time: 1991 },
{ name: "吴大勇123", id: 9, time: 1991 },
{ name: "圣埃蒂安123", id: 10, time: 1991 },
],
},],
},
],
},
{
id: 21,
name: "食品总公司",
ch_array: [
{
id: 22,
name: "食品总公司深圳分公司",
ch_array: [],
},
{
id: 23,
name: "食品总公司重庆分公司",
ch_array: [],
},
{
id: 24,
name: "食品总公司北京分公司",
ch_array: [],
},
],
},
{
id: 25,
name: "科技总公司",
ch_array: [
{
id: 26,
name: "科技总公司深圳分公司",
ch_array: [],
},
{
id: 27,
name: "科技总公司重庆分公司",
ch_array: [],
},
],
},
];
let data = {};
let model = create_comps_data;
initSelected(model);
data.ch_array = model;
data.selected = "";
data.show=false; // 隐藏下拉框
data.search=[]; // 用于显示查找对应年份的人员
return data;
}
// 初始化
function initSelected(list) {
for (var i = 0, n = list.length; i < n; i++) {
list[i].selected = "";
list[i].id = Math.random(100000); // 随机赋值 防止id相同出现bug
if (
list[i].ch_array &&
list[i].ch_array instanceof Array &&
list[i].ch_array.length > 0
)
initSelected(list[i].ch_array);
}
}
var VM = ko.mapping.fromJS(initData());
ko.applyBindings(VM, document.getElementById("container"));
function OnSelected($data, event) {
cleanUpSelected($data.ch_array());
}
// 还原初始化selected
function cleanUpSelected(item) {
item.forEach(function (value, index, array) {
if (typeof value.selected === "function") value.selected("");
if (typeof value.ch_array === "function")
cleanUpSelected(value.ch_array());
});
}
function inputChange(data,root,parent) {
let that = this;
let year = data.selectedyear;
console.log(year);
if (year != "") {
let array = data.ch_array();
// console.log(array)
// console.log($data)
// console.log($root)
// console.log(parent)
let z = array.filter((item) => { // 查找相同属性
// console.log(item)
return item.time() === parseInt(year);
});
// console.log(z);
if (z.length > 0) {
ko.mapping.fromJS(z, {}, root.search); // 重新渲染
ko.mapping.fromJS(true, {}, root.show);
}else{
ko.mapping.fromJS(false, {}, root.show);
}
} else {
ko.mapping.fromJS(false, {}, root.show);
}
}
</script>
后续改进
将题目的解题逻辑重写了,将级联的层级固定为四级级联
重写完全级联A
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div style="text-align: center; margin-top: 50px" id="container">
<div>完全级联</div>
<div>
<div>
<span>总公司</span>
<!-- value是要绑定在哪个数值变量 optionsValue是将其值传给value -->
<select
data-bind="options:monitor_head_comp_array, optionsText:'head_comp_name',optionsValue:$data,optionsCaption: '选择总公司',value:head_selected"
></select>
</div>
<div>
<span>分公司</span>
<select
data-bind="options:monitor_breach_comp_array, optionsText:'breach_comp_name',optionsValue:$data,optionsCaption: '选择分公司',value:breach_selected"
></select>
</div>
<div>
<span>各部门</span>
<select
data-bind="options:monitor_department_comp_array, optionsText:'depart_name',optionsValue:$data,optionsCaption: '选择部门',value:depart_selected"
></select>
</div>
<div>
<span>游戏类</span>
<select
data-bind="options:monitor_game_name_array, optionsText:'name',optionsValue:$data,optionsCaption: '选择游戏/员工',value:game_selected"
></select>
</div>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
<script type="text/javascript">
// 初始化数据
var create_game = [
{
id: 1,
head_comp_name: "XX总公司",
data_array: [
{
id: 2,
breach_comp_name: "XX总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司重庆分公司采购部门",
data_array: [
{ name: "彩虹六号", id: 4, time: 1991 },
{ name: "地下城与勇士", id: 5, time: 1991 },
{ name: "穿越火线", id: 6, time: 1991 },
{ name: "QQ飞车", id: 7, time: 1995 },
{ name: "虐杀原形1", id: 8, time: 1997 },
{ name: "虐杀原形2", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司重庆分公司研发部门",
data_array: [
{ name: "黑暗之魂1", id: 8, time: 1991 },
{ name: "黑暗之魂2", id: 9, time: 1991 },
{ name: "黑暗之魂3", id: 10, time: 1991 },
{ name: "只狼", id: 10, time: 1991 },
],
},
],
},
{
id: 2,
breach_comp_name: "XX总公司湖南分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司湖南分公司采购部门",
data_array: [
{ name: "赛尔号", id: 4, time: 1991 },
{ name: "奥比岛", id: 5, time: 1991 },
{ name: "功夫派", id: 6, time: 1991 },
{ name: "QQ炫舞", id: 7, time: 1995 },
{ name: "剑灵", id: 8, time: 1997 },
{ name: "欢乐斗地主", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司湖南分公司研发部门",
data_array: [
{ name: "蝙蝠侠阿甘之城", id: 8, time: 1991 },
{ name: "蝙蝠侠阿卡姆骑士", id: 9, time: 1991 },
{ name: "侠影之谜", id: 10, time: 1991 },
{ name: "闪电侠", id: 10, time: 1991 },
],
},
],
},
{
id: 2,
breach_comp_name: "XX总公司成都分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司成都分公司采购部门",
data_array: [
{ name: "天使爱美丽", id: 4, time: 1991 },
{ name: "猪猪侠", id: 5, time: 1991 },
{ name: "小灰灰", id: 6, time: 1991 },
{ name: "哆啦A梦", id: 7, time: 1995 },
{ name: "蜡笔小新", id: 8, time: 1997 },
{ name: "海绵宝宝", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司成都分公司研发部门",
data_array: [
{ name: "乐高蝙蝠侠1", id: 8, time: 1991 },
{ name: "乐高蝙蝠侠2", id: 9, time: 1991 },
{ name: "乐高蝙蝠侠3", id: 10, time: 1991 },
{ name: "乐高漫威超级英雄1", id: 10, time: 1991 },
{ name: "乐高漫威超级英雄2", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "YY总公司",
data_array: [
{
id: 2,
breach_comp_name: "YY总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "YY总公司重庆分公司游戏部门",
data_array: [
{ name: "艾尔登法环", id: 4, time: 1991 },
{ name: "switch", id: 5, time: 1991 },
{ name: "孤岛危机1", id: 6, time: 1991 },
{ name: "孤岛危机2", id: 7, time: 1995 },
{ name: "孤岛危机3", id: 8, time: 1997 },
{ name: "光环", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "YY总公司重庆分公司研发部门",
data_array: [
{ name: "GTA5", id: 8, time: 1991 },
{ name: "侠盗猎车手", id: 9, time: 1991 },
{ name: "幽浮1未知敌人", id: 10, time: 1991 },
{ name: "幽浮1内部敌人", id: 10, time: 1991 },
{ name: "幽浮2天选者之战", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "娱乐总公司",
data_array: [
{
id: 2,
breach_comp_name: "娱乐总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "娱乐总公司重庆分公司采购部门",
data_array: [
{ name: "凤凰点", id: 4, time: 1991 },
{ name: "蜘蛛侠1", id: 5, time: 1991 },
{ name: "蜘蛛侠2", id: 6, time: 1991 },
{ name: "蜘蛛侠3", id: 7, time: 1995 },
{ name: "超凡蜘蛛侠1", id: 8, time: 1997 },
{ name: "超凡蜘蛛侠2", id: 9, time: 1997 },
{ name: "超凡蜘蛛侠3", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司宣发部门",
data_array: [
{ name: "怪物猎人世界", id: 8, time: 1991 },
{ name: "怪物猎人崛起", id: 9, time: 1991 },
{ name: "明日方舟", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "暴雪总公司",
data_array: [
{
id: 2,
breach_comp_name: "暴雪总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "暴雪总公司重庆分公司采购部门",
data_array: [
{ name: "魔兽世界", id: 4, time: 1991 },
{ name: "魔兽争霸3冰封王座", id: 5, time: 1991 },
{ name: "星际争霸1", id: 6, time: 1991 },
{ name: "星际争霸2", id: 7, time: 1995 },
{ name: "守望先锋1", id: 8, time: 1997 },
{ name: "守望先锋2", id: 9, time: 1997 },
{ name: "暗黑破坏神", id: 9, time: 1997 },
{ name: "炉石传说", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司宣发部门",
data_array: [
{ name: "怪物猎人世界", id: 8, time: 1991 },
{ name: "怪物猎人崛起", id: 9, time: 1991 },
{ name: "明日方舟", id: 10, time: 1991 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司代理部门",
data_array: [
{ name: "文明6", id: 8, time: 1991 },
{ name: "欧陆风云2", id: 9, time: 1991 },
{ name: "维多利亚2", id: 10, time: 1991 },
{ name: "群星", id: 10, time: 1991 },
{ name: "仙剑奇侠传1", id: 10, time: 1991 },
{ name: "仙剑奇侠传2", id: 10, time: 1991 },
{ name: "仙剑奇侠传3", id: 10, time: 1991 },
{ name: "仙剑奇侠传4", id: 10, time: 1991 },
{ name: "仙剑奇侠传5", id: 10, time: 1991 },
{ name: "仙剑奇侠传6", id: 10, time: 1991 },
{ name: "仙剑奇侠传7", id: 10, time: 1991 },
],
},
],
},
],
},
];
let games = {};
let model = create_game;
setNewAttrInTraverse(model, "id", "data_array");
games["data_array"] = model;
initData();
this.monitor["monitor_head_comp_array"](
searchAttr("head_comp_name", model)
); // 初始化总公司
setListener("head_selected", "monitor_breach_comp_array", 1, this);
setListener("breach_selected", "monitor_department_comp_array", 2, this);
setListener("depart_selected", "monitor_game_name_array", 3, this);
function initData() {
var self = this;
self.monitor = {
monitor_head_comp_array: ko.observable([]),
monitor_breach_comp_array: ko.observable([]),
monitor_department_comp_array: ko.observable([]),
monitor_game_name_array: ko.observable([]),
head_selected: ko.observable(),
breach_selected: ko.observable(),
depart_selected: ko.observable(),
game_selected: ko.observable(),
};
ko.applyBindings(monitor, document.getElementById("container"));
}
function searchAttr(attr, list) {
let array = [];
for (let i = 0; i < list.length; i++) {
if (list[i].hasOwnProperty(attr)) {
array.push(list[i]);
}
}
return array;
}
// 添加数值变化监听事件
// monitor_name 要监听的属性名
// _name_array // 要修改的监听数组名
// state 重新点击第几层级
// _self // 全局作用域
function setListener(monitor_name, _name_array, state, _self) {
_self.monitor[monitor_name].subscribe(function (val) {
// 当总公司发生改变
console.log(val);
cleanUpSelected(state, _self);
if (val&&val.data_array) {
// cleanUpSelected(state, _self);
_self.monitor[_name_array](val["data_array"]);
}
}); // 监测值变化
}
// 遍历json格式对象 给每一层添加或修改属性
// list 数组
// id 属性值 string类型
// array 属性值 string类型
function setNewAttrInTraverse(list, id, array) {
for (let i = 0; i < list.length; i++) {
list[i][id] = Math.random(10000);
if (
list[i][array] &&
list[i][array] instanceof Array &&
list[i][array].length > 0
) {
// 如果子数列存在
setNewAttrInTraverse(list[i][array], id, array);
}
}
}
// 用于还原后面层级的初始状态
function cleanUpSelected(state, _self) {
switch (state) {
case 3:
// _self.monitor["game_selected"]({});
_self.monitor["game_selected"]({});
_self.monitor["monitor_game_name_array"]([]);
break;
case 2:
// _self.monitor["monitor_department_comp_array"]([]);
// _self.monitor["monitor_breach_comp_array"]([]);
_self.monitor["monitor_department_comp_array"]([]);
_self.monitor["monitor_game_name_array"]([]);
// _self.monitor["breach_selected"]({});
_self.monitor["depart_selected"]({});
_self.monitor["game_selected"]({});
break;
case 1:
// _self.monitor["monitor_head_comp_array"]([]);
_self.monitor["monitor_breach_comp_array"]([]);
_self.monitor["monitor_department_comp_array"]([]);
_self.monitor["monitor_game_name_array"]([]);
// _self.monitor["head_selected"]({});
_self.monitor["breach_selected"]({});
_self.monitor["depart_selected"]({});
_self.monitor["game_selected"]({});
break;
default:
}
}
</script>
<style type="text/css">
select {width: 300px;}
p {margin-left: 20px}
</style>
</html>
重写不完全级联B
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div style="text-align: center; margin-top: 50px" id="container">
<div>不完全级联</div>
<div>
<div>
<span>总公司</span>
<!-- value是要绑定在哪个数值变量 optionsValue是将其值传给value -->
<select
data-bind="options:monitor_head_comp_array, optionsText:'head_comp_name',optionsValue:$data,optionsCaption: '选择总公司',value:head_selected"
></select>
</div>
<div>
<span>分公司</span>
<select
data-bind="options:monitor_breach_comp_array, optionsText:'breach_comp_name',optionsValue:$data,optionsCaption: '选择分公司',value:breach_selected"
></select>
</div>
<div>
<span>各部门</span>
<select
data-bind="options:monitor_department_comp_array, optionsText:'depart_name',optionsValue:$data,optionsCaption: '选择部门',value:depart_selected"
></select>
</div>
<div>
<span>出版年</span>
<input
type="number"
placeholder="选择部门后输入搜索年份"
data-bind="disable:disabled_power,value:monitor.selected_year,event:{change:inputChange(monitor.depart_selected(),monitor.selected_year(),$root)}"
/>
</div>
<div>
<span>游戏类</span>
<select
data-bind="options:monitor_game_name_array, optionsText:function(item){return item.name+' 出版年:'+item.time},optionsValue:$data,optionsCaption: '选择游戏',value:game_selected"
></select>
</div>
</div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
<script type="text/javascript">
// 初始化数据
var create_game = [
{
id: 1,
head_comp_name: "XX总公司",
data_array: [
{
id: 2,
breach_comp_name: "XX总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司重庆分公司采购部门",
data_array: [
{ name: "彩虹六号", id: 4, time: 1991 },
{ name: "地下城与勇士", id: 5, time: 1991 },
{ name: "穿越火线", id: 6, time: 1991 },
{ name: "QQ飞车", id: 7, time: 1995 },
{ name: "虐杀原形1", id: 8, time: 1997 },
{ name: "虐杀原形2", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司重庆分公司研发部门",
data_array: [
{ name: "黑暗之魂1", id: 8, time: 1991 },
{ name: "黑暗之魂2", id: 9, time: 1991 },
{ name: "黑暗之魂3", id: 10, time: 1991 },
{ name: "只狼", id: 10, time: 1991 },
],
},
],
},
{
id: 2,
breach_comp_name: "XX总公司湖南分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司湖南分公司采购部门",
data_array: [
{ name: "赛尔号", id: 4, time: 1991 },
{ name: "奥比岛", id: 5, time: 1991 },
{ name: "功夫派", id: 6, time: 1991 },
{ name: "QQ炫舞", id: 7, time: 1995 },
{ name: "剑灵", id: 8, time: 1997 },
{ name: "欢乐斗地主", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司湖南分公司研发部门",
data_array: [
{ name: "蝙蝠侠阿甘之城", id: 8, time: 1991 },
{ name: "蝙蝠侠阿卡姆骑士", id: 9, time: 1991 },
{ name: "侠影之谜", id: 10, time: 1991 },
{ name: "闪电侠", id: 10, time: 1991 },
],
},
],
},
{
id: 2,
breach_comp_name: "XX总公司成都分公司",
data_array: [
{
id: 3,
depart_name: "XX总公司成都分公司采购部门",
data_array: [
{ name: "天使爱美丽", id: 4, time: 1991 },
{ name: "猪猪侠", id: 5, time: 1991 },
{ name: "小灰灰", id: 6, time: 1991 },
{ name: "哆啦A梦", id: 7, time: 1995 },
{ name: "蜡笔小新", id: 8, time: 1997 },
{ name: "海绵宝宝", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "XX总公司成都分公司研发部门",
data_array: [
{ name: "乐高蝙蝠侠1", id: 8, time: 1991 },
{ name: "乐高蝙蝠侠2", id: 9, time: 1991 },
{ name: "乐高蝙蝠侠3", id: 10, time: 1991 },
{ name: "乐高漫威超级英雄1", id: 10, time: 1991 },
{ name: "乐高漫威超级英雄2", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "YY总公司",
data_array: [
{
id: 2,
breach_comp_name: "YY总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "YY总公司重庆分公司游戏部门",
data_array: [
{ name: "艾尔登法环", id: 4, time: 1991 },
{ name: "switch", id: 5, time: 1991 },
{ name: "孤岛危机1", id: 6, time: 1991 },
{ name: "孤岛危机2", id: 7, time: 1995 },
{ name: "孤岛危机3", id: 8, time: 1997 },
{ name: "光环", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "YY总公司重庆分公司研发部门",
data_array: [
{ name: "GTA5", id: 8, time: 1991 },
{ name: "侠盗猎车手", id: 9, time: 1991 },
{ name: "幽浮1未知敌人", id: 10, time: 1991 },
{ name: "幽浮1内部敌人", id: 10, time: 1991 },
{ name: "幽浮2天选者之战", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "娱乐总公司",
data_array: [
{
id: 2,
breach_comp_name: "娱乐总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "娱乐总公司重庆分公司采购部门",
data_array: [
{ name: "凤凰点", id: 4, time: 1991 },
{ name: "蜘蛛侠1", id: 5, time: 1991 },
{ name: "蜘蛛侠2", id: 6, time: 1991 },
{ name: "蜘蛛侠3", id: 7, time: 1995 },
{ name: "超凡蜘蛛侠1", id: 8, time: 1997 },
{ name: "超凡蜘蛛侠2", id: 9, time: 1997 },
{ name: "超凡蜘蛛侠3", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司宣发部门",
data_array: [
{ name: "怪物猎人世界", id: 8, time: 1991 },
{ name: "怪物猎人崛起", id: 9, time: 1991 },
{ name: "明日方舟", id: 10, time: 1991 },
],
},
],
},
],
},
{
id: 1,
head_comp_name: "暴雪总公司",
data_array: [
{
id: 2,
breach_comp_name: "暴雪总公司重庆分公司",
data_array: [
{
id: 3,
depart_name: "暴雪总公司重庆分公司采购部门",
data_array: [
{ name: "魔兽世界", id: 4, time: 1991 },
{ name: "魔兽争霸3冰封王座", id: 5, time: 1991 },
{ name: "星际争霸1", id: 6, time: 1991 },
{ name: "星际争霸2", id: 7, time: 1995 },
{ name: "守望先锋1", id: 8, time: 1997 },
{ name: "守望先锋2", id: 9, time: 1997 },
{ name: "暗黑破坏神", id: 9, time: 1997 },
{ name: "炉石传说", id: 9, time: 1997 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司宣发部门",
data_array: [
{ name: "怪物猎人世界", id: 8, time: 1991 },
{ name: "怪物猎人崛起", id: 9, time: 1991 },
{ name: "明日方舟", id: 10, time: 1991 },
],
},
{
id: 10,
depart_name: "娱乐总公司重庆分公司代理部门",
data_array: [
{ name: "文明6", id: 8, time: 1991 },
{ name: "欧陆风云2", id: 9, time: 1991 },
{ name: "维多利亚2", id: 10, time: 1991 },
{ name: "群星", id: 10, time: 1991 },
{ name: "仙剑奇侠传1", id: 10, time: 1991 },
{ name: "仙剑奇侠传2", id: 10, time: 1991 },
{ name: "仙剑奇侠传3", id: 10, time: 1991 },
{ name: "仙剑奇侠传4", id: 10, time: 1991 },
{ name: "仙剑奇侠传5", id: 10, time: 1991 },
{ name: "仙剑奇侠传6", id: 10, time: 1991 },
{ name: "仙剑奇侠传7", id: 10, time: 1991 },
],
},
],
},
],
},
];
let games = {};
let model = create_game;
setNewAttrInTraverse(model, "id", "data_array");
games["data_array"] = model;
initData();
this.monitor["monitor_head_comp_array"](
searchAttr("head_comp_name", model)
); // 初始化总公司
setListener("head_selected", "monitor_breach_comp_array", 1, this);
setListener("breach_selected", "monitor_department_comp_array", 2, this);
setListener("depart_selected", "monitor_game_name_array", 3, this);
function initData() {
var self = this;
self.monitor = {
monitor_head_comp_array: ko.observable([]),
monitor_breach_comp_array: ko.observable([]),
monitor_department_comp_array: ko.observable([]),
monitor_game_name_array: ko.observable([]),
head_selected: ko.observable(),
breach_selected: ko.observable(),
depart_selected: ko.observable(),
game_selected: ko.observable(), // 选择的游戏层级的option
selected_year: ko.observable(), // 查找年份
disabled_power:ko.observable(true),
inputChange: function (data, year, root) {
let that = this;
if (
data &&
data["data_array"] &&
data["data_array"] instanceof Array &&
data["data_array"].length > 0
) {
let ar = data["data_array"].filter((item) => {
if (year === "") {
return item.time;
} else {
// 查找相同属性
console.log(item);
return item.time === parseInt(year);
}
});
root["monitor_game_name_array"](ar);
}
},
};
ko.applyBindings(monitor, document.getElementById("container"));
}
function searchAttr(attr, list) {
let array = [];
for (let i = 0; i < list.length; i++) {
if (list[i].hasOwnProperty(attr)) {
array.push(list[i]);
}
}
return array;
}
// 添加数值变化监听事件
// monitor_name 要监听的属性名
// _name_array // 要修改的监听数组名
// state 重新点击第几层级
// _self // 全局作用域
function setListener(monitor_name, _name_array, state, _self) {
_self.monitor[monitor_name].subscribe(function (val) {
// 当总公司发生改变
cleanUpSelected(state, _self);
if (val && val.data_array) {
_self.monitor[_name_array](val["data_array"]);
}
if(monitor_name ==='depart_selected'){
if(val&&val["data_array"]&&val["data_array"].length>0){
_self.monitor["disabled_power"](false);
}else{
_self.monitor["disabled_power"](true);
}
}
}); // 监测值变化
}
// 遍历json格式对象 给每一层添加或修改属性
// list 数组
// id 属性值 string类型
// array 属性值 string类型
function setNewAttrInTraverse(list, id, array) {
for (let i = 0; i < list.length; i++) {
list[i][id] = Math.random(10000);
if (
list[i][array] &&
list[i][array] instanceof Array &&
list[i][array].length > 0
) {
// 如果子数列存在
setNewAttrInTraverse(list[i][array], id, array);
}
}
}
// 用于还原后面层级的初始状态
function cleanUpSelected(state, _self) {
switch (state) {
case 3:
// _self.monitor["game_selected"]({});
_self.monitor["game_selected"]({});
_self.monitor["monitor_game_name_array"]([]);
_self.monitor["selected_year"]("");
// _self.monitor["disabled_power"](true);
break;
case 2:
// _self.monitor["monitor_department_comp_array"]([]);
// _self.monitor["monitor_breach_comp_array"]([]);
_self.monitor["monitor_department_comp_array"]([]);
_self.monitor["monitor_game_name_array"]([]);
// _self.monitor["breach_selected"]({});
_self.monitor["depart_selected"]({});
_self.monitor["game_selected"]({});
_self.monitor["selected_year"]("");
break;
case 1:
// _self.monitor["monitor_head_comp_array"]([]);
_self.monitor["monitor_breach_comp_array"]([]);
_self.monitor["monitor_department_comp_array"]([]);
_self.monitor["monitor_game_name_array"]([]);
// _self.monitor["head_selected"]({});
_self.monitor["breach_selected"]({});
_self.monitor["depart_selected"]({});
_self.monitor["game_selected"]({});
_self.monitor["selected_year"]("");
break;
default:
}
}
</script>
<style type="text/css">
select {
width: 300px;
}
input {
width: 290px;
}
</style>
</html>