123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- /*!
- * js模拟系统select v1.0
- * http://www.cnblogs.com/typeof/
- *
- * 主流浏览器对html的select元素渲染都不一样,IE系列(6, 7, 8)也不一样,
- * firefox,chrome,safari,opera 渲染和事件处理也稍有差异
- * 该脚本解决了在不同浏览器下渲染和事件响应不一致的问题,对系统select是完全
- * 意义上的替换。v1.0版本只支持单个select选择即不支持二级或者三级联动且不支持系统select的onchange事件。
- * 该版本支持模拟select选择的数据和系统select选中数据的同步,不影响form表单的提交
- *
- * 如果page上select有的不想通过该脚本替换,只想维持系统select,可以在相应的select元素添加自定义属性data-enabled="true",
- * 否则可以在想要通过该脚本替换的select元素上添加自定义属性data-enabled="false"或者不加,会默认为这个select需要
- * 通过该脚本进行替换
- *
- * 日期:2012-11-07 15:38
- */
- (function(squid) {
- function JSelect() {
- this.init()
- }
- JSelect.prototype = {
- constructor: JSelect,
- init: function(context) {
- //获取指定上下文所有select元素
- var elems = squid.getElementsByTagName('select', context)
- this.globalEvent()
- this.initView(elems)
- },
- initView: function(elems) {
- var i = 0,
- elem,
- length = elems.length,
- enabled;
- for(; i < length; i++) {
- elem = elems[i]
- enabled = elem.getAttribute('data-enabled')
- //使用系统select
- if(!enabled || enabled === 'true')
- continue
- if(squid.isVisible(elem))
- elem.style.display = 'none'
-
- this.create(elem)
- }
- },
- create: function(elem) {
- var data = [],
- i = 0,
- length,
- option,
- options,
- value,
- text,
- obj,
- lis,
- ul,
- _default,
- icon,
- selectedText,
- selectedValue,
- div,
- wrapper,
- position,
- left,
- top,
- cssText;
- options = elem.getElementsByTagName('option')
- length = options.length
- for(; i < length; i++) {
- option = options[i]
- value = option.value
- text = option.innerText || option.textContent
-
- obj = {
- value: value,
- text: text
- }
- if(option.selected) {
- selectedValue = value
- selectedText = text
- obj['selected'] = true
- }
- data.push(obj)
- }
- lis = this.render(this.tmpl, data)
- ul = '<ul class="select-item">' + lis + '</ul>'
- //
- div = document.createElement('span')
- div.style.display = 'none'
- div.className = 'select-wrapper'
- //已选元素
- _default = document.createElement('span')
- _default.className = 'select-default unselectable'
- _default.unselectable = 'on'
- //让div元素能够获取焦点
- _default.setAttribute('tabindex', '1')
- _default.setAttribute('data-value', selectedValue)
- _default.setAttribute('hidefocus', true)
- _default.innerHTML = selectedText
- div.appendChild(_default)
- //选择icon
- icon = document.createElement('i')
- icon.className = 'select-icon'
- div.appendChild(icon)
- //下拉列表
- wrapper = document.createElement('span')
- wrapper.className = 'select-list hide'
- wrapper.innerHTML = ul
- //生成新的元素
- div.appendChild(wrapper)
- //插入到select元素后面
- elem.parentNode.insertBefore(div, null)
- //获取select元素left top值
- //先设置select显示,取完left, top值后重新隐藏
- elem.style.display = 'block'
- //事件绑定
- this.sysEvent(div)
- position = squid.position(elem)
- elem.style.display = 'none'
- left = position.left
- top = position.top
- cssText = ' display: inline-block;'
- div.style.cssText = cssText
- },
- globalEvent: function() {
- //document 添加click事件,用户处理每个jselect元素展开关闭
- var target,
- className,
- elem,
- wrapper,
- status,
- that = this;
- squid.on(document, 'click', function(event) {
- target = event.target,
- className = target.className;
- switch(className) {
- case 'select-icon':
- case 'select-default unselectable':
- elem = target.tagName.toLowerCase() === 'span' ? target : target.previousSibling
- wrapper = elem.nextSibling.nextSibling
-
- //firefox 鼠标右键会触发click事件
- //鼠标左键点击执行
- if(event.button === 0) {
- //初始化选中元素
- that.initSelected(elem)
- if(squid.isHidden(wrapper)) {
- status = 'inline-block'
- //关闭所有展开jselect
- that.closeSelect()
- }else{
- status = 'none'
- }
- wrapper.style.display = status
- elem.focus()
- }else if(event.button === 2){
- wrapper.style.display = 'none'
- }
- that.zIndex(wrapper)
- break
- case 'select-option':
- case 'select-option selected':
- if(event.button === 0) {
- that.fireSelected(target, target.parentNode.parentNode.previousSibling.previousSibling)
- wrapper.style.display = 'none'
- }
- break
- default:
- while(target && target.nodeType !== 9) {
- if(target.nodeType === 1) {
- if(target.className === 'select-wrapper') {
- return
- }
- }
- target = target.parentNode
- }
- that.closeSelect()
- break
- }
- })
- },
- sysEvent: function(elem) {
- var stand = elem.firstChild,
- dropdown = elem.lastChild,
- target,
- //firefox = 'MozBinding' in document.documentElement.style,
- chrome = /chrome/i.test(navigator.userAgent),
- keyup = chrome ? 'keypress' : 'keyup',
- that = this;
- squid.on(elem, 'mouseover', function(event) {
- if(!that.doScrolling) {
- target = event.target
- that.activate(target)
- }
- })
- squid.on(elem, 'mouseout', function(event) {
- if(!that.doScrolling) {
- target = event.target
- that.deactivate(target)
- }
- })
- squid.on(stand, 'keydown', function(event) {
- var keyCode = event.keyCode;
- switch(keyCode) {
- //回车选中
- case 13:
- that.enter(dropdown)
- break
- //向上键
- case 38:
- that.doScrolling = true
- that.up(dropdown)
- break
- //向下键
- case 40:
- that.doScrolling = true
- that.down(dropdown)
- break
- default:
- break
- }
- })
- squid.on(stand, keyup, function(event) {
- var keyCode = event.keyCode;
- switch(keyCode) {
- //回车选中
- case 13:
- that.doScrolling = false
- break
- //向上键
- case 38:
- that.doScrolling = false
- break
- //向下键
- case 40:
- that.doScrolling = false
- break
- default:
- break
- }
- })
- },
- zIndex: function(elem) {
- var index = 10,
- cur = elem.parentNode.parentNode,
- next = squid.next(cur);
-
- if(next) {
- cur.style.zIndex = index
- next.style.zIndex = --index
- }
- },
- initSelected: function(elem) {
- var curText = elem.innerText || elem.textContent,
- curValue = elem.getAttribute('data-value'),
- wrapper = elem.nextSibling.nextSibling,
- n = wrapper.firstChild.firstChild,
- text,
- value,
- dir,
- min = 0,
- max,
- hidden = false;
- for(; n; n = n.nextSibling) {
- text = n.innerText || n.textContent
- value = n.getAttribute('data-value')
- if(curText === text && curValue === value) {
- //显示已选中元素
- if(squid.isHidden(wrapper)) {
- wrapper.style.display = 'block'
- hidden = true
- }
- max = wrapper.scrollHeight
- if(n.offsetTop > (max / 2)) {
- if(wrapper.clientHeight + wrapper.scrollTop === max)
- dir = 'up'
- else
- dir = 'down'
- }else{
- if(wrapper.scrollTop === min)
- dir = 'down'
- else
- dir = 'up'
- }
- this.inView(n, wrapper, dir)
- if(hidden)
- wrapper.style.display = 'none'
- this.activate(n)
- break
- }
- }
- },
- activate: function(elem) {
- var tagName = (elem.tagName || '').toLowerCase(),
- className = elem.className,
- parent = elem.parentNode,
- first = parent.firstChild,
- last = parent.lastChild;
- switch(tagName) {
- case 'li':
- //li.select-option 元素
- if(!~className.indexOf('selected') && (elem !== first || elem !== last)) {
- this.deactivate(elem)
- elem.className = className + ' selected'
- }
- break
- default:
- break
- }
- },
- deactivate: function(elem) {
- var tagName = (elem.tagName || '').toLowerCase(),
- className = (' ' + elem.className + ' ').replace(/[\n\r\t]/, '');
- switch(tagName) {
- case 'li':
- //li.select-option 元素
- var i = 0,
- lis = squid.siblings(elem),
- length = lis.length,
- cur;
- for(; i < length; i++) {
- cur = lis[i]
- cur.className = squid.trim(className.replace(' selected ', ''))
- }
- break
- default:
- break
- }
- },
- fireSelected: function(elem, s) {
- var text = elem.innerText || elem.textContent,
- value = elem.getAttribute('data-value'),
- r;
- s.setAttribute('data-value', value)
- if(s.innerText)
- s.innerText = text
- else
- s.textContent = text
- //触发系统select选中,用于form表单提交
- r = s.parentNode.previousSibling.previousSibling
- r.value = value
- r.setAttribute('data-text', text)
- },
- closeSelect: function() {
- var elems = squid.getElementsByClassName('select-list'),
- i = 0,
- length = elems.length,
- elem;
- for(; i < length; i++) {
- elem = elems[i]
- if(squid.isVisible(elem))
- elem.style.display = 'none'
- }
- },
- up: function(elem) {
- var ul = elem.firstChild,
- lis = ul.childNodes,
- li = this.getSelectedIndex(lis),
- cur,
- i = li.index;
-
- if(i > 0) {
- i--
- cur = lis[i]
- //判断元素是否in view
- this.inView(cur, elem, 'up')
- this.activate(cur)
- this.fireSelected(cur, elem.previousSibling.previousSibling)
- }
- },
- down: function(elem) {
- var ul = elem.firstChild,
- lis = ul.childNodes,
- li = this.getSelectedIndex(lis),
- cur,
- i = li.index;
- if(i < lis.length - 1) {
- i++
- cur = lis[i]
- //判断元素是否in view
- this.inView(cur, elem, 'down')
- this.activate(cur)
- this.fireSelected(cur, elem.previousSibling.previousSibling)
- }
- },
- enter: function(elem) {
- var ul = elem.firstChild,
- lis = ul.childNodes,
- li,
- i,
- cur;
- li = this.getSelectedIndex(lis)
- i = li.index
- cur = lis[i]
- this.fireSelected(cur, elem.previousSibling.previousSibling)
- this.closeSelect()
- },
- getSelectedIndex: function(elems) {
- var i = 0,
- length = elems.length,
- elem;
-
- for(; i < length; i++) {
- elem = elems[i]
- if(~elem.className.indexOf('selected')) {
- return {
- index: i
- }
- }
- }
- return {
- index: -1
- }
- },
- inView: function(elem, wrapper, dir) {
- var scrollTop = wrapper.scrollTop,
- offsetTop = elem.offsetTop,
- top;
- if(dir === 'up') {
- if(offsetTop === 0) {
- wrapper.scrollTop = offsetTop;
- }else if(offsetTop < scrollTop) {
- top = offsetTop - scrollTop
- this.scrollInView(wrapper, top)
- }
- }else{
- var clientHeight = wrapper.clientHeight;
-
- if(offsetTop + elem.offsetHeight === wrapper.scrollHeight) {
- wrapper.scrollTop = wrapper.scrollHeight - wrapper.clientHeight
- }else if(offsetTop + elem.offsetHeight > clientHeight + scrollTop) {
- top = (offsetTop + elem.offsetHeight) - (scrollTop + clientHeight)
- this.scrollInView(wrapper, top)
- }
- }
- },
- scrollInView: function(elem, top) {
- setTimeout(function() {
- elem.scrollTop += top
- }, 10)
- },
- doScrolling: false,
- render: function(tmpl, data) {
- var i = 0,
- cur,
- length = data.length,
- prop,
- value,
- item,
- r = [];
- for(; i < length; i++) {
- cur = data[i]
- item = tmpl.replace(/\{\{\w+\}\}/g, function(a) {
- prop = a.replace(/[\{\}]+/g, '')
- value = cur[prop] || ''
- if(prop === 'class') {
- value += 'select-option'
- if(cur.selected) {
- value += ' selected'
- }
- }
-
- return value
- })
- r.push(item)
- }
- return r.join('')
- },
- tmpl: '<li class="{{class}}" data-value="{{value}}">{{text}}</li>'
- }
- squid.swing.jselect = function() {
- return new JSelect()
- }
- })(squid);
|