You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.4 KiB
187 lines
6.4 KiB
/** |
|
* IndexedList |
|
* 类似联系人应用中的联系人列表,可以按首字母分组 |
|
* 右侧的字母定位工具条,可以快速定位列表位置 |
|
* varstion 1.0.0 |
|
* by Houfeng |
|
* Houfeng@DCloud.io |
|
**/ |
|
|
|
(function($, window, document) { |
|
|
|
var classSelector = function(name) { |
|
return '.' + $.className(name); |
|
} |
|
|
|
var IndexedList = $.IndexedList = $.Class.extend({ |
|
/** |
|
* 通过 element 和 options 构造 IndexedList 实例 |
|
**/ |
|
init: function(holder, options) { |
|
var self = this; |
|
self.options = options || {}; |
|
self.box = holder; |
|
if (!self.box) { |
|
throw "实例 IndexedList 时需要指定 element"; |
|
} |
|
self.createDom(); |
|
self.findElements(); |
|
self.caleLayout(); |
|
self.bindEvent(); |
|
}, |
|
createDom: function() { |
|
var self = this; |
|
self.el = self.el || {}; |
|
//styleForSearch 用于搜索,此方式能在数据较多时获取很好的性能 |
|
self.el.styleForSearch = document.createElement('style'); |
|
(document.head || document.body).appendChild(self.el.styleForSearch); |
|
}, |
|
findElements: function() { |
|
var self = this; |
|
self.el = self.el || {}; |
|
self.el.search = self.box.querySelector(classSelector('indexed-list-search')); |
|
self.el.searchInput = self.box.querySelector(classSelector('indexed-list-search-input')); |
|
self.el.searchClear = self.box.querySelector(classSelector('indexed-list-search') + ' ' + classSelector('icon-clear')); |
|
self.el.bar = self.box.querySelector(classSelector('indexed-list-bar')); |
|
self.el.barItems = [].slice.call(self.box.querySelectorAll(classSelector('indexed-list-bar') + ' a')); |
|
self.el.inner = self.box.querySelector(classSelector('indexed-list-inner')); |
|
self.el.items = [].slice.call(self.box.querySelectorAll(classSelector('indexed-list-item'))); |
|
self.el.liArray = [].slice.call(self.box.querySelectorAll(classSelector('indexed-list-inner') + ' li')); |
|
self.el.alert = self.box.querySelector(classSelector('indexed-list-alert')); |
|
}, |
|
caleLayout: function() { |
|
var self = this; |
|
var withoutSearchHeight = (self.box.offsetHeight - self.el.search.offsetHeight) + 'px'; |
|
self.el.bar.style.height = withoutSearchHeight; |
|
self.el.inner.style.height = withoutSearchHeight; |
|
var barItemHeight = ((self.el.bar.offsetHeight - 40) / self.el.barItems.length) + 'px'; |
|
self.el.barItems.forEach(function(item) { |
|
item.style.height = barItemHeight; |
|
item.style.lineHeight = barItemHeight; |
|
}); |
|
}, |
|
scrollTo: function(group) { |
|
var self = this; |
|
var groupElement = self.el.inner.querySelector('[data-group="' + group + '"]'); |
|
if (!groupElement || (self.hiddenGroups && self.hiddenGroups.indexOf(groupElement) > -1)) { |
|
return; |
|
} |
|
self.el.inner.scrollTop = groupElement.offsetTop; |
|
}, |
|
bindBarEvent: function() { |
|
var self = this; |
|
var pointElement = null; |
|
var findStart = function(event) { |
|
if (pointElement) { |
|
pointElement.classList.remove('active'); |
|
pointElement = null; |
|
} |
|
self.el.bar.classList.add('active'); |
|
var point = event.changedTouches ? event.changedTouches[0] : event; |
|
pointElement = document.elementFromPoint(point.pageX, point.pageY); |
|
if (pointElement) { |
|
var group = pointElement.innerText; |
|
if (group && group.length == 1) { |
|
pointElement.classList.add('active'); |
|
self.el.alert.innerText = group; |
|
self.el.alert.classList.add('active'); |
|
self.scrollTo(group); |
|
} |
|
} |
|
event.preventDefault(); |
|
}; |
|
var findEnd = function(event) { |
|
self.el.alert.classList.remove('active'); |
|
self.el.bar.classList.remove('active'); |
|
if (pointElement) { |
|
pointElement.classList.remove('active'); |
|
pointElement = null; |
|
} |
|
}; |
|
self.el.bar.addEventListener($.EVENT_MOVE, function(event) { |
|
findStart(event); |
|
}, false); |
|
self.el.bar.addEventListener($.EVENT_START, function(event) { |
|
findStart(event); |
|
}, false); |
|
document.body.addEventListener($.EVENT_END, function(event) { |
|
findEnd(event); |
|
}, false); |
|
document.body.addEventListener($.EVENT_CANCEL, function(event) { |
|
findEnd(event); |
|
}, false); |
|
}, |
|
search: function(keyword) { |
|
var self = this; |
|
keyword = (keyword || '').toLowerCase(); |
|
var selectorBuffer = []; |
|
var groupIndex = -1; |
|
var itemCount = 0; |
|
var liArray = self.el.liArray; |
|
var itemTotal = liArray.length; |
|
self.hiddenGroups = []; |
|
var checkGroup = function(currentIndex, last) { |
|
if (itemCount >= currentIndex - groupIndex - (last ? 0 : 1)) { |
|
selectorBuffer.push(classSelector('indexed-list-inner li') + ':nth-child(' + (groupIndex + 1) + ')'); |
|
self.hiddenGroups.push(liArray[groupIndex]); |
|
}; |
|
groupIndex = currentIndex; |
|
itemCount = 0; |
|
} |
|
liArray.forEach(function(item) { |
|
var currentIndex = liArray.indexOf(item); |
|
if (item.classList.contains($.className('indexed-list-group'))) { |
|
checkGroup(currentIndex, false); |
|
} else { |
|
var text = (item.innerText || '').toLowerCase(); |
|
var value = (item.getAttribute('data-value') || '').toLowerCase(); |
|
var tags = (item.getAttribute('data-tags') || '').toLowerCase(); |
|
if (keyword && text.indexOf(keyword) < 0 && |
|
value.indexOf(keyword) < 0 && |
|
tags.indexOf(keyword) < 0) { |
|
selectorBuffer.push(classSelector('indexed-list-inner li') + ':nth-child(' + (currentIndex + 1) + ')'); |
|
itemCount++; |
|
} |
|
if (currentIndex >= itemTotal - 1) { |
|
checkGroup(currentIndex, true); |
|
} |
|
} |
|
}); |
|
if (selectorBuffer.length >= itemTotal) { |
|
self.el.inner.classList.add('empty'); |
|
} else if (selectorBuffer.length > 0) { |
|
self.el.inner.classList.remove('empty'); |
|
self.el.styleForSearch.innerText = selectorBuffer.join(', ') + "{display:none;}"; |
|
} else { |
|
self.el.inner.classList.remove('empty'); |
|
self.el.styleForSearch.innerText = ""; |
|
} |
|
}, |
|
bindSearchEvent: function() { |
|
var self = this; |
|
self.el.searchInput.addEventListener('input', function() { |
|
var keyword = this.value; |
|
self.search(keyword); |
|
}, false); |
|
$(self.el.search).on('tap', classSelector('icon-clear'), function() { |
|
self.search(''); |
|
}, false); |
|
}, |
|
bindEvent: function() { |
|
var self = this; |
|
self.bindBarEvent(); |
|
self.bindSearchEvent(); |
|
} |
|
}); |
|
|
|
//mui(selector).indexedList 方式 |
|
$.fn.indexedList = function(options) { |
|
//遍历选择的元素 |
|
this.each(function(i, element) { |
|
if (element.indexedList) return; |
|
element.indexedList = new IndexedList(element, options); |
|
}); |
|
return this[0] ? this[0].indexedList : null; |
|
}; |
|
|
|
})(mui, window, document); |