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.

399 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 选择列表插件
* varstion 1.0.1
* by Houfeng
* Houfeng@DCloud.io
*/
(function($, document) {
//创建 DOM
$.dom = function(str) {
if (typeof(str) !== 'string') {
if ((str instanceof Array) || (str[0] && str.length)) {
return [].slice.call(str);
} else {
return [str];
}
}
if (!$.__create_dom_div__) {
$.__create_dom_div__ = document.createElement('div');
}
$.__create_dom_div__.innerHTML = str;
return [].slice.call($.__create_dom_div__.childNodes);
};
var _listpickerId = 0;
var ListPicker = $.ListPicker = $.Class.extend({
init: function(box, options) {
var self = this;
if (!box) {
throw "构造 ListPicker 时找不到元素";
}
self.box = box;
//避免重复初始化开始
if (self.box.listpickerId) return;
self.listpickerId = self.box.listpickerId = "listpicker-" + (++_listpickerId);
//避免重复初始化结束
self.box.setAttribute('data-listpicker-id', self.box.listpickerId);
//处理 options
options = options || {};
options.fiexdDur = options.fiexdDur || 150;
options.highlightStyle = options.highlightStyle || 'color: green;';
//在 ios 上启用 h5 模式,
if ($.os.ios) {
options.enabledH5 = true;
}
//如果没有设定 enabled3d将默认用 3d 模式
if (options.enabled3d === null || typeof options.enabled3d === 'undefined') {
options.enabled3d = $.os.ios;
}
//
self.options = options;
self._create();
self._handleShim();
self._bindEvent();
self._applyToBox();
self._handleHighlight();
},
_create: function() {
var self = this;
self.boxInner = $('.mui-listpicker-inner', self.box)[0];
self.boxHeight = self.box.offsetHeight;
self.list = $('ul', self.boxInner)[0];
//refresh 中会执行 self.itemElementArray = [].slice.call($('li', self.list));
self.refresh();
var firstItem = self.itemElementArray[0];
self.itemHeight = 0;
if (firstItem) {
self.itemHeight = firstItem.offsetHeight;
} else {
self.list.innerHTML = "<li>...</li>";
firstItem = $('li', self.list)[0];
self.itemHeight = firstItem.offsetHeight;
self.list.innerHTML = '';
}
self.list.style.paddingTop = self.list.style.paddingBottom = (self.boxHeight / 2 - self.itemHeight / 2) + 'px';
//创建中间选中项的高亮行
self.rule = $.dom('<div class="mui-listpicker-rule"> </div>')[0];
self.rule.style.height = self.itemHeight + 'px';
self.rule.style.marginTop = -(self.itemHeight / 2) + 'px';
self.box.appendChild(self.rule);
self.middle = self.boxInner.offsetHeight / 2;
self.showLine = parseInt((self.boxInner.offsetHeight / self.itemHeight).toFixed(0));
//是否启用 3d 效果
if (self.options.enabled3d) {
self.box.classList.add('three-dimensional');
}
},
//根据 options 处理不同平台兼容问题
_handleShim: function() {
var self = this;
if (self.options.enabledH5) {
self.options.fiexdDur *= 2;
self.boxInner.classList.add($.className('scroll-wrapper'));
self.list.classList.add($.className('scroll'));
self._scrollerApi = $(self.boxInner).scroll({
deceleration: 0.002
});
//增加惯性滚动时的 scroll 触发处理
//shimTetTranslate(self._scrollerApi);
//--
self.setScrollTop = function(y, dur, callback) {
self._scrollerApi.scrollTo(0, -y, dur);
};
self.getScrollTop = function() {
var self = this;
if (self._scrollerApi.lastY > 0) {
return 0
} else {
return Math.abs(self._scrollerApi.lastY);
}
};
} else {
//alert(0);
//为 boxInner 增加 scrollend 事件 (没有原生 scrollend 事件)
self.boxInner.addEventListener('scroll', function(event) {
if (self.disabledScroll) return;
self.isScrolling = true;
if (self.scrollTimer) {
clearTimeout(self.scrollTimer);
}
self.scrollTimer = setTimeout(function() {
self.isScrolling = false;
if (!self.isTouchDown || !$.os.ios) {
$.trigger(self.boxInner, 'scrollend');
}
}, 150);
}, false);
self.aniScrollTop = function(y, dur, callback) {
self.disabledScroll = true;
var stepNum = dur > 0 ? dur / 10 : 1;
var stepSize = (y - self.boxInner.scrollTop) / stepNum;
self._lastScrollTop = self.boxInner.scrollTop; //记录最后的位置
self._aniScrollTop(y, 0, stepNum, stepSize, callback);
};
self._aniScrollTop = function(y, stepIndex, stepNum, stepSize, callback) {
self.boxInner.scrollTop = self._lastScrollTop + stepSize * stepIndex;
if (stepIndex < stepNum) {
setTimeout(function() {
self._aniScrollTop(y, ++stepIndex, stepNum, stepSize);
}, 10);
} else {
//self.boxInner.scrollTop = y;
self.disabledScroll = false;
if (callback) callback();
}
};
self.setScrollTop = function(y, dur, callback) {
self.aniScrollTop(y, dur);
};
self.getScrollTop = function() {
var self = this;
return self.boxInner.scrollTop;
};
//在 ios 上手指不弹起时,防止定位抖动开始
if ($.os.ios) {
self.boxInner.addEventListener('touchstart', function(event) {
var self = this;
self.isTouchDown = true;
}, false);
self.boxInner.addEventListener('touchend', function(event) {
self.isTouchDown = false;
if (!self.isScrolling) {
setTimeout(function() {
$.trigger(self.boxInner, 'scrollend');
}, 0);
}
}, false);
}
//在 ios 上手指不弹起时,防止定位抖动结束
}
},
_handleHighlight: function() {
var self = this;
var scrollTop = self.getScrollTop();
var fiexd = parseInt((scrollTop / self.itemHeight).toFixed(0));
var lastIndex = self.itemElementArray.length - 1;
var displayRange = parseInt((self.showLine / 2).toFixed(0));
var displayBegin = fiexd - displayRange;
var displayEnd = fiexd + displayRange;
if (displayBegin < 0) {
displayBegin = 0;
}
if (displayEnd > lastIndex) {
displayEnd = lastIndex;
}
//高亮选中行开始
for (var index = displayBegin; index <= displayEnd; index++) {
var itemElement = self.itemElementArray[index];
if (index == fiexd) {
itemElement.classList.add($.className('listpicker-item-selected'));
//itemElement.classList.remove($.className('listpicker-item-before'));
//itemElement.classList.remove($.className('listpicker-item-after'));
} else {
//itemElement.classList.add($.className('listpicker-item-' + (fiexd > index ? 'before' : 'after')));
itemElement.classList.remove($.className('listpicker-item-selected'));
}
if (self.options.enabled3d) {
//3d 处理开始
var itemOffset = self.middle - (itemElement.offsetTop - scrollTop + self.itemHeight / 2) + 1;
var percentage = itemOffset / self.itemHeight;
var angle = (18 * percentage);
//if (angle > 180) angle = 180;
//if (angle < -180) angle = -180;
itemElement.style.webkitTransform = 'rotateX(' + angle + 'deg) translate3d(0px,0px,' + (0 - Math.abs(percentage * 12)) + 'px)';
//3d 处理结束
}
}
},
_triggerChange: function() {
var self = this;
$.trigger(self.box, 'change', {
index: self.getSelectedIndex(),
value: self.getSelectedValue(),
text: self.getSelectedText(),
item: self.getSelectedItem(),
element: self.getSelectedElement()
});
},
_scrollEndHandle: function() {
var self = this;
var scrollTop = self.getScrollTop();
var fiexd = (scrollTop / self.itemHeight).toFixed(0);
self.disabledScrollEnd = true;
self.setSelectedIndex(fiexd);
self._triggerChange();
self._handleHighlight();
setTimeout(function() {
self.disabledScrollEnd = false;
self._handleHighlight();
}, self.options.fiexdDur);
},
_bindEvent: function() {
var self = this;
//滚动处理高亮
self.boxInner.addEventListener('scroll', function(event) {
self._handleHighlight(event);
}, false);
//处理滚动结束
self.disabledScrollEnd = false;
self.boxInner.addEventListener('scrollend', function(event) {
if (self.disabledScrollEnd) return;
self.disabledScrollEnd = true;
self._scrollEndHandle();
}, false);
//绑定项 tap 事件
$(self.boxInner).on('tap', 'li', function(event) {
var tapItem = this;
var items = [].slice.call($('li', self.list));
for (var i in items) {
var item = items[i];
if (item == tapItem) {
self.setSelectedIndex(i);
return;
}
};
});
},
getSelectedIndex: function() {
var self = this;
return (self.getScrollTop() / self.itemHeight).toFixed(0);
},
setSelectedIndex: function(index, noAni) {
var self = this;
index = (index || 0);
self.setScrollTop(self.itemHeight * index, noAni ? 0 : self.options.fiexdDur);
},
getSelectedElement: function() {
var self = this;
var index = self.getSelectedIndex();
return $('li', self.list)[index];
},
getSelectedItem: function() {
var self = this;
var itemElement = self.getSelectedElement();
if (!itemElement) return null;
var itemJson = itemElement.getAttribute('data-item');
return itemJson ? JSON.parse(itemJson) : {
text: itemElement.innerText,
value: itemElement.getAttribute('data-value')
};
},
refresh: function() {
var self = this;
self.itemElementArray = [].slice.call($('li', self.list));
},
setItems: function(items) {
var self = this;
var buffer = [];
for (index in items) {
var item = items[index] || {
text: 'null',
value: 'null' + index
};
var itemJson = JSON.stringify(item);
buffer.push("<li data-value='" + item.value + "' data-item='" + itemJson + "'>" + item.text + "</li>");
};
self.list.innerHTML = buffer.join('');
if (self._scrollerApi && self._scrollerApi.refresh) {
self._scrollerApi.refresh();
}
self.refresh();
self._handleHighlight();
self._triggerChange();
},
getItems: function() {
var self = this;
var items = [];
var itemElements = $('li', self.list);
for (index in itemElements) {
var itemElement = itemElements[index];
var itemJson = itemElement.getAttribute('data-item');
items.push(itemJson ? JSON.parse(itemJson) : {
text: itemElement.innerText,
value: itemElement.getAttribute('data-value')
});
}
return items;
},
getSelectedValue: function() {
var self = this;
var item = self.getSelectedItem();
if (!item) return null;
return item.value;
},
getSelectedText: function() {
var self = this;
var item = self.getSelectedItem();
if (!item) return null;
return item.text;
},
setSelectedValue: function(value, noAni) {
var self = this;
var itemElements = $('li', self.list);
for (index in itemElements) {
var itemElement = itemElements[index];
if (!itemElement || !itemElement.getAttribute) {
continue;
}
if (itemElement.getAttribute('data-value') == value) {
self.setSelectedIndex(index, noAni);
return;
}
}
},
_applyToBox: function() {
var self = this;
var memberArray = [
"getSelectedIndex",
"setSelectedIndex",
"getSelectedElement",
"getSelectedItem",
"setItems",
"getItems",
"getSelectedValue",
"getSelectedText",
"setSelectedValue"
];
var _clone = function(name) {
if (typeof self[name] === 'function') {
self.box[name] = function() {
return self[name].apply(self, arguments);
};
} else {
self.box[name] = self[name];
}
};
for (var i in memberArray) {
var name = memberArray[i];
_clone(name);
}
}
});
//添加 locker 插件
$.fn.listpicker = function(options) {
//遍历选择的元素
this.each(function(i, element) {
if (options) {
new ListPicker(element, options);
} else {
var optionsText = element.getAttribute('data-listpicker-options');
var _options = optionsText ? JSON.parse(optionsText) : {};
_options.enabledH5 = element.getAttribute('data-listpicker-enabledh5') || _options.enabledH5;
_options.enabled3d = element.getAttribute('data-listpicker-enabled3d') || _options.enabled3d;
_options.fixedDur = element.getAttribute('data-listpicker-fixddur') || _options.fixedDur;
new ListPicker(element, _options);
}
});
return this;
};
//自动初始化
$.ready(function() {
$('.mui-listpicker').listpicker();
});
})(mui, document);