欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript模擬select,jselect的方法實現(xiàn)

 更新時間:2012年11月08日 15:46:58   作者:  
由于主流瀏覽器對select元素渲染不同,所以在每種瀏覽器下顯示也不一樣,最主要的是默認情況下UI太粗糙,即使通過css加以美化也不能達到很美觀的效果
由于主流瀏覽器對select元素渲染不同,所以在每種瀏覽器下顯示也不一樣,最主要的是默認情況下UI太粗糙,即使通過css加以美化也不能達到很美觀的效果。這對于我們這些專注于UX的前端開發(fā)人員是無法容忍的。于是在項目不太忙的時候,就計劃寫一個模擬的select控件出來。接下來就把實現(xiàn)的細節(jié)、遇到的問題以及如何使用和大家分享一下。
1. 實現(xiàn)細節(jié)
init: function(context) {
//獲取指定上下文所有select元素
var elems = squid.getElementsByTagName('select', context)
this.globalEvent()
this.initView(elems)
}
在一個用戶注冊的應用場景,有多個select元素。模擬的select控件(以下簡稱jselect)初始化方法會獲取頁面上所有select元素,然后綁定全局事件globalEvent,初始化頁面顯示initView。globalEvent方法如下:
復制代碼 代碼如下:

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() === 'div' ? target : target.previousSibling
wrapper = elem.nextSibling.nextSibling

//firefox 鼠標右鍵會觸發(fā)click事件
//鼠標左鍵點擊執(zhí)行
if(event.button === 0) {
//初始化選中元素
that.initSelected(elem)
if(squid.isHidden(wrapper)) {
status = '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
}
})
}

globalEvent實現(xiàn)了在document綁定click事件,然后在頁面上觸發(fā)點擊事件的時候通過事件代理來判斷當前點擊元素是否是需要進行處理的目標元素,判斷條件是通過元素的class,代碼中語句的分支分別是:展開當前點擊的jselect元素下拉、選中點擊列表項、判斷是否需要關閉jselect。

initView方法如下:
復制代碼 代碼如下:

initView: function(elems) {
var i = 0,
elem,
length = elems.length,
enabled;

for(; i < length; i++) {
elem = elems[i]
enabled = elem.getAttribute('data-enabled')
//使用系統(tǒng)select
if(!enabled || enabled === 'true')
continue
if(squid.isVisible(elem))
elem.style.display = 'none'

this.create(elem)
}
}

initView實現(xiàn)了將需要使用jselect替換的select元素先隱藏然后調用create方法,生成單個jselect的整體結構并插入到頁面并替代默認select位置。

create方法如下:
復制代碼 代碼如下:

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('div')
div.style.display = 'none'
div.className = 'select-wrapper'
//已選元素
_default = document.createElement('div')
_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('span')
icon.className = 'select-icon'
div.appendChild(icon)
//下拉列表
wrapper = document.createElement('div')
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 = 'left: ' + left + 'px; top: ' + top + 'px; display: block;'
div.style.cssText = cssText
}

create方法實現(xiàn)了將系統(tǒng)select數(shù)據(jù)拷貝到jselect下拉列表,jselect的層級關系是最外層有一個class為select-wrapper的元素包裹,里面有class為select-default的元素用于存放已選的元素,class為select-icon的元素用戶告訴用戶這是一個下拉列表,class為select-list的div元素里面包含了一個ul元素里面是從系統(tǒng)select拷貝的option的文本和值分別存放在li元素的文本和data-value屬性。sysEvent方法是為jselect添加點擊展開關閉下拉列表事件以及鍵盤上下選擇下拉元素回車選中下拉元素事件。squid.position方法用于獲取系統(tǒng)select元素相對于其offsetParent的位置,這里與獲取系統(tǒng)select元素的offset是有區(qū)別。其實就是獲取自己的offset得到top,left值然后分別減去offsetParent獲取的offset的top,left值。最后是把jselect插入到系統(tǒng)select元素后面,顯示到頁面。

jselect創(chuàng)建的基本流程就是上面描述的這樣,剩下就是細節(jié)地方的實現(xiàn),比如說:點擊展開下拉顯示上次已選擇的元素,具體實現(xiàn)該功能的是initSelected方法如下
復制代碼 代碼如下:

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
}
}
}

該方法接收class為select-default的div元素即用于存放用戶已選擇內容的元素,具體實現(xiàn)方式是先遍歷所有選項獲取class有selected的li元素,通過activate方法標示為當前已選中的元素。這里有一個需要計算的地方,就是每次展開下拉列表都要將已選中的元素滾動到頁面可視區(qū)。因為有可能下來列表內容很多,但是下拉列表的外層select-list會有一個最大的高度,超過最大高度會出現(xiàn)滾動條,默認不做計算的話有可能已選中的元素會在滾動條下面或者是滾動條上面,所以需要通過計算來重置容器滾動條的位置。具體是已選中內容顯示到滾動條的上面還是下面需要根據(jù)已選中元素的offsetTop值是否大于外層容器select-list的實際高度一半,把已選中元素顯示到可視區(qū)的方式是inView方法。inView方法如下
復制代碼 代碼如下:

inView: function(elem, wrapper, dir) {
var scrollTop = wrapper.scrollTop,
//已選中元素offsetTop
offsetTop = elem.offsetTop,
top;

if(dir === 'up') {
if(offsetTop === 0) {
//滾動條置頂
wrapper.scrollTop = offsetTop;
}else if(offsetTop < scrollTop) {
top = offsetTop - scrollTop
//滾動條滾動到top值
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)
}
}
}

