quiz icon indicating copy to clipboard operation
quiz copied to clipboard

DOM基础测试40

Open zhangxinxu opened this issue 6 years ago • 33 comments
trafficstars

本期关于常见的列表操作,以及简单的快捷键访问支持。

积分:3+4

大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式(缩进和代码高亮1积分)。

```js
// 你的JS代码写在这里
 ```

**心怀瑞雪,自己作答,不要参考别人回答**

其他 本周因为要去北京参加活动,因此直播时间改为下周六和CSS小测一起,直播地址:https://live.bilibili.com/21193211

每位答题者会有至少2积分参与分,本次小测满分9积分,1分隐藏奖励分。

首位答题者将会获得100%被翻牌的技能。

zhangxinxu avatar Nov 20 '19 11:11 zhangxinxu

    {
        let now = -1;
        let oInput = document.querySelector("input");
        let aLi = document.querySelectorAll("#list li");

        aLi.forEach((item, index) => {
            item.addEventListener("click", () => {
                if (now != index) {
                    aLi[now] && aLi[now].classList.remove("selected");
                    oInput.value = item.innerHTML;
                    item.classList.add("selected");
                    now = index;
                }
            })
        });

        let move = (dir) => {
            aLi[now] && aLi[now].classList.remove("selected");
            dir === "up" ? now-- : now++;
            if (now < 0) {
                now = aLi.length - 1;
            }
            if(now > aLi.length - 1){
                now = 0;
            }
            oInput.value = aLi[now].innerHTML;
            aLi[now].classList.add("selected");
        };
        document.addEventListener("keyup", ({keyCode}) => {
            switch (keyCode) {
                case 38: //up
                    move("up");
                    break;
                case 40: //down
                    move("down");
                    break;
            }
        })
    }

guqianfeng avatar Nov 20 '19 12:11 guqianfeng

var input = document.querySelector("#input");
var list = document.querySelector("#list");
list.addEventListener("click",function(e){
    var target = e.target;
    var selected = list.querySelector(".selected");
    selected&&selected.classList.remove("selected");
    target.classList.add('selected');
    input.value = target.innerHTML;
})
var lis = list.querySelectorAll('li');
window.addEventListener("keyup",function(e){
    var selected = list.querySelector(".selected"),
        target;
    switch(e.keyCode){
        case 40:
        if(!selected||selected===list.lastElementChild){
            target = list.firstElementChild;
        }else{
            target = selected.nextElementSibling;
        };
        break;
        case 38:
        if(!selected||selected===list.firstElementChild){
            target = list.lastElementChild;
        }else{
            target = selected.previousElementSibling;
        };
        break;
    }
    if([38,40].includes(e.keyCode)){
        selected&&selected.classList.remove("selected");
        target.classList.add('selected');
        input.value = target.innerHTML;
    }
})

liyongleihf2006 avatar Nov 20 '19 12:11 liyongleihf2006

https://jsbin.com/tunino/edit?html,css,output

    var list = document.getElementById('list');
    var input = document.getElementById('input');
    function selected(target) {
        // 在列表中选择 有 selected 的元素 不取消不在列表中的selected元素
        var items = list.querySelectorAll('.selected');
        var txt = target.innerText.replace(/$\s+/).replace(/\s+^/);
        input.value = txt;
        items && items.length > 0 && items.forEach(item => {item.classList.remove('selected')});
        target.classList.add('selected');
    }
    // 点击
    list.addEventListener('click', (e) => {
        var target = e.target;
        selected(target);
    });
    function move(e) {
        var keyCode = e.keyCode;
        if(keyCode !== 38 && keyCode !== 40){
            return;
        }
        var items = list.children;
        var index = Array.prototype.reduce.call(items,(init,item, i) => {
            return item.classList.contains('selected') ? i : init;
        },-1)
        if(keyCode === 40) {
            //向下
            index = index === -1 ? 0 : (index + 1) % items.length;
        }
        else{
            // 向上
            index = index === -1 ? items.length - 1 : (index + items.length - 1) % items.length;
        }
        selected(items[index]);
    }
    // 按键
    window.addEventListener('keyup',(e) => {
        move(e);
    })

ylfeng250 avatar Nov 20 '19 13:11 ylfeng250

demo

//zxx: 有bug,会同时出现两个红色
    let input = document.querySelector('#input')

    let list = document.querySelectorAll('#list li')

    let originTarget
    list.forEach((item) => {
      item.addEventListener('click', e => {
        if (originTarget) {
          originTarget.classList.remove('selected')
        }
        console.log(e.target.classList)
        originTarget = e.target
        input.value = e.target.innerText
        e.target.classList.toggle('selected')
      })
    })
    // 2
    function selectedIndex(arr) {
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].classList.contains('selected')) return i
      }
      return -1
    }
    function sync(current, prev, input) {
      if (current) {
        console.log(current)
        current.classList.add('selected')
        input.value = current.innerText
      }
      prev ? prev.classList.remove('selected') : ''
    }
    document.addEventListener('keydown', e => {
      let si = selectedIndex(list)
      let current
      let prev
      if (e.keyCode == 40) {
        if (si == list.length - 1) {
          prev = list[si]
          current = list[0]
        } else if (si >= 0) {
          prev = list[si]
          current = list[si + 1]
        } else {
          current = list[0]
        }
        sync(current, prev, input)
      } else if (e.keyCode == 38) {
        if (si > 0) {
          prev = list[si]
          current = list[si - 1 % list.length]
        } else if (si == 0) {
          prev = list[si]
          current = list[list.length - 1]
        } else {
          current = list[list.length - 1]
        }
        sync(current, prev, input)
      }
    })

