当前位置:网站首页>mobile-picker.js
mobile-picker.js
2022-07-29 01:16:00 【kilito_01】
(function(global){
var PICKERCOUNT = 0;
var body = document.getElementsByTagName("body")[0];
var coordinate = {
start: {
y:0},end: {
y:0,status:true}, move: {
y:0}};
var Util = {
removeClass: function(el, className) {
var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
el.className = el.className.replace(reg, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
},
addClass: function(el, className) {
!Util.hasClass(el,className) && (el.className += (el.className ? ' ' : '') + className);
},
hasClass: function(el, className) {
return !!el.className && new RegExp('(^|\\s)' + className + '(\\s|$)').test(el.className);
},
loop: function(start,end,handle){
for(var i = start; i < end; i++){
Util.isFunc(handle) && handle(i);
}
},
isFunc: function(name){
return typeof name === 'function';
},
isArray: function(o) {
return Object.prototype.toString.call(o) === '[object Array]';
},
isObject: function(o) {
return typeof o === 'object';
},
damping: function (value) {
//阻尼运算
var steps = [20, 40, 60, 80, 100],rates = [0.5, 0.4, 0.3, 0.2, 0.1];
var result = value,len = steps.length;
while (len--) {
if (value > steps[len]) {
result = (value - steps[len]) * rates[len];
for (var i = len; i > 0; i--) {
result += (steps[i] - steps[i - 1]) * rates[i - 1];
}
result += steps[0] * 1;
break;
}
}
return result;
},
createEle: function(parent, tag, className, html) {
var ele = document.createElement(tag);
className && Util.addClass(ele,className);
html && (ele.innerHTML = html);
parent && parent.appendChild(ele);
return ele;
},
getEle: function(ctx, selector) {
return ctx.querySelector(selector);
},
setTransform: function(el,y) {
el.style.transform = 'translate3d(0,'+ y +'px,0)';
}
}
function Picker(config){
this.index = ++PICKERCOUNT;//当前选择器的索引
this.target = config.target instanceof HTMLElement ? config.target : typeof config.target === "string" ? Util.getEle(document,config.target) : null;//触发选择器的dom元素
this.data = config.data || [];//需要显示的数据
this.value = config.value ? (Util.isArray(config.value) ? config.value : config.value.split(',')) : [];//选择器默认值
this.childKey = config.childKey || 'child';//子数据索引名
this.valueKey = config.valueKey || 'value';//用于索引初始值的key
this.textKey = config.textKey || 'value';//用于显示的key
this.autoFill = !(config.autoFill === false);//选择确定后是否填充到目标元素
this.confirm = config.confirm;//确定选择的回调
this.cancel = config.cancel;//取消回调
this.initCallback = config.initCallback;//实例化完成的回调
this.select = config.select;//单个列表选择后的回调
this.lock = config.lock === true;//锁定确定按钮,用于异步加载时等待使用
this.className = config.className || '';//定制的类名
this.init();
}
Picker.prototype = {
constructor: Picker,
init: function(){
this.initResult();
var html = '<div class="mp-container"><div class="mp-header"><span class="mp-cancel">取消</span><span class="mp-confirm'+(this.lock ? ' disabled' : '')+'">确定</span></div><div class="mp-content"><div class="mp-shadowup"></div><div class="mp-shadowdown"></div><div class="mp-line"></div><div class="mp-box"></div></div>';
var container = Util.createEle(body,'div','mp-mask',html);
this.className && Util.addClass(container,this.className);
container.id = 'mobilePicker'+this.index;
this.container = container;
this.box = Util.getEle(container, '.mp-box')//用于包含滚动元素的容器
this.createScroll(this.data);//核心方法:创建滚动的元素
this.value = [];
this.bindEvent();//绑定事件
this.finisInit();
},
initResult: function(config){
this.scrollCount = 0;//已渲染的数据层级数
this.selectIndex = [];//每个层级选中的索引集合
this.result = [];//选择器最终的结果
this.offset = [];//每个层级滚动的偏移量集合
},
finisInit: function(){
var value = this.fillResult();
Util.isFunc(this.initCallback) && this.initCallback(value,this.result);
},
update: function(options){
for(var i in options) {
this[i] = options[i];
}
this.initResult()
this.box.innerHTML = '';
this.createScroll(this.data);
this.value = [];
},
getData: function(indexes){
//获取数据集合
var arr = [];
for(var i = 0; i < indexes.length; i++){
arr = i == 0 ? this.data : arr[indexes[i -1]][this.childKey];
}
return arr;
},
setResult: function(data){
if(!Util.isObject(data)) return data;
var temp = {
};
for(var key in data){
key != this.childKey && (temp[key] = data[key]);
}
return temp;
},
createScroll: function(data){
var scroll = Util.createEle(this.box,'div','mp-list-wrap','<ul></ul>');
scroll.scrollIndex = this.scrollCount++;
this.addList(Util.getEle(scroll, 'ul'), data);
},
getText: function(data){
return Util.isObject(data) ? data[this.textKey] : data;
},
addList: function(parent, data){
var html = '',that = this;
var index = 0,scrollIndex = parent.parentNode.scrollIndex,text = '';
Util.loop(0,data.length,function(i){
text = that.getText(data[i]);
html += '<li>'+text+'</li>';
//初始化时有默认值,应该选中当前值,否则index就会为0,即选中第一个
if(that.value.length && that.value[scrollIndex] && (Util.isObject(data[i]) && data[i][that.valueKey] == that.value[scrollIndex][that.valueKey] || data[i] == that.value[scrollIndex])){
index = i;
}
});
parent.innerHTML = html;
this.offset.push(0);
this.selectItem(data, index, scrollIndex);//选中并创建下一级选择器
},
updateList: function(index,data){
var dom = this.box.childNodes[index];
if(!dom){
this.createScroll(data);
return;
}
dom = Util.getEle(dom,'ul');
this.addList(dom, data);
},
setScroll: function(index,data,value,callback) {
value && (this.value[index] = value);
this.offset.length = this.selectIndex.length = this.result.length = this.selectIndex.length = index;
if(index == 0){
this.data = data;
} else {
var temp = this.data[this.selectIndex[0]];
for(var i = 1, len = index; i < len; i++){
temp = temp[this.childKey][this.selectIndex[i]];
}
temp && (temp[this.childKey] = data);
}
this.updateList(index,data);
this.value = [];
Util.isFunc(callback) && callback(index,this.result);
},
removeScroll: function(index){
var that = this;
var node = this.box.childNodes[index];
if(node){
this.box.removeChild(node);
this.scrollCount--;
this.calcWidth();
}
},
calcWidth: function() {
var wraps = this.box.querySelectorAll('.mp-list-wrap');
for(var m = 0; m < wraps.length; m++){
wraps[m].style.width = (100 / this.scrollCount) + '%';
}
},
selectItem:function(data, index, scrollIndex){
//params: 数据,选中的索引,当前scroll的索引
var that = this;
var oldScrollCount = this.scrollCount;
this.selectIndex.length = this.result.length = scrollIndex + 1;
this.selectIndex[scrollIndex] = index;
this.result[scrollIndex] = this.setResult(data[index]);
this.setOffset(scrollIndex, index);
if(data[index] && data[index][that.childKey] && Util.isArray(data[index][that.childKey]) && data[index][that.childKey].length){
//存在子元素
if(that.scrollCount < scrollIndex + 2){
//如果上一次的ul个数少于当前需要的个数,则创建新的ul
that.createScroll(data[index][that.childKey]);
} else {
that.updateList(scrollIndex + 1, data[index][that.childKey]);
}
} else {
//说明当前的滚动器数目多于需要的,移除多余的
for ( var j = oldScrollCount - 1, len = that.selectIndex.length; j >= len; j-- ) {
//删除多余的ul
that.removeScroll(j);
}
}
// this.scrollIndex = this.offset.length = this.selectIndex.length;
this.offset.length = this.selectIndex.length;
this.calcWidth();//计算滚动对象的宽度
Util.isFunc(that.select) && that.select(scrollIndex,this.result,index,data[index] && data[index][that.childKey] && Util.isArray(data[index][that.childKey]) && data[index][that.childKey].length);
},
fillContent: function(content){
var tagName = this.target.tagName.toLowerCase();
if(['input','select','textarea'].indexOf(tagName) != -1) {
this.target.value = content;
} else {
this.target.innerText = content;
}
},
fillResult: function(){
var value = '';
for(var i = 0,len = this.result.length; i < len; i++){
if(Util.isObject(this.result[i])){
this.result[i][this.textKey] && (value += this.result[i][this.textKey]);
} else {
value += this.result[i];
}
}
this.autoFill && this.fillContent(value);
return value;
},
hide: function(){
var that = this;
Util.getEle(this.container,'.mp-container').style.transform = 'translate3d(0,100%,0)';
Util.removeClass(body, 'mp-body');
setTimeout(function(){
that.container.style.visibility = 'hidden';
},250)
},
show: function(){
var that = this;
that.container.style.visibility = 'visible';
Util.addClass(body, 'mp-body');
setTimeout(function(){
Util.getEle(that.container,'.mp-container').style.transform= 'translate3d(0,0,0)';
},0)
},
setOffset: function(scrollIndex, index){
var scroll = this.box.childNodes[scrollIndex].querySelector('ul');
var offset = scroll.childNodes[0] ? scroll.childNodes[0].offsetHeight * index : 0;
Util.setTransform(scroll, -offset)
this.offset[scrollIndex] = offset;
},
setLock: function(value){
var confirm = Util.getEle(this.container,'.mp-confirm'),old = this.lock;
this.lock = value !== false;
if(old !== this.lock) {
this.lock ? Util.addClass(confirm,'disabled') : Util.removeClass(confirm, 'disabled');
}
},
bindEvent: function(){
var that = this;
that.target.disabled = true;
['touchstart','touchend','touchmove'].forEach(function(action){
that.box.parentNode.addEventListener(action,function(event){
event = event || window.event;
event.preventDefault();
var target = event.target;
var index = target.parentNode.scrollIndex;
var child = target.childNodes;
var liHeight = child[child.length - 1].offsetHeight;
var scrollHeight = child[child.length - 2].offsetTop;
if(target.tagName.toLowerCase() != 'ul') return;
switch(action) {
case 'touchstart':
if(coordinate.end.status){
coordinate.end.status = !coordinate.end.status;
coordinate.start.y = event.touches[0].clientY;
coordinate.start.time = Date.now();
}
break;
case 'touchmove':
coordinate.move.y = event.touches[0].clientY;
var distance = coordinate.start.y - coordinate.move.y;
var os = distance + that.offset[index];
if(os < 0){
//已经滑到最顶部
Util.setTransform(target, Util.damping(-os));
} else if(os <= scrollHeight){
Util.setTransform(target, -os);
} else {
//超过了整体的高度
Util.setTransform(target, -(scrollHeight + Util.damping(os-scrollHeight)));
}
break;
case 'touchend':
coordinate.end.y = event.changedTouches[0].clientY;
var count = Math.floor((that.offset[index] + (coordinate.start.y - coordinate.end.y))/liHeight + 0.5)
count = count < 0 ? 0 : Math.min(count, target.childNodes.length - 1);
var temp = that.offset[index];
that.offset[index] = count < 0 ? 0 : Math.min(count * liHeight,target.offsetHeight - 5 * liHeight)
Util.setTransform(target, -that.offset[index]);
coordinate.end.status = true;
that.selectIndex.length = index + 1;
that.selectIndex[index] = count;
that.selectItem(that.getData(that.selectIndex),count,index)
break;
}
},false)
});
that.target.addEventListener('touchstart',function(event){
(event || window.event).preventDefault();
//记录旧结果,用于取消恢复
that.oldResult = that.result.slice(0);
that.show();
});
// 用click事件代替touchstart防止点透
Util.getEle(that.container,'.mp-cancel').addEventListener('click',function(){
that.hide();
//恢复旧的结果
that.update({
value: that.oldResult,
valueKey: that.textKey
});
Util.isFunc(that.cancel) && that.cancel();
},false);
Util.getEle(that.container,'.mp-confirm').addEventListener('click',function(){
if(that.lock) return;
var value = that.fillResult();
that.hide();
Util.isFunc(that.confirm) && that.confirm(value, that.result);
});
}
}
if (typeof module !== 'undefined' && typeof exports === 'object') {
module.exports = Picker;
} else if (typeof define === 'function' && (define.amd || define.cmd)) {
define(function() {
return Picker; });
} else {
global.Picker = Picker;
}
})(this);
html,body,div,li,ul {
padding: 0; margin: 0;}
body{
position: relative;}
li,ul {
list-style: none;}
.mp-body {
overflow: hidden;
}
.mp-mask {
position: fixed;
left:0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,.4);
/* display: none; */
visibility: hidden;
overflow: hidden;
}
.mp-shadowup,.mp-shadowdown {
height: 5em;
width: 100%;
position: absolute;
left: 0;
z-index: 50;
}
.mp-shadowup {
top: -1px;
background:-webkit-linear-gradient(to bottom, #FFF, rgba(255, 255, 255, .3));
background:linear-gradient(to bottom, #FFF, rgba(255, 255, 255, .3));
pointer-events: none;
}
.mp-shadowdown {
bottom: 0;
background: -webkit-linear-gradient(to top, #FFF, rgba(255,255,255,.3));
background: linear-gradient(to top, #FFF, rgba(255,255,255,.3));
pointer-events: none;
}
.mp-line {
position: absolute;
top: 5em;
left: 0;
width: 100%;
height: 2.5em;
border-top: 1px solid #acacac;
border-bottom: 1px solid #acacac;
}
.mp-container {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: #FFF;
font-size: 16px;
-webkit-transition: transform .25s;
-webkit-transform: translate3d(0,100%,0);
transition: transform .25s;
transform: translate3d(0,100%,0);
}
.mp-header {
background: #e2e2e2;
color: #249ff1;
line-height: 2.5em;
}
.mp-cancel {
padding-left: 1em;
}
.mp-confirm {
float: right;
padding-right: 1em;
}
.mp-confirm.disabled {
opacity: .3;
}
.mp-content {
position: relative;
height: 12.5em;
}
.mp-box {
height: 12.5em;
overflow: hidden;
}
.mp-box:after {
display: table;
height: 0;
clear: both;
content: '';
}
.mp-list-wrap ul {
position: relative;
padding: 5em 0;
-webkit-transition: transform .1s ease-out;
transition: transform .1s ease-out;
}
.mp-list-wrap ul:after {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 55;
content: '';
}
.mp-list-wrap li {
line-height: 2.5em;
font-size: 1em;
text-align: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.mp-list-wrap {
float: left;
height: 12.5em;
overflow: hidden;
font-size: 16px;
-webkit-transition: width .2s;
transition: width .2s;
}
<input type="text" id="cardWord" value="" placeholder="选择祝福语"/>
const Picker = require("@/picker/mobile-picker.js");
let fruit = ['新春快乐,虎年大吉!', '万事顺意,虎气冲天!', '好运连连,虎气生财!', '身体健康,虎虎生威!'
, '阖家欢乐,虎年顺意!', '喜气盈门,虎年快乐!'];
new Picker({
target: "#cardWord",
data: fruit,
value: '新春快乐,虎年大吉!',
});
let word = $("#cardWord").val();
//获取选中的值
边栏推荐
- Lxml web page capture the most complete strategy
- Day01 job
- Number of consecutive subarrays with leetcode/ and K
- Ciscn 2022 central China Misc
- Introduction to shared data center agent
- leetcode/乘积小于K 的连续子数组的个数
- StoneDB 邀请您参与开源社区月会!
- How to deal with the DDoS attack on the game server and how to defend it?
- 【流放之路-第五章】
- [the road of Exile - Chapter III]
猜你喜欢
![[the road of Exile - Chapter 6]](/img/cd/408118f43dbda2e6367b328a1c20fc.png)
[the road of Exile - Chapter 6]

知道创宇上榜CCSIP 2022全景图多个领域
![[the road of Exile - Chapter 4]](/img/76/e1e249ddb2f963abb5d2b617a5f178.png)
[the road of Exile - Chapter 4]

Ciscn 2022 central China Misc

Minimalist thrift+consumer

E-commerce keyword research helps data collection

覆盖接入2w+交通监测设备,EMQ为深圳市打造交通全要素数字化新引擎

【流放之路-第三章】

Top network security prediction: nearly one-third of countries will regulate blackmail software response within three years
![[golang] use select {}](/img/30/fa593ec682a40c47689c1fd88f9b83.png)
[golang] use select {}
随机推荐
TDA75610-I2C-模拟功放I2C地址的确定
leetcode/乘积小于K 的连续子数组的个数
Leetcode/0 and 1 consecutive subarrays with the same number
How to crawl web pages with playwright?
使用本地缓存+全局缓存实现小型系统用户权限管理
The solution of reducing the sharpness of pictures after inserting into word documents
[7.21-26] code source - [good sequence] [social circle] [namonamo]
Event express | Apache Doris Performance Optimization Practice Series live broadcast course is open at the beginning. You are cordially invited to participate!
The basic concept of transaction and the implementation principle of MySQL transaction
【流放之路-第六章】
What is the function of data parsing?
Code reading - ten C open source projects
【流放之路-第四章】
Random talk on distributed development
Planning mathematics final simulation exam I
Planning mathematics final exam simulation II
基于 ICA 与 DL 的语音信号盲分离
Data platform data access practice
九天后我们一起,聚焦音视频、探秘技术新发展
数学建模——带相变材料的低温防护服御寒仿真模拟