IFE斌斌学院-JS总结(2)

时间:2022-12-26 14:09:45

我的github代码地址

任务一 : 模拟一个队列,队列的每个元素是一个数字,初始队列为空有一个input输入框,以及4个操作按钮,完成左侧入,左侧出,右侧入,右侧出,以及点击数字删除的功能

  • 首先需要四个函数, function leftEnter(), functionrightEnter(), function leftOut(),rightOut() 分别实现队列操作,而js刚好有四个函数分别对应着四种操作

    • shift:从数组中把第一个元素删除,并返回这个元素的值。
    • unshift: 在数组的开头添加一个或更多元素,并返回新的长度
    • push:在数组的中末尾添加元素,并返回新的长度
    • pop:从数组中把最后一个元素删除,并返回这个元素的值。
  • 所以只需要给四个按钮绑这四个函数,在传入arr就可以了。但是在调用四个函数之前,需要做好流程控制

    • 如果input框为输入为空,则弹出alert提示。if(newNum.value != '' || null){ leftEnter(list,newNum,box); }else{alert('不能为空');}以及在
    • 如果队列长度已经为0,则不能继续删除元素if(list.length != 0){alert('你删除了第一个元素' + ' ' + leftOut(list,box));}else{alert('队列已为空');}
  • 由于每次队列更新以后需要更新dom,所以,需要一个dom操作的方法,function List(),当时我的考虑是,其实大部分dom节点是不改变的,所以没有必要每次都重新渲染全部dom,但是,没有找到合适的方法去只添加新增dom,所以还是采取遍历list,然后重新渲染dom。

  • 然后点击元素,就从list中删除这个元素。
    • 第一考虑,需要一个 function removeSelf(),然后用arr.splice(loca,1);删除loca这个位置开始的一个元素,就是点击的元素本身。
    • 第二考虑,需要给每一个元素绑定一个事件,这里就需要用到闭包了。按照我的想法就是,通过传入n,用e来代理这个n,相当于用一个变量存储n这个值。至于理由点这里

      for(var n = 0; n < members.length;n ++){
      (function(e){
      members[e].addEventListener('click',function(){
      removeSelf(arr,e,parentNode);
      });
      })(n);
      }
  • 然后自己也是沿用的init()初始函数,在里面获得需要的dom元素,如按钮等。

小结:所以每一个方法操作了数组改变了list之后,都需要重新渲染dom,我认为是很不可取得,但是我是没想出好的解决方法的。

任务二 :

  • 基于上一任务
  • 限制输入的数字在10-100
  • 队列元素数量最多限制为60个,当超过60个时,添加元素时alert出提示
  • 队列展现方式变化,直接用高度表示数字大小
  • 实现一个简单的排序功能,如冒泡排序(不限制具体算法),用可视化的方法表达出来

    1. 针对限制数字输入,我采用了正则表达式,考虑的是用test()方法,匹配满足正则表达式的值,10-100,我想的是只要是两位数字以及一个100就可以通过,所以var reg = /^\d{2}$|100/gi; if(newNum.value != '' && reg.test(newNum.value)){ leftEnter(list,newNum,box);}else{alert('输入框不能为空,请输入10-100之间的数字'); }出现了一个bug,应该是正则表达式的问题,总之是秘制bug,打印正则表达式的值为true,但是却没有办法进入if语句,以及控制台调试的时候显示false,总之就偶尔可以进入if偶尔不可以,所以只能放弃正则,单纯的用>10 <100来控制就没有问题了然后队列长度小于60就是一个length
    2. 然后队列的展示方式需要类似用一个柱状图来模拟,这个就是在插入dom节点以后,members[n].style.height = arr[n] + 'px';
    3. 实现一个简单的排序,这个才是我真正烦恼的地方,实现一个排序,按理说只需要添加一个函数,然后,排序后再次渲染dom就可以实现,可是要求是要动态的展示,就是要把每一步都慢慢的展示出来,可是在数据量很小的情况下,for循环真是一眨眼的功夫,我想到了用闭包+setTime的方法,可是也并不能实现渲染dom延迟,只能实现打印arr是延迟打印的。实现打印延迟的原理

      function sort(arr,parentNode){
      //i用来记录第几次完整的排序,j是记录每一次完整的排序包含多少次小排序
      //而i每增加1,小排序就会减少1,因为每次完整的排序就会把最大的数置于最后
      var save ,m = 1;
      for(var i = 1;i < arr.length;i ++){
      for(var j = 0;j < arr.length - i;j ++,m ++){
      if(arr[j] > arr[j + 1]){
      save = arr[j + 1];
      arr[j + 1] = arr[j];
      arr[j] = save;

      (function(list,count) {
      setTimeout(function() {
      // console.log(count);
      List(list,parentNode);
      }, 100 * count);
      })(arr,m);
      }
      }
      }
      }
  • 还有就是有些细节也要注意,比如,最初的时候如果list中有数据,就要进行初次渲染if(list.length > 0){List(list,box);}给每个数字绑定方法一定要在dom插入结束之后parentNode.innerHTML = boxCon;还有一个就是,input.value取值,取出的值是一个字符,直接push进数组[‘1’,’2’,3,4,5];这样的形式存在,在后面排序的时候会出现问题,所以需要用parseInt转化一下。