les-lee avatar Nov 20 '19 13:11 les-lee

const input = document.getElementById("input");
const list = document.getElementById("list");
const func = (nextEle, prevEle) => {
  if (prevEle) {
    prevEle.classList.remove("selected");
  }
  input.value = nextEle.innerText;
  nextEle.classList.add("selected");
};
// 点击li列表元素赋值
list.addEventListener("click", function(e) {
  const element = e.target;
  const name = element.nodeName;
  if (name === "LI") {
    const oldSelectedLi = list.getElementsByClassName("selected")[0];
    func(element, oldSelectedLi);
  }
});

// 监听键盘上下方向,按键后列表高亮并同时赋值
document.addEventListener("keyup", function(e) {
  const keyCode = e.keyCode;
  if (keyCode === 38) {
    const oldSelectedLi = list.getElementsByClassName("selected")[0];
    if (oldSelectedLi) {
      const prevEle = oldSelectedLi.previousElementSibling;
      if (prevEle) {
        func(prevEle, oldSelectedLi);
        return;
      }
    }
    const lastEle = list.lastElementChild;
    func(lastEle, oldSelectedLi);
  }

  if (keyCode === 40) {
    const oldSelectedLi = list.getElementsByClassName("selected")[0];
    if (oldSelectedLi) {
      const nextEle = oldSelectedLi.nextElementSibling;
      if (nextEle) {
        func(nextEle, oldSelectedLi);
        return;
      }
    }
    const firstEle = list.firstElementChild;
    func(firstEle, oldSelectedLi);
  }
});

zjgyb avatar Nov 20 '19 13:11 zjgyb

demo

var input = document.getElementById('input');
var oul = document.getElementById('list');
var list = oul.querySelectorAll('li');
var vlist = oul.querySelectorAll('li:not([hidden])');
var index = -1;

function setIndex(i){
    var max = vlist.length - 1;
    if(i<0){
        i = max;
    }
    if(i>max){
        i = 0;
    }
    vlist[index] && vlist[index].classList.remove('select');
    vlist[i].classList.add('select');
    input.value = vlist[i].innerText;
    index = i;
}
oul.addEventListener('click',function(ev){
    var target = ev.target;
    if(target.tagName==='LI'){
        setIndex([].slice.call(vlist).indexOf(target));
        input.focus();
    }
})
input.addEventListener('keydown',function(ev){
    switch (ev.keyCode) {
        case 40:
            ev.preventDefault();
            setIndex(index+1);
            break;
        case 38:
            ev.preventDefault();
            setIndex(index-1);
            break;
        default:
            break;
    }
})
input.addEventListener('input',function(ev){
    var value = ev.target.value;
    list.forEach(function(el,i){
        if(el.innerText.includes(value)){
            el.removeAttribute('hidden');
        }else{
            el.setAttribute('hidden','');
        }
    });
    vlist[index] && vlist[index].classList.remove('select');
    vlist = oul.querySelectorAll('li:not([hidden])');
    if(value){
        index = 0;
        vlist[0].classList.add('select');
    }else{
        index = -1;
    }
})

XboxYan avatar Nov 20 '19 13:11 XboxYan

code Demo

const input = document.getElementById('input')
const list = document.getElementById('list')
const log = document.getElementById('log');

function selectList(e) {
    const selectedLi = list.children
    let index = Array.prototype.findIndex.call(selectedLi, elm => elm.classList.contains('selected'))
    let selectIndex = index
    if (e.keyCode === 40) {
        if (index === -1) {
            selectIndex = 0
        } else {
            selectIndex = ++selectIndex % list.childElementCount
        }
    } else if (e.keyCode === 38) {
        if (index === -1) {
            selectIndex = list.childElementCount - 1
        } else {
            selectIndex = selectIndex === 0 ? list.childElementCount - 1 : selectIndex - 1
        }
    } else {
        return
    }
    index !== -1 && list.children[index].classList.remove('selected')
    list.children[selectIndex].classList.add('selected')
    input.value = list.children[selectIndex].textContent
}

list.querySelectorAll(':root li').forEach(elm => {
    elm.addEventListener('click', e => {
        input.value = elm.textContent
        removeSelected()
        e.currentTarget.classList.add('selected')
    })
})

input.addEventListener('keydown', selectList)

function removeSelected() {
  const selected = document.querySelector('.selected')
  if (selected) {
    selected.classList.remove('selected')
  }
}

livetune avatar Nov 20 '19 15:11 livetune

demo

let eleList = document.getElementById("list");
let eleInput = document.getElementById("input");
let dataList = new Proxy({},{
 get(target, name) {
  switch (name) {
   case "next": return target.act && target.act.nextElementSibling || eleList.firstElementChild;
   case "prev": return target.act && target.act.previousElementSibling || eleList.lastElementChild;
   default    : return target[name];
  }},
 set(obj, prop, value) {
  switch (prop) {
   case "act" :
     if (!value) {return}
     obj.act && obj.act.classList.remove("selected");
     value && value.classList.add("selected");
     eleInput.value = value.textContent;
     eleInput.select();//自动选中
   default :
     obj[prop] = value;
  }}
});
eleList.addEventListener("mousedown", e => e.preventDefault());//防止outline闪烁
eleList.addEventListener("click", e => {dataList.act = e.target});
document.addEventListener("keydown", e => {
  e.keyCode === 38||e.keyCode === 40?e.preventDefault():void 0;//防止光标闪烁
  dataList.act =
     e.keyCode === 38? dataList.prev
   : e.keyCode === 40? dataList.next
   : null;
});

