我知道,通过List.js示例,通过List.js创建可搜索列表是almost trivial。使用some additional effort,可以将分页添加到列表中。但是,afaik无法自定义寻呼机。另外,从JavaScript方面传递到列表的数据似乎有点...静态。
我的业务要求如下:
在“编辑菜单”页面中,类别和项目可以添加到菜单中。为此,用户单击“添加类别”或“添加项目”按钮,并弹出相应的模式
用户将不会以该模式看到菜单上已经存在的类别,也不会看到其所在类别中的任何项目(例如,如果Category1包含ItemA,ItemB,... ItemK,然后,当Category1处于活动状态时,这些项都不应该出现在模式中。但是,如果Category2为空,并且单击它,然后出现模式,则它们都应该出现。)
这些要求已经得到满足,但是由于可能在模态中出现成千上万的项目,我现在被赋予了分页模态并相应地更新过滤策略的任务。
这里是IIFE,它用作菜单状态(一切都作用在菜单上并使用(我提供了所有代码,以便提供向其状态添加/删除类别/项目的方法):
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
updateQueue.async {
if let imageAnchor = anchor as? ARImageAnchor {
guard let lastAnchor = self.lastImageAnchor else { return }
if imageAnchor != lastAnchor {
self.session.remove(anchor: lastAnchor)
}
}
}
}
按照第一个链接,有一种方法可以将对象传递给List.js API。但是,由于JavaScript不是传递引用,因此,我需要以某种方式让List.js调用正确的方法来获取列表的正确数据,即项目的/* all the categories, items, and modifiers that power this page */
const menuState = (function() {
class MenuData {
constructor(attached = [], available = []) {
// attached,available MUST be arrays!
if ((!Array.isArray(attached)) || (!Array.isArray(available))) {
throw TypeError("passed data MUST be in the form of Arrays!")
}
this.attached = attached;
this.available = available;
}
add(entities) {
// entities MUST be Array
if (!Array.isArray(entities)) throw ReferenceError("entities must be array")
// from here, we simply move from this.available to this.attached, the entities
// but first, let's check if they're even available
if (hasEntities(entities, this.available)) {
// attach them
this.attached = this.attached.concat(entities)
// they are no longer available
this.available= this.available
.filter(excluderFactory(entities))
}
// if they're not attached, that is an error
if (!hasEntities(entities, this.attached)) {
throw Error('The entities you were trying to add were neither attached nor available')
}
}
remove(entities) {
// entities MUST be Array
if (!Array.isArray(entities)) throw ReferenceError("entities must be array")
// from here, we simply move from this.attached to this.available, the entities
// but first, let's check if they're even attached
if (hasEntities(entities, this.attached)) {
// make them available
this.available = this.available.concat(entities)
// detach them
this.attached = this.attached
.filter(excluderFactory(entities))
}
// if they're not available, that is an error
if (!hasEntities(entities, this.available)) {
throw Error('The entities you were trying to remove were neither attached nor available')
}
}
};
let _categories = new MenuData(),
_items = new MenuData()
let _itemPool = [],
_categoryItems = {}
/**
* Determines if an array has entities with an Id.
* @param {Object[]} entities
* @param {Object[]} arrayToCheck
* @returns {boolean} whether arrayToCheck has objects with entities' Ids.
*/
function hasEntities(entities, arrayToCheck) {
for (let idx in entities) {
if (arrayToCheck.find((element) => element.Id === entities[idx].Id)) {
if (idx == entities.length - 1) {
return true;
}
continue;
}
return false;
}
}
/**
* Returns a callback for the purpose of excluding entities
* @param {Object[]} entities the entities to exclude
*/
function excluderFactory(entities) {
return function(model) {
return !entities.find((entity) => entity.Id === model.Id)
}
}
return {
getAllCategories : () => _categories.attached.concat(_categories.available),
getAttachedCategories : () => _categories.attached.slice(),
getAvailableCategories : () => _categories.available.slice(),
addCategories : (categories) => {
_categories.add(categories)
},
removeCategories : (categories) => {
_categories.remove(categories)
},
/**
* Updates the _items to the category.
* @param {Object} category the category object to update to. MUST HAVE ID!
*/
changeCurrentCategory : function(category) {
if (category.Id === undefined) {
throw ReferenceError("Category MUST have Id!")
}
_items = _categoryItems[category.Id]
},
// because _items can be reset to reference other states, we MUST
// directly reference it in these public methods
getAllItems : () => _items.attached.concat(_items.available).slice(),
getAttachedItems : () => _items.attached.slice(),
getAvailableItems : () => _items.available.slice(),
addItems : function(entities) {
return _items.add(entities)
},
removeItems : function(entities) {
return _items.remove(entities)
},
/**
* initializes the item pool of the menu state.
* All category-item states are constructed from the item pool.
*
* @param {Object[]} items
*/
initItemPool : (items) => {
if (!Array.isArray(items)) {
throw TypeError("item pool can only be initialized with an Array.")
}
// if _itemPool already has data, we're done here
if (_itemPool.length) {
throw Error("item pool is already initialized!")
}
_itemPool = items
},
getItemPool : () => _itemPool.slice(),
initCategories : (categories) => {
if (!Array.isArray(categories)) {
throw TypeError("categories can only be initialized with an Array.")
}
// if _categories already has data, we're done here
if ((_categories.attached.length) || (_categories.available.length)) {
throw Error("categories is already initialized!")
}
_categories = new MenuData([], categories)
},
/**
* Creates an entry in the category items object
* @param {number} categoryId : the ID of the category containing these items
* @param {Object[]} categoryItems : the category items. These are assumed attached to a category
*/
addCategoryItems : function(categoryId, categoryItems) {
categoryId = parseInt(categoryId) || 0
// if there is entry for categoryId already
if (_categoryItems[categoryId]) {
// throw an error
throw Error(`There already exists data for category with ID ${categoryId} !`)
}
// make the "complement" of categoryItems, using _itemPool
let availableItems = _itemPool.filter(excluderFactory(categoryItems))
// write categoryItems,availableItems to key categoryId of _categoryItems
_categoryItems[categoryId] = new MenuData(categoryItems,
availableItems)
},
getCategoryItems : () => _categoryItems
}
})()
,getAvailableItems
选择器和类别选择器模态。
有没有办法让List.js做到这一点(我无法在任何地方找到示例 )?