>웹 프론트엔드 >JS 튜토리얼 >JavaScript는 select, jselect 메소드 구현_javascript 기술을 시뮬레이션합니다.

JavaScript는 select, jselect 메소드 구현_javascript 기술을 시뮬레이션합니다.

WBOY
WBOY원래의
2016-05-16 17:48:281222검색

주류 브라우저는 선택 요소를 다르게 렌더링하기 때문에 각 브라우저의 표시도 다릅니다. 가장 중요한 것은 기본적으로 UI가 너무 거칠고 CSS를 통해 아름답게 만들어도 매우 아름다운 효과를 얻을 수 없다는 것입니다. 이는 UX에 중점을 두는 우리 프론트엔드 개발자들에게는 참을 수 없는 일입니다. 그래서 프로젝트가 너무 바쁘지 않을 때 시뮬레이션된 선택 컨트롤을 작성할 계획입니다. 다음으로 구현 세부 사항, 발생한 문제 및 사용 방법을 공유하겠습니다.
1. 구현 세부정보
init: function(context) {
//지정된 컨텍스트의 모든 선택 요소 가져오기
var elems = squid.getElementsByTagName('select', context)
this.globalEvent()
this.initView(elems)
}
사용자 등록 애플리케이션 시나리오에는 여러 선택 요소가 있습니다. 시뮬레이션된 선택 컨트롤(이하 jselect) 초기화 방법은 페이지의 모든 선택 요소를 얻은 다음 전역 이벤트 globalEvent를 바인딩하고 페이지를 초기화하여 initView를 표시합니다. globalEvent 메서드는 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

globalEvent: function() {
//Document는 클릭 이벤트를 추가하고 사용자는 각 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 마우스 오른쪽 버튼을 누르면 클릭 이벤트가 발생합니다.
//마우스 왼쪽 버튼을 누르면 실행됩니다
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
기본값:
while(target && target.nodeType !== 9) {
if(target.nodeType == = 1) {
if(target.className === ' select-wrapper') {
return
}
}
target = target.parentNode
}
.closeSelect()
break
}
} )
}

globalEvent는 문서의 클릭 이벤트 바인딩을 구현한 다음 이벤트 프록시를 사용하여 현재 클릭된 요소는 페이지에서 클릭 이벤트가 트리거될 때 처리되어야 하는 대상 요소입니다. 판단 조건은 요소의 클래스를 기반으로 합니다. 코드의 명령문 분기는 현재 클릭된 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')
//시스템 선택 사용
if(!enabled || 활성화 === 'true')
continue
if(squid.isVisible(elem))
elem.style.display = 'none'

this.create(elem)
}
}

initView는 jselect로 교체해야 하는 select 요소를 숨긴 후 create 메소드를 호출하여 단일 jselect의 전체 구조를 생성하고 이를 페이지에 삽입하고 교체하는 메소드를 구현합니다. 기본 선택 위치.

생성 방법은 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

생성: function(elem) {
var data = [],
i = 0,
length,
option,
options,
value,
text,
obj,
lis,
ul,
_default,
icon,
selectedText,
selectedValue,
div,
wrapper,
위치,
왼쪽,
위쪽,
cssText;

options = elem.getElementsByTagName('option')
length = options.length
for(; i < length; i ) {
option = options[i]
값 = 옵션.값
텍스트 = 옵션.innerText || option.textContent

obj = {
값: 값,
텍스트: 텍스트
}
if(option.selected) {
selectedValue = 값
selectedText = text
obj['selected'] = true
}
data.push(obj)
}

lis = this.render(this.tmpl, data)
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(래퍼)
//插入到select 元素后면
elem.parentNode.insertBefore(div, null)
//获取select元素왼쪽 상단值
//先设置select显示,取完left, top值后중새隐藏
elem.style.display = 'block'
//事件绑정
this.sysEvent(div)
position = squid.position(elem)
elem.style.display = '없음'
왼쪽 = position.left
top = position.top
cssText = '왼쪽: '왼쪽'px; 상단: ' 상단 'px; 디스플레이: 블록;'
div.style.cssText = cssText
}

create 방법을 선택하세요.个클래스为선택 -래퍼의 모토 페이지, 페이지가 있는 클래스는 select-default의 모토 유형에 사용되는 클래스 선택 아이콘, 클래스의 선택 아이콘의 모토 탭 사용 또는 클래스 선택 목록의 div 모토 페이지에서 사용 가능합니다.了一个ul 元素里面是从系统select拷贝의 옵션에 있는 文本과 值分别存放에서 li 元素的文本과 data-value 속성입니다.及键盘上下选择下拉元素回车选中下拉오징어 위치 방법 사용 于获取系统select 켤레상호수 offset得到top,left值然后分别减去offsetParent获取的오프셋 상단, 왼쪽.细节地方的实现,比如说:点击 확장开下拉显示上次已选择的元素,具体实现该功能的是initSelectedmethod如下