Seasonley avatar Nov 20 '19 16:11 Seasonley

代码示例:https://codepen.io/iceytea/pen/oNNVxeK

注:仅在 Chrome 78.0.3904.97(正式版本)下测试通过,代码中未作出对其他浏览器兼容性的处理

var SELECTED_MARK = "selected";
var KEYCODE_UP = 38,
  KEYCODE_DOWN = 40;
var input = document.getElementById("input"),
  ul = document.getElementById("list"),
  li_group = ul.children,
  first_li = ul.firstElementChild,
  last_li = ul.lastElementChild;

var last_selected_li; // 上次选中的 li

/* 处理选中事件 selected_li 当前选中的 li*/
function handleSelect(selected_li) {
  if (last_selected_li) {
    last_selected_li.classList.remove(SELECTED_MARK);
  }
  selected_li.classList.add(SELECTED_MARK);
  input.value = selected_li.textContent;
}

// 设置上次选中的 li
function setLastSelectedLi() {
  // 注:同一时刻只有一个被选中的 li
  last_selected_li = ul.getElementsByClassName(SELECTED_MARK).item(0);
}

// 点击事件
ul.addEventListener("click", function(e) {
  var selected_li = e.target;
  setLastSelectedLi();
  if (selected_li.parentElement === ul && selected_li !== last_selected_li) {
    handleSelect(selected_li);
  }
});

// 键盘按下事件
document.addEventListener("keydown", function(e) {
  var keyCode = e.keyCode;
  setLastSelectedLi();

  if (keyCode === KEYCODE_DOWN) {
    if (!last_selected_li || !last_selected_li.nextElementSibling) {
      handleSelect(first_li);
    } else {
      handleSelect(last_selected_li.nextElementSibling);
    }
  }
  if (keyCode === KEYCODE_UP) {
    if (!last_selected_li || !last_selected_li.previousElementSibling) {
      handleSelect(last_li);
    } else {
      handleSelect(last_selected_li.previousElementSibling);
    }
  }
});

ghost avatar Nov 20 '19 16:11 ghost

demo

var SELECT = 'selected';
var input = document.getElementById('input');
var list = document.getElementById('list');
var liArr = list.querySelectorAll('li');
var liLength = liArr.length;
var selectIndex = -1;
var selectLi;

list.addEventListener('click', function(event) {
  var target = event.target;
  if (target.tagName === 'LI') {
    if (selectLi) {
      selectLi.classList.remove(SELECT);
      selectLi.removeAttribute('aria-selected');
    }
    selectLi = target;
    selectLi.classList.add(SELECT);
    selectLi.setAttribute('aria-selected', 'true');
    selectIndex = Array.from(liArr).indexOf(selectLi);
    input.value = selectLi.textContent;
  }
});

list.addEventListener('focus', function() {
  if (!selectLi) {
    var event = new Event('keydown');
    event.key = 'Home';
    document.dispatchEvent(event);
  }
});

// 2
document.addEventListener('keydown', function(event) {
  switch (event.key) {
    case 'ArrowUp':
      selectIndex = selectIndex === -1 ? 0 : selectIndex;
      _selectByIndex(-1);
      break;
    case 'ArrowDown':
      _selectByIndex(1);
      break;
    case 'Home':
      selectIndex = 0;
      _selectByIndex(0);
      break;
    case 'End':
      selectIndex = liArr.length - 1;
      _selectByIndex(0);
      break;
    default:
      break;
  }
});

function _selectByIndex(step) {
  selectIndex = (selectIndex + liLength + step) % liLength;
  if (selectLi) {
    selectLi.classList.remove(SELECT);
    selectLi.removeAttribute('aria-selected');
  }
  selectLi = liArr[selectIndex];
  selectLi.classList.add(SELECT);
  selectLi.setAttribute('aria-selected', 'true');
  input.value = selectLi.textContent;
  list.focus();
}

Despair-lj avatar Nov 20 '19 19:11 Despair-lj

demo

li.selected {
  color: red;
}
<input id="input">
<ul id="list">
  <li>列表1</li>
  <li>列表2</li>
  <li>列表3</li>
</ul>
let list = document.getElementById('list')
let items = list.querySelectorAll('li')
let inputItem = document.getElementById('input')
let cur = -1 // 当前选中li元素索引
let total = items.length // li元素总数

// 选中指定索引的li元素
function selectItem (idx) {
  if (cur !== -1) {
    items[cur].classList.remove('selected')
  }
  items[idx].classList.add('selected')
  inputItem.value = items[idx].innerText
  cur = idx
}

for (let i = 0; i < total; i++) {
  items[i].addEventListener('click', () => {
    selectItem(i)
  })
}

window.addEventListener('keydown', e => {
  if (e.key === 'ArrowDown') {
    selectItem(cur !== -1 ? (cur + 1) % total : 0)
  } else if (e.key === 'ArrowUp') {
    selectItem(cur !== -1 ? (cur - 1 + total) % total : total - 1)
  }
})

xxf1996 avatar Nov 21 '19 02:11 xxf1996

demo

