原生javascript的DOM操作,写demo时遇到了一个问题?

这是我目前做的小demo,请问如何才能实现:
①点击li后,相同项只显示一个。比如我点击价格0-299,当我再点击300-600时,前面那个0-299去掉,只显示300-600;类别和品牌也同样,同一项只显示一个内容。
②如何排序,使得点击后,div显示的顺序始终是价格、类别、品牌

↓点击代码,可预览效果
https://jsfiddle.net/20170808...

本人刚学原生javascript,请不要说用JQuery

阅读 2.9k
3 个回答
  • 不要直接在 body 上 appendChild, 所以在 html 结构上加上 <div id="selected"></div>, 专门用来显示选择的结果。

  • js 部分直接上代码算了。

var aUl = document.getElementsByTagName('ul');

    for (var i = 0; i < aUl.length; i++) {
      var aLi = aUl[i].getElementsByTagName('li');
      for (var j = 0; j < aLi.length; j++) {
        fn1(aLi[j]);
      }
    }

    var selected = document.getElementById('selected')
    var body = document.getElementsByTagName('body')[0];

    function fn1(oLi) {
      oLi.onclick = function () {
        var peerLis = this.parentNode.getElementsByTagName('li') // 该类别下的所有 li
        for (var j=0;j<peerLis.length;j++) {
          peerLis[j].style.display = 'inline-block'
        } // 所有的 li 都设置为 inline-block ,也就是使得上一次点击的项可见
        this.style.display = 'none'; // 当前点击项不可见

        var catagory = this.parentNode.children[0].innerHTML // 点击的类别

        if (selected.innerHTML.indexOf(catagory) > -1) { // 已经有这个类别了
          var oDiv = document.getElementById(catagory) // 获得该类别对应的 div
          oDiv.getElementsByTagName('span')[0].innerHTML = this.innerHTML + 'x' // 修改显示的内容
        } else { // 没有这个类别对应的 div 元素
          var oDiv = document.createElement('div');
          oDiv.setAttribute('id', catagory)
          selected.appendChild(oDiv);
          var oSpan = document.createElement('span');
          oSpan.innerHTML = this.innerHTML + ' x';
          oDiv.appendChild(oSpan);
        }
        fn2(oDiv, this);
      };
    }

    function fn2(oDiv, oLi) {
      oDiv.onclick = function () {
        oLi.style.display = 'inline-block';
        this.parentNode.removeChild(this);
      };
    }

主要修改了 fn1 部分,有注释,自己看。

  • css 不要所有的 div 都一个样式,

我看了下你的代码,你的代码,
clipboard.png这一块都是自动生成的,虽然也可以实现效果,但是麻烦,写起来也不优雅!我就重新自己写了一次。原理都是注释那里!你自己在浏览器上运行一下,调试下(打断点调试或者在代码中输入debugger;)就知道怎么回事了!
需要提醒的有两点,1.我的做法是利用事件委托原理时间委托原理2。2.target是鼠标点击的那个点的最底层元素。看下面的图如果鼠标点击白色区域,那个target就是body元素,鼠标点击绿色区域target就是div元素,鼠标点击蓝色区域target就是ul,点击橙色就是li。

clipboard.png

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            ul {
  list-style: none;
  margin: 12px 0;
}

li {
  display: inline-block;
  cursor: pointer;
  margin-left: 10px;
  color: blue;
}

h4 {
  display: inline-block;
  margin: 0;
}

.choose-little {
  border: 1px solid gray;
  line-height: 32px;
  display: inline-block;
  padding: 0 5px;
  cursor: pointer;
  font-style: italic;
  margin-right: 10px;
}

span {
  color: red;
}
        </style>
    </head>
    <body>
  <ul id="price">
    <h4>价格:</h4>
    <li>0-299</li>
    <li>300-699</li>
    <li>700-1099</li>
    <li>1100-1999</li>
    <li>2000-3599</li>
    <li>3600-4299</li>
  </ul>
  <hr>
  <ul id="kind">
    <h4>类别:</h4>
    <li>文件夹</li>
    <li>办公套装</li>
    <li>文件筐</li>
    <li>美工刀</li>
    <li>三针一线</li>
    <li>票夹</li>
  </ul>
  <hr>
  <ul id="brand">
    <h4>品牌:</h4>
    <li>得力</li>
    <li>齐心</li>
    <li>有比例</li>
    <li>三木</li>
    <li>GBC</li>
    <li>李蓝</li>
  </ul>
  <hr>
  <div id="choose-box">
      
  </div>
  