小结:这位大神实现了,我现在去拜读一下代码,还有就是,如果有时间有记性的话,我想总结一下关于排序算法。真是觉得自己笨惨了。

拜读代码总结,不看不知道一看吓一跳,这位大神的写法真是闻所未闻,高超啊,我后来看了一下,用了ES6,虽然大神的实现我还是无法复制,但是,还是收获了很多,我看了三个小时啊!!

  • <input type="number" id="aqi-input" min='10' max='100' /> 这样虽然还是需要验证是否满足10-100,但是算是一个为用户考虑的做法。
  • 大神是这样绑定点击事件的,脱离了我一个一个绑定事件的低级趣味。还有=+这种第一次见得方法,没有办法,我是低级趣味
 //绑定四个简单操作
document.getElementById("bts").addEventListener("click",function(e){//利用冒泡父代理子元素的事件;
var id = e.target.id||e.srcElement.id;
//因为btn的id为id='bt1',所以截取后面的数字
//=+ js语法的一种特殊写法,相当于把i转换成数值类型,因为后文的switch使用。
id =+ id.slice(2);
switch(id){
case 0:leftJoin();break;
case 1:rightJoin();break;
case 2:leftOut();break;
case 3:rightOut();break;
return ;
}
//调用自定的painting函数,创建自定义事件,然后在需要渲染列表的时候,监听这个事件,来调用painting函数
painting();
},false);
  • 大神给每一个li绑定点击删除事件,也是用的很清新的方式,然后index属性,实在生成每一个li的时候就添加了一个index属性
 //给每一个li绑定点击删除事件,但是不是用的遍历绑定,而是借助只有在li标签的index属性,来判断点击的对象
document.getElementById("zhu").addEventListener("click",function (e){
var sdoc = e.target || e.srcElement;
var index = sdoc.index;//只有Li.creat的li有index;
if(index){
delete_docli(sdoc);//不方便由index得知sdoc;so 传递sdoc;
}
},false);
  • 简单的说,其实大神也就是用的面向对象编程,我猜是这样的。只是声明的方式高级了一点,ES6,构造了两个class,一个用来渲染dom,一个用来生成li,我不是特别懂这样的意义,但是,这有什么重要的呢?TOT
  • 然后,在渲染时,也是通过painting方法定义了一个painting事件,然后,全局监听这个painting事件来执行paint方法。
function painting(time){
var evt = document.createEvent("CustomEvent");
evt.times = time;
evt.initEvent("painting",true,true);
window.dispatchEvent(evt);
}
//如果监听到painting自定义事件,执行paint函数
window.addEventListener("painting",function (e){
ultup.paint();
},false);
  • 总之,如果有一天我能写到这种水平,O(∩_∩)O~
  • 然后我真的认真观察了一下大神是如何实现动态展示排序过程的,首先,大神用的冒泡方式和我连续用了两个for是不一样的,大神只用了一个for,然后for循环完成以后,在进行渲染,这样,其实也没有实时改变,然后,再利用递归调用了排序方法本身,这样就可以部分动态了。其实还是排序思路的问题。
    注意了新的思路可以实现了,就是,不在排序函数里面调用函数,而是在点击事件内调用排序函数之后,再调用渲染函数。上代码~
var sortBtn = document.getElementById('sortArr');
//定义全局计时器
var time;

sortBtn.addEventListener('click',function(){
//排序
sort(list);
//清除计时器
clearTimeout(time);
//调用slow方法
time = setTimeout(slow,500);
function slow() {
//取出第一个子元素,而这里的第一个子元素就是我们需要的arr
//这里需要在排序函数if语句的最后一步,把原本的arr赋值给新的newList --- newList.push(arr.slice(0));slice把arr值传递给newList,避免了对arr的引用
var wait = newList.shift();
//在最后一步中,排序已经结束,但是还要执行一次,这是wait就是undefined
if (wait != undefined) {
List(wait,box);
time = setTimeout(slow, 500);
} else {
clearTimeout(time);
}
}
});

任务三:

  • 基于任务四进行升级
  • 将新元素输入框从input改为textarea
  • 允许一次批量输入多个内容,格式可以为数字、中文、英文等,可以通过用回车,逗号(全角半角均可),顿号,空格(全角半角、Tab等均可)等符号作为不同内容的间隔
  • 增加一个查询文本输入框,和一个查询按钮,当点击查询时,将查询词在各个元素内容中做模糊匹配,将匹配到的内容进行特殊标识,如文字颜色等。举例,内容中有abcd,查询词为ab或bc,则该内容需要标识