llet lis = document.querySelectorAll('#list li')
let input = document.getElementById('input')
lis.forEach(li => {
    li.addEventListener('click', event => {
        console.log(event)
        let text = event.target.innerText
        input.value = text
        lis.forEach(li => {
            li.classList.remove('selected')
        })
        event.target.classList.add('selected')
    })
})
function selectPrev() {
let selectedLi = document.querySelector('#list .selected')
    if (selectedLi) {
        selectedLi.classList.remove('selected')
        if (selectedLi.previousElementSibling) {
            selectedLi.previousElementSibling.classList.add('selected')
            input.value = selectedLi.previousElementSibling.innerText
        } else {
            lis[lis.length - 1].classList.add('selected')
            input.value = lis[lis.length - 1].innerText
        }
    }
}
function selectNext() {
    let selectedLi = document.querySelector('#list .selected')
    if (selectedLi) {
        selectedLi.classList.remove('selected')
        if (selectedLi.nextElementSibling) {
            selectedLi.nextElementSibling.classList.add('selected')
            input.value = selectedLi.nextElementSibling.innerText
        } else {
            lis[0].classList.add('selected')
            input.value = lis[0].innerText
        }
    } else {
        lis[0].classList.add('selected')
        input.value = lis[0].innerText
    }
}
document.addEventListener('keydown', event => {
    let { keyCode } = event
    switch (keyCode) {
    case 38:
        selectPrev()
    break;
    case 40: 
        selectNext()
    default:
        break;
    }
})

frankyeyq avatar Nov 21 '19 03:11 frankyeyq

题目1

var input = document.getElementById('input');
var listWrap = document.getElementById('list');
var listItems = listWrap.getElementsByTagName('li');
var curIndex = -1;

function clickHandle (e) {
  console.log(listItems.length);
  var target = e.target;

  if (target.tagName === 'LI') {
    if(listItems[curIndex] === target) return input.focus();

    if (curIndex > -1) {
      listItems[curIndex].classList.remove('selected');
    }

    for (var i = 0, len = listItems.length; i < len; i ++) {
      if(target === listItems[i]){
        curIndex = i;
        break;
      }
    }

    target.classList.add('selected');
    input.value = target.textContent;
    input.focus();
  }
}
listWrap.addEventListener('click', clickHandle, false);

题目2

var changeCur = {
  '38': function () {
    curIndex = (--curIndex > -1) ? curIndex : (listItems.length - 1);
  },
  '40': function () {
    curIndex = (curIndex + 1) % listItems.length;
  }
}

function keyDownHandle(e) {
  var keyCode = e.keyCode;

  if (keyCode === 38 || keyCode === 40) {
    e.preventDefault();
    if (curIndex > - 1) {
      listItems[curIndex].classList.remove('selected');
    }

    changeCur[keyCode]();

    listItems[curIndex].classList.add('selected');
    input.value = listItems[curIndex].textContent;
    input.focus();

  }
}
document.addEventListener('keydown', keyDownHandle, false);

theDrunkFish avatar Nov 21 '19 03:11 theDrunkFish

demo

let list = document.getElementById('list')
let aLi = Array.from(list.children)

// 存储当前DOM索引
let current_highlight = null

list.addEventListener('click', (e) => {
  if (e.target.nodeName === 'LI') {
    handleInputAndLi(e.target)
  }
})

document.addEventListener('keydown', (e) => {
  let keyCode = e.keyCode
  
  if (keyCode !== 38 && keyCode !== 40) return
  
  let index
  let maxIndex = aLi.length - 1

  if (current_highlight) {
    let _currenIndex = current_highlight - 1
    index = keyCode === 38 ? (_currenIndex === 0 ? maxIndex : _currenIndex - 1) : (_currenIndex === maxIndex ? 0 : _currenIndex + 1)
  } else {
   index = keyCode === 38 ? 0 : maxIndex
  }
  
  handleInputAndLi(aLi[index])
})

function handleInputAndLi (el) {
  let val = el.innerHTML
  input.value = val
  aLi.forEach((item, index) => {
    if (item.classList.contains('selected')) {
      item.classList.remove('selected')
    }
    
    if (item === el) {
      current_highlight = index + 1
    }
  })
  el.classList.add('selected')
}

asyncguo avatar Nov 21 '19 03:11 asyncguo

demo

let ul = document.querySelector("#list");
let input = document.querySelector("#input");
let list = document.querySelectorAll("li");
ul.addEventListener("click", function(e) {
    for (var i = 0; i < list.length; i++) {
        if (list[i].classList.contains("selected")) {
            list[i].classList.remove("selected");
          }
        }  
        let currentItem = e.target;
        input.value = currentItem.innerText;
        currentItem.classList.add("selected");
 });

window.addEventListener("keyup", function(e) {
    var selected = ul.querySelector(".selected");
    let index;
    switch (e.keyCode) {
       case 38:
       e.preventDefault();
        if (!selected) {
          index = list.length - 1;
          input.value = list[index].innerText;
          list[index].classList.add("selected");
            } else {
              index = Array.from(list).indexOf(selected);
              if (index == 0) {
                index = list.length;
              }
              selected.classList.remove("selected");
              list[index - 1].classList.add("selected");
              input.value = list[index - 1].innerText;
            }
            break;
        case 40:
        e.preventDefault();
        if (!selected) {
          index = 0;
          input.value = list[index].innerText;
          list[index].classList.add("selected");
            } else {
              index = Array.from(list).indexOf(selected);
              if (index == list.length - 1) {
                index = -1;
              }
              selected.classList.remove("selected");
              list[index + 1].classList.add("selected");
              input.value = list[index + 1].innerText;
            }
            break;
        }
 });