复代代码 代码如下:
initSelected: function(elem) {
var curText = elem.innerText || elem.textContent,
curValue = elem.getAttribute('data-value'),
wrapper = elem.nextSibling.nextSibling,
n = Wrapper.firstChild.firstChild,
text,
값,
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 래퍼.scrollTop === max)
dir = 'up'
else
dir = 'down'
}else{
if(wrapper.scrollTop === min)
dir = 'down'
else
dir = 'up'
}
this.inView(n, 래퍼, dir)
if(hidden)
wrapper.style.display = 'none'
this.activate(n)
break
}
}
}


이 방법은 사용자가 선택한 콘텐츠를 저장하는 데 사용되는 select-default 클래스를 사용하여 div 요소를 수신합니다. 구체적인 구현 방법은 먼저 모든 옵션을 순회하여 선택한 클래스가 있는 li 요소를 얻은 다음 표시하는 것입니다. 현재 activate 메소드를 통해 선택되어 있습니다. 여기서 계산해야 할 것이 있습니다. 즉, 드롭다운 목록이 확장될 때마다 선택한 요소를 페이지의 보이는 영역까지 스크롤해야 합니다. 드롭다운 목록에는 내용이 많을 수 있지만 드롭다운 목록의 외부 선택 목록에는 최대 높이가 있으므로 최대 높이를 초과하면 계산이 스크롤 막대가 나타납니다. 기본적으로 수행되지 않는 경우 선택한 요소는 스크롤 막대 아래 또는 스크롤 막대 위의 스크롤 막대 아래에 있을 수 있으므로 컨테이너 스크롤 막대의 위치를 ​​재설정하려면 계산이 필요합니다. 구체적으로, 선택한 콘텐츠가 스크롤 막대 위 또는 아래에 표시되는지 여부는 선택한 요소의 offsetTop 값이 외부 컨테이너 선택 목록의 실제 높이의 절반보다 큰지 여부에 따라 선택한 요소를 시각적 영역에 표시하는 방법입니다. inView 메소드입니다. inView 메소드는 다음과 같습니다
코드 복사 코드는 다음과 같습니다.

inView: 함수 (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
//스크롤 막대는 상위 값으로 스크롤됩니다.
this.scrollInView(wrapper, top)
}
}else{
var clientHeight = 래퍼. 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을 지정된 값으로 설정하는 것입니다. 메소드는 다음과 같이 구현됩니다.
코드 복사 코드는 다음과 같습니다.

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

이 메소드는 setTimeout 및 자바스크립트 실행 큐에 지연이 추가되는데, 가장 큰 문제는 IE8에서 확장된 드롭다운 목록의 스크롤 막대가 코드에서 설정한 scrollTop을 무시하고 결국 맨 위로 스크롤된다는 점입니다(성능 측면에서 볼 때, scrollTop 설정도 적용될 수 있는 것 같지만 결국에는 스크롤 막대가 맨 위로 재설정됩니다. IE8에서 왜 이런 문제가 발생하는지 모르겠습니다.) 선택한 요소를 시각적 영역 내에 표시할 수 없습니다. 다른 브라우저에서는 문제가 발생하지 않습니다.
전체 구현 세부 사항은 대략 이 정도입니다. 키보드의 위쪽 및 아래쪽 키를 누르고 Enter 키를 눌러 드롭다운 목록을 닫는 논리는 매우 간단합니다.
발생한 문제
키보드 키다운, 키업, 키누름 이벤트에 응답하기 위해 div가 포커스를 갖도록 하는 방법, Google(Google은 특별한 상황에서는 사용하기 쉽지 않습니다. 기능) 일부 정보를 검색한 후 마침내 div 요소가 집중을 얻고 사용자 작업에 응답할 수 있도록 div 요소에 대한 tabindex 속성을 설정해야 한다는 것을 발견했습니다. 브라우저는 기본적으로 두 번 클릭하거나 너무 자주 클릭하여 현재 영역을 선택하므로 이 기본 작업을 취소하고 사용자에게 좋은 경험을 제공하려면 선택 불가능한 속성을 div 요소에 추가해야 합니다. IE 브라우저에만 적용됩니다. 선택 불가능한 클래스 이름을 추가하면 다른 브라우저에서 이 문제를 피할 수 있습니다. 다른 문제는 논리적 제어 및 일부 위치 계산이며 여기서는 논의하지 않습니다.
사용 방법
먼저 페이지 템플릿에서 jselect로 바꾸려는 요소를 숨기거나 처리하지 않습니다. 기본적으로 jselect는 페이지의 모든 선택 항목을 가져와서 바꿉니다. jselect가 이를 대체하는 것을 원하지 않으면 select 요소
에 사용자 정의 속성 data-enabled="true"를 추가해야 합니다. 물론 data-enabled="false"를 추가하면 이 사용자 정의 속성이 없는 것처럼 jselect로 대체됩니다. 사용 중에 레이아웃 구조가 더 복잡한 페이지에서는 다른 문제가 발생할 수 있습니다. 제가 테스트한 페이지 구조는 매우 간단하기 때문에 테스트하지 않았을 수 있습니다.
jselect를 사용하려면 먼저 squid.js를 도입한 다음 jselect-1.0.js, jselect-1.0.css 파일을 가져와야 합니다. jselect를 호출해야 하는 경우 다음 호출 방법을 통해 jselect를 초기화합니다. Swing.jselect();
참고: jselect 소스 코드와 데모는 여기에서 다운로드할 수 있습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.