我有一个曲目列表\来源,在不同页面上显示了几次。我想允许用户对列表进行独立排序(每页)。
我可以创建此列表的几个副本,但是问题是可以更改此列表(添加\删除\重命名曲目等),因此在这种情况下,此列表的几个副本似乎不是一个好的解决方案,因为此类更改必须应用于列表的所有副本。
有没有一种技术可以仅对一个轨道源进行独立的轨道排序?
答案 0 :(得分:0)
您基本上有两种选择:
1)当列表更改时,通知所有拥有其列表排序版本的所有组件,以便它们可以复制更改的列表并对其进行排序/显示。为此,您需要一种发出事件的方式,例如作为混合类:
const EventEmitter = Parent => class EventEmitter extends Parent {
constructor(...args) {
super(...args);
this._emitters = {};
}
trigger(evt, ...args) {
(this._emitters[evt] || []).forEach(emitter => emitter(...args));
}
on(evt, handler) {
(this._emitters[evt] || (this._emitters[evt] = [])).push(handler);
}
};
然后,您可以代理一个数组,以便在每次更改时触发更新事件:
const ChangeEmitter = Parent => {
const Mixin = EventEmitter(Parent);
return (...args) => new Proxy(
new Mixin(...args),
{
set(obj, prop, value) {
const result = Reflect.set(...arguments);
obj.trigger("update", obj);
return result;
}
}
);
};
这看起来很复杂,但是现在我们可以这样做:
// Our source of truth:
const base = new ChangeEmitter(Array);
// One of the functions that renders the data:
function renderSorted(array) {
const sorted = array.sort();
document.body.innerHTML = sorted;
}
renderSorted(base); // Initial render
base.on("update", renderSorted);
base[0] = 1;
因此,每当我们更新基本数组时,所有渲染器都将再次被调用,并且所有内容都可以更新。
2)创建一些排序的数组,并将每个突变应用于所有数组。为此,我们需要一个排序数组:
class SortedArray extends Array {
constructor(sorter, ...args) {
super(...args);
this.sorter = sorter;
this.sort(sorter);
}
// Do insertion sort
add(el) {
let index = 0;
while(index <= this.length && this.sorter(el, this[index]) > 0) index++;
this splice(index, 0, el);
}
remove(el) {
this.splice(this.indexOf(el), 1);
}
}
以及一种并行更改多个数组的方法:
const unifyArrays = (...arrays) => ({
add(el) { arrays.forEach(arr => arr.add(el)); },
remove(el) { arrays.forEach(arr => arr.remove(el)); }
});
现在您可以这样做:
const sorted = new SortedArray((a, b) => a - b);
const reversed = new SortedArray((a, b) => b - a);
const base = unifyArrays(sorted, reversed);
base.add(1);
请确保您可以结合使用这两种方法,以便在更改数组时会发出偶数。