whrice avatar Nov 21 '19 04:11 whrice

demo JS

    var tag = -1
    var list = document.querySelectorAll('#list li')
    var length = list.length - 1
    var inputEle = document.querySelector('#input')

    /**
     * 样式改变
     * @param {Array} [arr = []] 列表数组
     * @param {String} [style] 要移除的样式
     */
    function styleAlert(arr = [], style) {
      arr.forEach((item, index) => { item.classList.remove(style) }) // 移除全部selectde样式
      arr.forEach((item, index) => {
        if (index === tag) {
          item.classList.add(style)
          inputEle.value = item.innerHTML
        }
      })
    }
    list.forEach((item, index) => {
      item.addEventListener('click', function () {
        tag = index
        styleAlert(list, 'selectde')
      })
    })
    window.onkeyup = function (event) {
      if (event.keyCode === 38 && event.code === "ArrowUp") {
        tag > 0 ? --tag : tag = length
        styleAlert(list, 'selectde')
      }
      if (event.keyCode === 40 && event.code === "ArrowDown") {
        tag < 2 ? ++tag : tag = 0
        styleAlert(list, 'selectde')
      }
    
    }

HTML

  <input type="text" id="input">
  <ul id="list">
    <li class="pervent-more-click">列表1</li>
    <li class="pervent-more-click">列表2</li>
    <li class="pervent-more-click">列表3</li>
  </ul>

CSS

    input {
      border: 1px solid #ccc;
      border-radius: 3px;
      padding: 5px 10px;
    }

    .pervent-more-click {
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
      outline: 0;
    }

    ul {
      padding: 0px;
      /* display: inline-block; */
      list-style-type: none;
    }

    li {
      width: 200px;
      cursor: pointer;
    }

    li.selectde {
      color: red;
    }

zengqingxiao avatar Nov 21 '19 04:11 zengqingxiao

var oLi = document.querySelectorAll('li')
var input = document.querySelector('input')
oLi.forEach(item => {
	item.addEventListener('click',function(){
		let self = this;
		self.className = self.className.indexOf('selected') === -1 ? self.className += 'selected' : self.className;
		input.value = self.innerText;
		let aLi = self.parentNode.children
		for (let i = 0, len = aLi.length; i < len; i++) {
			if (self !== aLi[i]) {
				aLi[i].className = aLi[i].className.replace(/selected/g, '')
			}
		}
	},false)
})
document.addEventListener('keydown', function(event){
	if (event.keyCode === 38) {
		move('up')
	}
	if (event.keyCode === 40) {
		move('down')
	}
},false)
   function move (type) {
	let now, next;
	let current = document.querySelector('.selected')
	let currentUl = [...document.querySelectorAll('li')]
	if (current === null) {
		if (type === 'up') {
			next = oLi.length -1
		} else {
			next = 0
		}
	} else {
		now = currentUl.indexOf(current)
		if (type === 'up') {
			next = (now - 1) >= 0 ? now -1 : oLi.length -1;
		}
		if (type === 'down') {
			next = now + 1 >= oLi.length ? 0 : now + 1;
		}
		oLi[now].className = oLi[now].className.replace(/selected/g, '')
	}
	oLi[next].className = 'selected'
	input.value = oLi[next].innerText
  }

LYN-alan avatar Nov 21 '19 05:11 LYN-alan

> 在线 Demo <

const viewList = {
  init() {
    this.input = document.getElementById('input');
    this.list = document.getElementById('list');
    this.listItems = this.list.querySelectorAll('li');
    this.selectedIdx = -1;
    this.clickHandle();
    this.keyingHandle();
  },
  clickHandle() {
    this.listItems.forEach((li, index) => {
      li.addEventListener('click', () => this.doSelect(index));
    });
  },
  keyingHandle() {
    document.addEventListener('keydown', ({ keyCode }) => {
      const maxIndex = this.listItems.length - 1;
      let index = this.selectedIdx;

      if (keyCode === 38) {  // ↑
        index--
      } else if (keyCode === 40) {  // ↓
        index++
      }

      index = index < 0 ? maxIndex : index;
      index = index > maxIndex ? 0 : index;

      this.doSelect(index);
    });
  },
  doSelect(index) {
    const curLi = this.listItems[index];
    const selectedIdx = this.selectedIdx < 0 ? 0 : this.selectedIdx;

    this.listItems[selectedIdx].classList.remove('selected');
    curLi.classList.add('selected');
    this.input.value = curLi.innerText;
    this.selectedIdx = index;
  }
};

viewList.init();

wingmeng avatar Nov 21 '19 12:11 wingmeng

JSBIN:点我

//zxx: 为什么键盘事件在列表DOM上,autocomplete冲突可以阻止默认行为,或者设置属性值为off

@zhangxinxu 我可能理解错题意了,因为第一题是点击一个列表然后在输入框中显示文案,第二题我理解为直接在这个列表选中状态下进行上下键操作😂

<style>
    li.selected {
        background-color: red;
    }
</style>
<input id="input">
<ul tabindex="0" id="list">
    <li>列表1</li>
    <li>列表2</li>
    <li>列表3</li>
    <li>
    <div>列表41</div>
    <div>
        <span>列表42</span>
    </div>
    </li>
