当前位置:网站首页>mobile-picker.js
mobile-picker.js
2022-07-29 02:09: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) {
// Damping operation
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;// Index of the current selector
this.target = config.target instanceof HTMLElement ? config.target : typeof config.target === "string" ? Util.getEle(document,config.target) : null;// Trigger selector dom Elements
this.data = config.data || [];// The data that needs to be displayed
this.value = config.value ? (Util.isArray(config.value) ? config.value : config.value.split(',')) : [];// Selector default
this.childKey = config.childKey || 'child';// Sub data index name
this.valueKey = config.valueKey || 'value';// Used to index the initial value key
this.textKey = config.textKey || 'value';// For display key
this.autoFill = !(config.autoFill === false);// Select whether to fill in the target element after confirmation
this.confirm = config.confirm;// Determine the selected callback
this.cancel = config.cancel;// Cancel callback
this.initCallback = config.initCallback;// Instantiate the completed callback
this.select = config.select;// Callback after single list selection
this.lock = config.lock === true;// Lock the OK button , Used to wait for use when loading asynchronously
this.className = config.className || '';// Customized class name
this.init();
}
Picker.prototype = {
constructor: Picker,
init: function(){
this.initResult();
var html = '<div class="mp-container"><div class="mp-header"><span class="mp-cancel"> Cancel </span><span class="mp-confirm'+(this.lock ? ' disabled' : '')+'"> determine </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')// For containers containing rolling elements
this.createScroll(this.data);// The core approach : Create scrolling elements
this.value = [];
this.bindEvent();// The binding event
this.finisInit();
},
initResult: function(config){
this.scrollCount = 0;// Number of rendered data layers
this.selectIndex = [];// Index set selected at each level
this.result = [];// The final result of the selector
this.offset = [];// Set of offsets scrolled at each level
},
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){
// Get the data set
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>';
// There are default values when initializing , The current value should be selected , otherwise index Will be for 0, That is, select the first
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);// Select and create the next level selector
},
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: data , Selected index , At present scroll The index of
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){
// There are subelements
if(that.scrollCount < scrollIndex + 2){
// If last time ul The number is less than the number currently needed , Create a new ul
that.createScroll(data[index][that.childKey]);
} else {
that.updateList(scrollIndex + 1, data[index][that.childKey]);
}
} else {
// Indicates that the current number of scrollers is more than required , Remove the extra
for ( var j = oldScrollCount - 1, len = that.selectIndex.length; j >= len; j-- ) {
// Remove redundant ul
that.removeScroll(j);
}
}
// this.scrollIndex = this.offset.length = this.selectIndex.length;
this.offset.length = this.selectIndex.length;
this.calcWidth();// Calculate the width of the rolling object
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){
// Has slid to the top
Util.setTransform(target, Util.damping(-os));
} else if(os <= scrollHeight){
Util.setTransform(target, -os);
} else {
// More than the overall height
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();
// Record old results , Used to cancel recovery
that.oldResult = that.result.slice(0);
that.show();
});
// use click Event replacement touchstart Prevent penetration
Util.getEle(that.container,'.mp-cancel').addEventListener('click',function(){
that.hide();
// Restore the old results
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=" Choose blessings "/>
const Picker = require("@/picker/mobile-picker.js");
let fruit = [' Happy New Year , Good luck in the year of the tiger !', ' Everything goes well , Tiger gas soars into the sky !', ' Good luck , Tiger gas makes money !', ' A healthy body , A tiger makes a mighty tiger !'
, ' A happy family , The year of the tiger is going well !', ' Joy filled the door , Happy year of the tiger !'];
new Picker({
target: "#cardWord",
data: fruit,
value: ' Happy New Year , Good luck in the year of the tiger !',
});
let word = $("#cardWord").val();
// Gets the selected value
边栏推荐
- [circuit design] open collector OC output of triode
- Control the pop-up window and no pop-up window of the input box
- 分布式开发漫谈
- Qt 内存管理小技巧
- Comprehensive explanation of "search engine crawl"
- Mathematical modeling -- heat conduction of subgrade on Permafrost
- The growth path of embedded engineers
- How to find the right agent type? Multi angle analysis for you!
- Process -- user address space and kernel address space
- The solution of reducing the sharpness of pictures after inserting into word documents
猜你喜欢

Mobile communication -- simulation model of error control system based on convolutional code

Mathematical modeling -- Optimization of picking in warehouse

【ONE·Data || 链式二叉树】

Basic working principle and LTSpice simulation of 6T SRAM

Monadic linear function perceptron: Rosenblatt perceptron

一文读懂Okaleido Tiger近期动态,挖掘背后价值与潜力

Mathematical modeling -- red wine quality classification

Use POI to export excel file, image URL to export file, image and excel file to export compressed package
![[circuit design] peak voltage and surge current](/img/d5/45bf9a79171ff9b8d7ba4c771b340c.png)
[circuit design] peak voltage and surge current

Why can't Bi software do correlation analysis
随机推荐
Resolve the conflict with vetur when using eslint, resulting in double quotation marks and comma at the end of saving
Lm13 morphological quantification momentum period analysis
Lxml web page capture the most complete strategy
Thirty years of MPEG audio coding
Number of consecutive subarrays with leetcode/ and K
The growth path of embedded engineers
[MySQL] SQL aliases the table
Stonedb invites you to participate in the open source community monthly meeting!
Leetcode/0 and 1 consecutive subarrays with the same number
给LaTeX公式添加优美的注解;日更『数据科学』面试题集锦;大学生『计算机』自学指南;个人防火墙;前沿资料/论文 | ShowMeAI资讯日报
Golang run times undefined error [resolved]
Add graceful annotations to latex formula; "Data science" interview questions collection of RI Gai; College Students' computer self-study guide; Personal firewall; Cutting edge materials / papers | sh
Try to understand the essence of low code platform design from another angle
druid. io kill -9 index_ Realtime traceability task
Leetcode 242. valid anagram
在Qt中如何编写插件,加载插件和卸载插件
How to write, load and unload plug-ins in QT
Qt 内存管理小技巧
Mathematical modeling -- heat conduction of subgrade on Permafrost
基于 ICA 与 DL 的语音信号盲分离