UNPKG

@frontend_worker/search-selector

Version:

《远程搜索+单选》组件区别于element-ui或iview组件库的select远程搜索, ①将头部显示的值和下拉选项显示的值独立开来, ②避免远程加载时头部默认值显示异常, ③支持插槽自定义 ④将搜索框值放置于下拉弹框里面

436 lines (386 loc) 13.3 kB
import Vue from 'vue'; const isServer = Vue.prototype.$isServer; export const deepCopy = obj => { return JSON.parse(JSON.stringify(obj)); }; // 判断是否是对象 export function isObject (obj) { return typeof(obj) === 'object'; } // js对象深度比较 全相等 export function isEqual (obj1, obj2) { // 如果传入的不是对象,那就直接比较并且返回 if (!isObject(obj1) || !isObject(obj2)) { return obj1 === obj2; } // 如果传入的两个对象为同一个,那直接返回true if (obj1 === obj2) { return true; } // 如果两个对象的key的长度不一致,返回false const obj1Keys = Object.keys(obj1); const obj2Keys = Object.keys(obj2); if (obj1Keys.length !== obj2Keys.length) { return false; } // 递归比较 for (let key in obj1) { const res = isEqual(obj1[key], obj2[key]); if (!res) { return false; } } return true; } // 判断参数是否是其中之一 export function oneOf (value, validList) { for (let i = 0; i < validList.length; i++) { if (value === validList[i]) { return true; } } return false; } const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; const MOZ_HACK_REGEXP = /^moz([A-Z])/; function camelCase(name) { return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { return offset ? letter.toUpperCase() : letter; }).replace(MOZ_HACK_REGEXP, 'Moz$1'); } // getStyle export function getStyle (element, styleName) { if (!element || !styleName) return null; styleName = camelCase(styleName); if (styleName === 'float') { styleName = 'cssFloat'; } try { const computed = document.defaultView.getComputedStyle(element, ''); return element.style[styleName] || computed ? computed[styleName] : null; } catch(e) { return element.style[styleName]; } } // firstUpperCase function firstUpperCase(str) { return str.toString()[0].toUpperCase() + str.toString().slice(1); } export {firstUpperCase}; // Warn export function warnProp(component, prop, correctType, wrongType) { correctType = firstUpperCase(correctType); wrongType = firstUpperCase(wrongType); console.error(`[iView warn]: Invalid prop: type check failed for prop ${prop}. Expected ${correctType}, got ${wrongType}. (found in component: ${component})`); // eslint-disable-line } export function typeOf(obj) { const toString = Object.prototype.toString; const map = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]' : 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Undefined]': 'undefined', '[object Null]' : 'null', '[object Object]' : 'object' }; return map[toString.call(obj)]; } // deepCopy // function deepCopy(data) { // const t = typeOf(data); // let o; // if (t === 'array') { // o = []; // } else if ( t === 'object') { // o = {}; // } else { // return data; // } // if (t === 'array') { // for (let i = 0; i < data.length; i++) { // o.push(deepCopy(data[i])); // } // } else if ( t === 'object') { // for (let i in data) { // o[i] = deepCopy(data[i]); // } // } // return o; // } // export {deepCopy}; // scrollTop animation export function scrollTop(el, from = 0, to, duration = 500, endCallback) { if (!window.requestAnimationFrame) { window.requestAnimationFrame = ( window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { return window.setTimeout(callback, 1000/60); } ); } const difference = Math.abs(from - to); const step = Math.ceil(difference / duration * 50); function scroll(start, end, step) { if (start === end) { endCallback && endCallback(); return; } let d = (start + step > end) ? end : start + step; if (start > end) { d = (start - step < end) ? end : start - step; } if (el === window) { window.scrollTo(d, d); } else { el.scrollTop = d; } window.requestAnimationFrame(() => scroll(d, end, step)); } scroll(from, to, step); } // Find components upward function findComponentUpward (context, componentName, componentNames) { if (typeof componentName === 'string') { componentNames = [componentName]; } else { componentNames = componentName; } let parent = context.$parent; let name = parent.$options.name; while (parent && (!name || componentNames.indexOf(name) < 0)) { parent = parent.$parent; if (parent) name = parent.$options.name; } return parent; } export {findComponentUpward}; // Find component downward export function findComponentDownward (context, componentName) { const childrens = context.$children; let children = null; if (childrens.length) { for (const child of childrens) { const name = child.$options.name; if (name === componentName) { children = child; break; } else { children = findComponentDownward(child, componentName); if (children) break; } } } return children; } // Find components downward export function findComponentsDownward (context, componentName) { return context.$children.reduce((components, child) => { if (child.$options.name === componentName) components.push(child); const foundChilds = findComponentsDownward(child, componentName); return components.concat(foundChilds); }, []); } // Find components upward export function findComponentsUpward (context, componentName) { let parents = []; const parent = context.$parent; if (parent) { if (parent.$options.name === componentName) parents.push(parent); return parents.concat(findComponentsUpward(parent, componentName)); } else { return []; } } // Find brothers components export function findBrothersComponents (context, componentName, exceptMe = true) { let res = context.$parent.$children.filter(item => { return item.$options.name === componentName; }); let index = res.findIndex(item => item._uid === context._uid); if (exceptMe) res.splice(index, 1); return res; } /* istanbul ignore next */ const trim = function(string) { return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, ''); }; /* istanbul ignore next */ export function hasClass(el, cls) { if (!el || !cls) return false; if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.'); if (el.classList) { return el.classList.contains(cls); } else { return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1; } } /* istanbul ignore next */ export function addClass(el, cls) { if (!el) return; let curClass = el.className; const classes = cls instanceof Array ? cls : (cls || '').split(' '); for (let i = 0, j = classes.length; i < j; i++) { const clsName = classes[i]; if (!clsName) continue; if (el.classList) { el.classList.add(clsName); } else { if (!hasClass(el, clsName)) { curClass += ' ' + clsName; } } } if (!el.classList) { el.className = curClass; } } /* istanbul ignore next */ export function removeClass(el, cls) { if (!el || !cls) return; const classes = cls.split(' '); let curClass = ' ' + el.className + ' '; for (let i = 0, j = classes.length; i < j; i++) { const clsName = classes[i]; if (!clsName) continue; if (el.classList) { el.classList.remove(clsName); } else { if (hasClass(el, clsName)) { curClass = curClass.replace(' ' + clsName + ' ', ' '); } } } if (!el.classList) { el.className = trim(curClass); } } export const dimensionMap = { xs: '480px', sm: '576px', md: '768px', lg: '992px', xl: '1200px', xxl: '1600px', }; export function setMatchMedia () { if (typeof window !== 'undefined') { const matchMediaPolyfill = mediaQuery => { return { media: mediaQuery, matches: false, on() {}, off() {}, }; }; window.matchMedia = window.matchMedia || matchMediaPolyfill; } } // 用于 select Cascader 计算 +n 的宽度 function getTagWidth(parent, classes, text, tagName = 'div') { const tag = document.createElement(tagName); addClass(tag, classes); tag.innerText=text; parent.appendChild(tag); const width = tag.getBoundingClientRect().width; parent.removeChild(tag); return width; } // 用于 select Cascader 计算 +n 的数量 // parent tag 的父元素 // total 总tag 数 // inputWidth 开启 filter input的width // moreTagClasses 未显示的标签数 export function getShowNum(parent, total, inputWidth, moreTagClasses) { const $tags = parent.querySelectorAll('.zz-tag') || []; const headWidth = parent.getBoundingClientRect().width; let showNum = total - $tags.length; // 倒序遍历所有标签 for(let i = $tags.length - 1; i >= 0;i--) { const { offsetLeft, offsetTop } = $tags[i]; // 判断标签是在第一行还是在其他行 if(offsetTop>10) { showNum++; }else { // 如果标签在第一行 // 获取 标签宽度 const tagWidth = $tags[i].getBoundingClientRect().width; // 获取 +n 的宽度 const moreTagWidth = showNum === 0 ? 0 : getTagWidth(parent, moreTagClasses, `+${showNum}`); // 标签宽度 + 标签左侧离边界距离 + moreTagWidth + 搜索input宽度 > select-head宽度,说明超出 if(tagWidth + offsetLeft + moreTagWidth + inputWidth > headWidth) { showNum++; } else { break; } } } return showNum; } export function isPlaceholderNeedToolTip(refNode, placeholderContent =''){ let inputNode = refNode; const { offsetWidth }= inputNode; const { paddingLeft, paddingRight } = window.getComputedStyle(inputNode); let targetDomStyle = { opacity: 0, fontSize: getStyle(inputNode, 'font-size'), fontFamily: getStyle(inputNode, 'font-family'), fontWeight: getStyle(inputNode, 'font-weight'), letterSpacing: getStyle(inputNode, 'letter-spacing') }; let node = document.createElement('span'); node.style.fontSize = targetDomStyle.fontSize; node.style.fontFamily = targetDomStyle.fontFamily; node.style.fontWeight = targetDomStyle.fontWeight; node.style.letterSpacing = targetDomStyle.letterSpacing; node.style.opacity =targetDomStyle.opacity; node.innerHTML = placeholderContent; document.body.appendChild(node); let rect = node.getBoundingClientRect(); const { width } = rect; document.body.removeChild(node); return width < offsetWidth - parseInt(paddingLeft)- parseInt(paddingRight); } export function IEVersion() { var useAgent = navigator.userAgent; var isIE = useAgent.indexOf('compatible'); var isEdge = useAgent.indexOf('Edge') > -1 && !isIE; var isIE11 = useAgent.indexOf('Trident') > -1 && useAgent.indexOf('rv:11.0') > -1; if(isIE) { var reIE = new RegExp('MSIE (\\d+\\.\\d+);'); reIE.test(useAgent); var fIEVersion = parseFloat(RegExp(['$1'])); if (fIEVersion === 7) { return 7; } else if (fIEVersion === 8) { return 8; } else if (fIEVersion === 9) { return 9; } else if (fIEVersion === 10) { return 10; } else { return 6; } } else if (isEdge) { return 'edge'; } else if (isIE11) { return 11; } else { return -1; } } export const sharpMatcherRegx = /#([^#]+)$/; export function isNumber(v) { return Object.prototype.toString.call(v) === '[object Number]'; } export function isExist(val) { return val !== null && val !== undefined; } export function getIntStyle(element, styleName) { return parseInt(getStyle(element, styleName)); }