</ul>
<script>
    var domInput = document.getElementById("input");
    var domList = document.getElementById("list");
    var fnSelectThisItem = function (item) {
        // 移除 domList 所有 selected
        var domSelected = domList.querySelectorAll('.selected');
        var selectedLen = domSelected.length;
        for (var i = 0; i < selectedLen; i++) {
            domSelected[i].classList.remove('selected');
        }
        // 高亮
        item.classList.add('selected');
        // 赋值
        domInput.value = item.innerText;
    };


    domList.addEventListener('click', function (e) {
        var domTarget = e.target;
        // 找到对应子元素
        while (domTarget !== domList && domTarget.tagName.toLowerCase() !== 'li') {
            domTarget = domTarget.parentNode;
        }
        if (domTarget !== domList && !domTarget.classList.contains('selected')) {
            fnSelectThisItem(domTarget);
        }
    });

    // 输入框按下让列表获取焦点
    // 但是这个功能感觉不应该有和 autoComplete 有点冲突
    // 有点拿捏不准
    // domInput.addEventListener('keydown', function (e) {
    //     (e.keyCode === 40) && domList.focus();
    // });

    domList.addEventListener('keydown', function (e) {
        var isUp = e.keyCode === 38;
        var isDown = e.keyCode === 40;
        if (!isUp && !isDown) {
            return;
        }
        var domSelected = domList.querySelector('.selected');
        var kids = domList.children;
        var kidLen = kids.length;
        // 一个选中的都没有
        if (!domSelected) {
            var goIndex = isUp ? kidLen - 1 : 0;
            fnSelectThisItem(kids[goIndex]);
            return;
        }
        for (var i = 0; i < kidLen; i++) {
            var kid = kids[i];
            // 遍历找到当前选中的元素
            if (kid === domSelected) {
                var goIndex = 0;
                if (isUp) {
                    goIndex = (i - 1) < 0 ? kidLen - 1 : i - 1;
                } else if (isDown) {
                    goIndex = (i + 1) < kidLen ? i + 1 : 0;
                }
                fnSelectThisItem(kids[goIndex]);
                break;
            }
        }
    });
</script>

ziven27 avatar Nov 21 '19 12:11 ziven27

demo

var list = document.getElementById('list')
var input = document.getElementById('input')
var li = document.querySelectorAll('#list>li')
li = [...li]
list.addEventListener('click', (e) => {
  var self = e.target
  if (self.tagName === 'LI') {
    var selected = li.find(item => item.classList.contains('selected'))
    if (selected) {
      selected.classList.remove('selected')
    }
    self.classList.add('selected')
    input.value = self.innerText
  }
})
window.addEventListener('keydown', (e) => {
  var code = e.keyCode
  if (code === 38 || code === 40) {
    var i = li.findIndex(item => item.classList.contains('selected'))
    var len = li.length
    var nextIndex
    if (i >= 0) {
      li[i].classList.remove('selected')
      nextIndex = code === 40 ? (i + 1) % len : (i - 1 + len) % len        
    } else {
      nextIndex = code === 40 ? 0 : len - 1
    }
    var next = li[nextIndex]
    next.classList.add('selected')
    input.value = next.innerText
  }
})

zy017 avatar Nov 21 '19 14:11 zy017

var input = document.querySelector("#input");
var li = document.querySelectorAll("li");
var index = -1;

[].slice.call(li).forEach(function (el,i) {
    el.addEventListener("click",function () {
        var selected = document.querySelector(".selected");
        selected && selected.classList.remove("selected");
        this.classList.add("selected");
        input.value = this.textContent;
        index = i;
    });
});

document.addEventListener("keyup",function (e) {
    if(e.keyCode === 40){
        movePos("down");
    }else if(e.keyCode === 38){
        movePos("up");
    }
});

function movePos(type){
    index !== -1 && li[index].classList.remove("selected");
    if(type === "down"){
        index++;
        if(index > li.length - 1){
            index = 0;
        }
    }else{
        index--;
        if(index < 0){
            index = li.length - 1;
        }
    }
    li[index].classList.add("selected");
    input.value = li[index].textContent;
}

silverWolf818 avatar Nov 21 '19 14:11 silverWolf818

demo

    let inputDom = document.getElementById('input'),
        list = document.getElementById('list'),
        lis = list.children,
        listLength = lis.length,
        dom = null

    list.addEventListener('click', e => {
        if (dom instanceof HTMLElement) {
            dom.classList.remove('selected')
        }
        dom = e.target
        e.target.classList.add('selected')
        inputDom.value = e.target.innerText
    })

    document.onkeydown = e => {
        if (e.keyCode === 38 || e.keyCode === 40) {
            let clickIndex = 0
            if (dom instanceof HTMLElement) {
                clickIndex = [].indexOf.call(lis, dom)
                if (e.keyCode === 38) {
                    clickIndex--
                } else {
                    clickIndex++
                }
            } else {
                if (e.keyCode === 38) {
                    clickIndex = listLength - 1
                }
            }
            clickIndex = clickIndex < 0 ? listLength - 1 : clickIndex === listLength ? 0 : clickIndex
            lis[clickIndex].click()
        }
    }

rayj1993 avatar Nov 21 '19 16:11 rayj1993

