因此,我目前正在使用此代码来呈现元素列表,并(希望)指定活动元素,当其中一个元素被单击时,该元素可以更改。
let active_experiment_id = null;
function set_experiments() {
const u = d3.select('#experiments')
.selectAll('li')
.data(Object.values(experiments).sort((a, b) => {
const a_time = moment(a['created']),
b_time = moment(b['created']);
if (a_time.isBefore(b_time))
return 1;
else if (a_time.isAfter(b_time))
return -1;
else
return 0;
}), (d) => d);
const entering = u.enter()
.append('li')
.classed('nav-item', true)
.classed('active', (d) => d.active_experiment)
.on('click', d => {
if (d.experiment_id !== active_experiment_id)
set_active_experiment(d.experiment_id);
})
.append('a')
.classed('nav-link', true)
.classed('active', (d) => d.active_experiment)
.append('p')
.text((d) => { return d.name; });
u.exit().remove();
}
function set_active_experiment(experiment_id) {
if (experiment_id === null) {
active_experiment_id = null;
set_classes(null);
set_workflows(null);
set_tasks(null);
set_seleced_task(null, null);
return;
}
if (active_experiment_id !== null)
experiments[active_experiment_id].active_experiment = false;
active_experiment_id = experiment_id;
experiments[active_experiment_id].active_experiment = true;
fetch_tasks(experiment_id)
.then(() => {
set_experiments();
set_classes(experiment_id);
set_workflows(experiment_id);
set_tasks(experiment_id);
set_selected_task(experiment_id, experiments[experiment_id].root_task_id);
});
}我目前在列表中有两个数据元素,我可以单击第二个数据元素并获得要应用的active类。但是,我不能让第一个被点击。我尝试了调试,但在第一个任务(下面的experiment_id=2)上甚至没有调用enter函数。这些元素如下所示:
experiments = {1: {
experiment_id: 1,
name: "Experiment One",
created: (before 2)
...
}, 2: {
experiment_id: 2,
name: "Experiment Two",
created: (after 1),
...
}发布于 2019-11-20 23:08:22
我相信我已经弄明白了问题所在。因为我使用的是Object.values,所以只有第二个实验保持了它的位置。在此之后,由于数据是通过引用直接绑定的(使用键(d) => d),因此d3会将元素本身作为键测试进行比较。因此,无论您选择哪种键方法,d3仍然会将对象的键与其自身进行比较,而不会注册该对象是否已更新。因此,为了解决这个问题,我每次都会创建一个数据的投影副本,并使用一个新的键方法来减少通过enter和exit的对象数量。
function set_experiments() {
const key = d => `${d.experiment_id}${d.active_experiment}`;
const data = Object.values(experiments).sort((a, b) => {
const a_time = moment(a['created']),
b_time = moment(b['created']);
if (a_time.isBefore(b_time))
return 1;
else if (a_time.isAfter(b_time))
return -1;
else
return 0;
})
.map(d => ({
"experiment_id": d.experiment_id,
"created": d.created,
"name": d.name,
"active_experiment": d.active_experiment,
}));
const u = d3.select('#experiments')
.selectAll('li')
.data(data, key);
const entering = u.enter()
.append('li')
.classed('nav-item', true)
.classed('active', (d) => {
num_entered++;
return d.active_experiment;
})
.on('click', d => {
if (d.experiment_id !== active_experiment_id) {
set_active_experiment(d.experiment_id);
}
})
.append('a')
.classed('nav-link', true)
.classed('active', (d) => {
return d.active_experiment;
})
.append('p')
.text((d) => { return d.name; });
u.exit().remove();
}虽然它不是最有效的,因为我仍然必须复制所有数据,但复制的数据不会影响DOM。只有更新值才是,因为新的键方法删除了多余的添加和删除。
https://stackoverflow.com/questions/58947074
复制相似问题