inView方法需要判斷是向上滾動還是向下滾動,scrollInView方法代碼很簡單就是把下拉列表外層容器的scrollTop設置為指定的值。方法實現(xiàn)如下
復制代碼 代碼如下:

scrollInView: function(elem, top) {
setTimeout(function() {
elem.scrollTop += top
}, 10)
}

這個方法實現(xiàn)放到了setTimeout里面做了一個延遲添加到javascript執(zhí)行隊列里面,主要解決的是IE8下展開下拉列表滾動條會最終滾動到頂部,忽略代碼設置的scrollTop(從表現(xiàn)上來看好像對scrollTop的設置也能生效,但是最后會重置滾動條到頂部,不知道IE8為什么會有這個問題。),不能把已選中的元素顯示到可視區(qū)范圍,其他瀏覽器下不會有這個問題。
整個的實現(xiàn)細節(jié)大致就這么多,鍵盤上下鍵回車鍵,關閉下拉列表邏輯都很簡單。
遇到的問題
如何讓div獲取焦點來響應鍵盤keydown, keyup, keypress事件,到谷歌(非常時期谷歌都不好用了,沒辦法誰讓這是咱的特色呢)查找一些資料最后發(fā)現(xiàn)需要為div元素設置tabindex屬性,這樣就可以讓div元素獲取焦點,來響應用戶的操作。因為瀏覽器在默認情況下雙擊或者是點擊太頻繁的話會選中當前區(qū)域,為了取消這個默認操作給用戶一個好的體驗需要為div元素添加一個屬性unselectable,不過這個屬性只能適用于IE瀏覽器,其他瀏覽器下可以通過添加一個class名字是unselectable來避免這個問題。其他的問題都是邏輯上的控制,還有一些位置的計算了,這里就不再說了。
使用方法
首先是在頁面模板把希望通過jselect替換的元素隱藏或者不做任何處理,默認情況下jselect會獲取頁面所有select依次替換,如果不希望jselect替換的select元素
需要添加自定義屬性data-enabled="true"。當然添加data-enabled="false"和沒有這個自定義屬性一樣都會被jselect替換。在使用的過程中可能對于布局結構比較復雜的頁面還會有其他的問題,因為我測試的頁面結構很簡單,所以可能沒有測試出來。
使用jselect需要先引入squid.js,然后引入jselect-1.0.js, jselect-1.0.css文件,在需要調用jselect的地方通過如下的調用方式來初始化jselect:squid.swing.jselect();
注:jselect源碼以及demo可以通過這里下載

相關文章

  • 兼容ie ff div 層 打開+關閉+ 拖動+遮罩+移動+動畫改變高寬

    兼容ie ff div 層 打開+關閉+ 拖動+遮罩+移動+動畫改變高寬

    div層 打開+關閉+ 拖動+遮罩+移動+動畫改變高寬的實例js代碼
    2008-07-07
  • JavaScrip數(shù)組刪除特定元素的幾種方法總結

    JavaScrip數(shù)組刪除特定元素的幾種方法總結

    從js數(shù)組中刪除指定元素是我們每個人都遇到的問題,網(wǎng)上這方面的資料也很多,但有的時間過于久遠,有的內容不夠全面,所以自己來整理下,這篇文章主要給大家總結介紹了關于JavaScrip數(shù)組刪除特定元素的多種方法,需要的朋友可以參考下。
    2017-09-09
  • TypeScript中函數(shù)重載寫法

    TypeScript中函數(shù)重載寫法

    這篇文章主要介紹了TypeScript中函數(shù)重載寫法,TypeScript 提供了函數(shù)重載功能,下面文章圍繞TypeScript函數(shù)重載續(xù)航管資料展開內容,具有一定得參考價值,需要的朋友可以參考一下
    2021-12-12
  • javascript使用activex控件的代碼

    javascript使用activex控件的代碼

    最近公司項目用到了avtivex控件。以前從來沒有用過。我把最近到處找到的使用方法整理一下。
    2011-01-01
  • js 提取class相同的節(jié)點集合

    js 提取class相同的節(jié)點集合

    可以獲取網(wǎng)頁中相同class的節(jié)點的腳本,然后就可以統(tǒng)一做一些調整。
    2008-12-12
  • js時間轉換毫秒的實例代碼

    js時間轉換毫秒的實例代碼

    在本篇文章里小編給大家整理的是關于js時間轉換毫秒的實例代碼以及相關知識點,需要的朋友們可以學習下。
    2019-08-08
  • GRID拖拽行的實例代碼

    GRID拖拽行的實例代碼

    這篇文章介紹了GRID拖拽行的實例代碼,有需要的朋友可以參考一下
    2013-07-07
  • javascript每日必學之繼承

    javascript每日必學之繼承

    javascript每日必學之繼承,介紹了有關繼承的相關內容,感興趣的小伙伴們可以參考一下
    2016-02-02
  • javascript基礎語法學習筆記

    javascript基礎語法學習筆記

    這篇文章主要為大家分享了javascript基礎語法學習筆記,幫助大家夯實javascript基礎知識,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 微信小程序開發(fā)搖一搖功能

    微信小程序開發(fā)搖一搖功能

    這篇文章主要介紹了微信小程序搖一搖功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11

最新評論