var selectItem = function(item) {
	item.classList.add('selected');
	document.querySelector('#input').value = item.innerText;
};
//第一题
document.querySelector('#list').onclick = function (e) {
	selectItem(e.target);
	Array.from(e.target.parentNode.children).forEach(child => {
		if (child !== e.target) {
			child.classList.remove('selected');
		}
	});
};
//第二题
var listTrigger = (function() {
	var list = document.querySelector('#list').children;
	var getIndex = function() {
		return Array.from(list).findIndex(v => v.classList.contains('selected'));
	};

	return {
		prev: function() {
			var index = getIndex();
			if (index !== -1) {
				list[index].classList.remove('selected');
				index--;
				if (index < 0) {
					index += list.length;
				}
			} else {
				index = 0;
			}
			selectItem(list[index]);
		},
		next: function() {
			var index = getIndex();
			if (index !== -1) {
				list[index].classList.remove('selected');
			}
			index = (index + 1) % list.length;
			selectItem(list[index]);
		}
	}
})();
document.onkeydown = function (e) {
	if (e.code === 'ArrowUp') {
		listTrigger.prev();
	}
	if (e.code === 'ArrowDown') {
		listTrigger.next();
	}
}

NeilChen4698 avatar Nov 22 '19 04:11 NeilChen4698

在线demo

var input = document.querySelector('#input')
var ul = document.querySelector('#list')
var list = ul.querySelectorAll('li')

// 1
list.forEach(li => {
  li.addEventListener('click', () => {
    input.value = li.innerText
    var selected = ul.querySelector('.selected')
    selected && selected.classList.remove('selected')
    li.classList.add('selected')
  })
})

// 2
document.addEventListener('keydown', e => {
  if (e.keyCode !== 38 && e.keyCode !== 40) {
    return
  }
  var selected = ul.querySelector('.selected')
  if (e.keyCode === 38) {
    if (!selected || selected === ul.firstElementChild) {
      selected && selected.classList.remove('selected')
      ul.lastElementChild.classList.add('selected')
      input.value = ul.lastElementChild.innerText
    } else {
      selected && selected.classList.remove('selected')
      selected.previousElementSibling.classList.add('selected')
      input.value = selected.previousElementSibling.innerText
    }
  }
  if (e.keyCode === 40) {
    if (!selected || selected === ul.lastElementChild) {
      selected && selected.classList.remove('selected')
      ul.firstElementChild.classList.add('selected')
      input.value = ul.firstElementChild.innerText
    } else {
      selected && selected.classList.remove('selected')
      selected.nextElementSibling.classList.add('selected')
      input.value = selected.nextElementSibling.innerText
    }
  }
})

JaimeCheng avatar Nov 22 '19 06:11 JaimeCheng

demo js部分

let ipt = document.getElementById('input'),
    listBox = document.getElementById('list'),
    list = document.querySelectorAll('#list li');
let aClick = []; //记录上个点击的是谁

//第一题 点击切换 selected
list.forEach(function(item){
    item.onclick = function(){
        //前面有操作 对上一个操作处理
        if(aClick.length > 0) aClick[0].classList.remove('selected');
        // 现在要处理的操作
        this.classList.add("selected");
        ipt.value = this.innerText;
        aClick[0] = this;
    };
})

//第二题
let items = list[list.length-1];
let first = list[0];

function addCur(el,flag){
    let els = flag === 'first' ? list[0]: flag === 'last' ? items :el ;
    els.classList.add('selected');
    aClick[0] = el;
    ipt.value = el.innerText;
}

document.onkeydown = function(e){
    //向上
    if(e.keyCode == 38){
        //零界点处理
        if(aClick.length == 0) return addCur(items,'last');
        let prev = aClick[0].previousElementSibling;
        aClick[0].classList.remove('selected');
        addCur(!prev ? items:prev);
    }
    //向下
    if(e.keyCode==40){
        //零界点处理
        if(aClick.length == 0) return addCur(first,'first');
        let next = aClick[0].nextElementSibling;
        aClick[0].classList.remove('selected');
        addCur(!next ? first:next);
    }  
}; 

juzhiqiang avatar Nov 22 '19 06:11 juzhiqiang

jsbin

window.onload = function() {

  // 第一题
  let selectedIndex = -1;
  const lis = document.querySelectorAll('li');
  const input = document.querySelector('#input');
  [...lis].forEach((li,index) => {
    li.addEventListener('click',(e) => {
      selectedIndex = index;

      [...lis].forEach((li) =>{ li.classList.remove('selected')});
      e.target.classList.add('selected');

      const text = e.target.innerText;
      input.value = text;
    }, false)
  });

  // 第二题
  document.onkeyup = function(event) {
    if (event.keyCode === 40) {
      selectedIndex ++;
    }
    if (event.keyCode === 38) {
      selectedIndex --;
    }
    if (selectedIndex === 3) selectedIndex = 0;
    if (selectedIndex === -1) selectedIndex = 2;

    [...lis].forEach((li) =>{ li.classList.remove('selected')})
    const e = lis[selectedIndex];
    
    e.classList.add('selected');

    const text = e.innerText;
    input.value = text;
  }
}

GCGligoudan avatar Nov 22 '19 16:11 GCGligoudan

Demo

let inputObject = document.querySelector("#input");
let listObject = document.querySelectorAll("#list li");
var seletedItem = -1;
  • 第一题
listObject.forEach((item, index) => {
  item.addEventListener("click", () => {
    if (seletedItem != index) {
      if (listObject[seletedItem]) {
        listObject[seletedItem].classList.remove("selected");
      }
      inputObject.value = item.innerHTML;
      item.classList.add("selected");
      seletedItem = index;
    }
  });
});
  • 第二题