</body>
<script type="text/javascript">

    window.onload=function(){
        var obj={
            price:'',
            kind:'',
            brand:''
        }
        var oUl=document.getElementsByTagName("ul"),oDiv=document.getElementById("choose-box");
        //为ul绑定事件
        for(var i=0,len=oUl.length;i<len;i++){
            oUl[i].addEventListener("click",function(e){
                var ev=e||window.event;
                var target=ev.target||ev.srcElement;
                //如果target是li元素
                if(target.tagName.toLowerCase()==='li'){
                    var sib=siblings(target,"li");
                    for(var i=0,len=sib.length;i<len;i++){
                        sib[i].style.display="inline-block";
                    }
                    target.style.display="none";
                    //执行方法
                    doClcik(target.innerHTML,this.id)
                }
            })
        }
        oDiv.addEventListener("click",function(e){
            var ev=e||window.event;
            var target=ev.target||ev.srcElement;
            //如果target是span
            if(target.tagName.toLowerCase()==='span'){
                //根据定义的data-type属性!如果data-type=peice;就相当于设置obj.peice="",ulId='peice';
                var ulId=""
                if(target.parentNode.dataset){
                    obj[target.parentNode.dataset.type]="";
                    ulId=target.parentNode.dataset.type;
                }
                else{
                    obj[target.parentNode.getAttribute("data-type")]="";
                    ulId=target.parentNode.getAttribute("data-type");
                }
                //根据ulId查找ul,再查询该ul下的所有li,并且显示出来
                var oLi=document.getElementById(ulId).getElementsByTagName("li");
                for(var i=0,len=oLi.length;i<len;i++){
                    oLi[i].style.display="inline-block";
                }
                //删除这个元素的父元素!就是div
                oDiv.removeChild(target.parentNode)
            }
        })
        //查找兄弟节点 如下面代码
        //html以下元素  <div><p id="p1"></p><div id="div1"></div><span id="span1"></span></div>
        //oDiv1=document.getElementById("div1")
        //oP1=document.getElementById("p1")
        //oSpan1=document.getElementById("span1")
        //siblings(oDiv1), 返回一个数组[oP1,oSpan1]
        //siblings(oDiv1,"#p1"), 返回一个数组[oP1]
        //siblings(oDiv1,"span"), 返回一个数组[oSpan1]
        function siblings(obj,opt) {
            var a = []; //定义一个数组,用来存o的兄弟元素
            var p = obj.previousSibling;
            while (p) { //先取o的哥哥们 判断有没有上一个哥哥元素,如果有则往下执行 p表示previousSibling
                if (p.nodeType === 1) {
                    a.push(p);
                }
                p = p.previousSibling //最后把上一个节点赋给p
            }
            a.reverse() //把顺序反转一下 这样元素的顺序就是按先后的了
            var n = obj.nextSibling; //再取o的弟弟
            while (n) { //判断有没有下一个弟弟结点 n是nextSibling的意思
                if (n.nodeType === 1) {
                    a.push(n);
                }
                n = n.nextSibling;
            }
            if(opt){
                var b=[];//定义一个数组,用于储存过滤a的数组
                if(opt[0]==='.'){
                    b=a.filter(function(item){return item.className===opt});
                }
                else if(opt[0]==='#'){
                    b=a.filter(function(item){return item.id===opt});
                }
                else{
                    b=a.filter(function(item){return item.tagName.toLowerCase()===opt});
                }
                return b;
            }
            return a;
        }
        function doClcik(_html,_id){
            //初始化html
            var chooseText='';
            //根据_id参数判断是价格,类别还是品牌。如果是价格,就设置obj.peice=_html;
            switch(_id){
                case 'price':obj.price=_html;break;
                case 'kind':obj.kind=_html;break;
                case 'brand':obj.brand=_html;break;
            }
            //遍历_html对象
            for(var k in obj){
                //如果obj[k]的值不为空,比如obj.peice不为空
                if(obj[k]){
                    //chooseText累加html代码,比如k为price,就累加<div class="choose-little" data-type="price">价格:<span>'+obj[k]+'x</span></div>
                    switch(k){
                        case 'price':chooseText+='<div class="choose-little" data-type="price">价格:<span>'+obj[k]+'x</span></div>';break;
                        case 'kind':chooseText+='<div class="choose-little" data-type="kind">类别:<span>'+obj[k]+'x</span></div>';break;
                        case 'brand':chooseText+='<div class="choose-little" data-type="brand">品牌:<span>'+obj[k]+'x</span></div>';break;
                    }
                    
                }
            }
            //最后一起添加进choose-box
            oDiv.innerHTML=chooseText;
        }
        
    }
</script>
</html>

最后,给个建议,如果你看懂了我上面的代码,根据我上面的判断逻辑,改你原来的代码,实现同样效果!虽然我并不建议你那样写,这里只是一个练手作用!然后,把我的js删除了,自己再写一篇(你觉得怎么方便,怎么写)。相当于一个练习题,理解js逻辑的一步

问题1可以使用对象去保存相应的节点引用,触发了事件就去查询一下对象,查询到有激活的div就将他删除

问题2 可以在HTML中创建三个div 给他们不同的名字 不设置宽度,顺序固定,你的元素往里面不同的div插入就可以,让子元素自动撑开他们

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题