document.addEventListener("keyup", ({ keyCode }) => {
  if (keyCode == 38) {
    //UP
    action(false);
  } else if (keyCode == 40) {
    //Down
    action(true);
  }
});
function action(key) {
        if (seletedItem >= 0) {
            // seletedItem已赋值情况
            if (listObject[seletedItem]) {
                listObject[seletedItem].classList.remove("selected");
            }
            if (key) {
                seletedItem += 1;
            } else {
                if (seletedItem == 0) {
                    seletedItem = listObject.length - 1;
                } else {
                    seletedItem -= 1;
                }
            }

            seletedItem = seletedItem % listObject.length;
            var resultObject = listObject[seletedItem];
            inputObject.value = resultObject.innerHTML;
            resultObject.classList.add("selected");
        } else {
            //seletedItem未赋值情况
            if (key) {
                seletedItem = 0;
                var resultObject = listObject[seletedItem];
                inputObject.value = resultObject.innerHTML;
                resultObject.classList.add("selected");
            } else {
                seletedItem = listObject.length - 1;
                var resultObject = listObject[seletedItem];
                inputObject.value = resultObject.innerHTML;
                resultObject.classList.add("selected");
            }
        }
    }

lifelikejuly avatar Nov 24 '19 13:11 lifelikejuly

https://codepen.io/emmayxy/pen/poomZjp

//zxx: 点击事件丢了,上面链接地址也不对

let list = document.getElementsByTagName('li');
let index = 0, hasSelected = false;
let input = document.querySelector('#input');

function keyUp(e) {
if (e.keyCode === 38) {
  index --
} else if (e.keyCode === 40 && hasSelected) {
  index ++
} else if (e.keyCode === 40 && !hasSelected){
  hasSelected = true
  index = 0
} else {
  index = null
}
if (index < 0) {
  index = 2
} else if (index > 2) {
  index = 0
}
if (typeof index !== "object") {
  input.value = list[index].innerHTML
  Array.prototype.forEach.call(list, item => {
    item.classList.remove('selected')
  })
  list[index].classList.add('selected')
} 
}
document.addEventListener('keyup', keyUp)

EmmaYXY avatar Nov 26 '19 00:11 EmmaYXY

// 第一题
document.querySelector('#list').addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    [].slice.apply(document.querySelectorAll('#list li')).forEach(function(item) {
      item.classList.remove('selected');
    })
    document.querySelector('#input').value = e.target.innerText;
    e.target.classList.add('selected');
  }
});
// 第二题
document.addEventListener('keydown', function(e) {
   var li = [].slice.apply(document.querySelectorAll('#list li'));
   var selectedIndex = 0;
   li.forEach(function(item, index) {
     if ([].slice.apply(item.classList).indexOf('selected') !== -1) {
       item.classList.remove('selected');
       selectedIndex = index + 1;
     }
   })
   if (e && e.keyCode === 38) {
     const index = (selectedIndex - 1) % (li.length + 1);
     let realIndex = index;
     if (index === -1 || index === 0) {
       realIndex = li.length;
     }
     document.querySelector('#list li:nth-child('+ realIndex + ')').click();
   }
   if (e && e.keyCode === 40) {
     console.log(selectedIndex);
     const index = (selectedIndex + 1) % (li.length + 1);
     const realIndex = index === 0 ? 1 : index;
     document.querySelector('#list li:nth-child('+ realIndex + ')').click();
}
});

towavephone avatar Nov 26 '19 13:11 towavephone

//演示地址 http://49.233.165.74:801/

function Select(obj) { this.el = obj.el; this.class = obj.activeClass; //高亮的类名 this.isHas = false; //是否已经高亮 this.init(); }

Select.prototype = { //初始化 init: function () { this.addEvent(); }, //选择元素 $: function (el) { return document.querySelector(el); }, //初始化状态 pointState: function () { let childrens = this.$(this.el).children; for (let i = 0; i < childrens.length; i++) { childrens[i].classList.remove(this.class); }//初始化 return childrens; }, //元素添加高亮 isActive: function () { let childrens = this.$(this.el).children; let tabIndex = -1; for (let i = 0; i < childrens.length; i++) { if (childrens[i].classList.contains(this.class)) { tabIndex = i; break; } } return tabIndex; }, //高亮切换 changeEl: function (tempIndex, keyCode) { let codeArr = [13, 38, 40]; if (!codeArr.includes(keyCode)) { return } let childrens = this.pointState(); switch (keyCode) { case 13: if (this.isHas) { childrens[tempIndex].classList.add(this.class);//当前元素添加类名 } break; case 38: tempIndex--; if (tempIndex < 0) { tempIndex = childrens.length - 1; } childrens[tempIndex].classList.add(this.class);//当前元素添加类名 this.isHas = true; break; case 40: tempIndex++; if (tempIndex > childrens.length - 1) { tempIndex = 0; } this.isHas = true; childrens[tempIndex].classList.add(this.class);//当前元素添加类名 break; } console.log(childrens[tempIndex].innerHTML); ////输出当前选择的元素 }, //添加事件 addEvent: function () { let that = this; //添加点击事件 let childrens = this.$(this.el).children; for (let i = 0; i < childrens.length; i++) { childrens[i].addEventListener('click', function () { let tempChildren = that.pointState(); tempChildren[i].classList.add(that.class); console.log(tempChildren[i].innerHTML); ////输出当前选择的元素 }); }//初始化 //键盘事件 that.$('body').addEventListener('keyup', function (e) { let keyCode = e.keyCode; that.changeEl(that.isActive(), keyCode); // }) };

glwz2017 avatar Nov 27 '19 10:11 glwz2017