一、普通函数与自执行函数的区别
例1:
$('#btn').click(function(){
$('.box').animate({
width:"500px",
height:"200px"
},2000,function(){
console.log('执行完成了');
})
});
例2:
$('#btn').click(
$('.box').animate({
width:"500px",
height:"200px"
},2000,function(){
console.log('执行完成了');
})
);
思考:在手撸jQuery中遇到了这个问题,普通函数与自执行函数的区别我当然知道,一个需要调用或触发才能执行,一个自动执行。当时突然蒙圈了一下,不知道什么叫做自执行函数了,不是不明白他的定义,而是对于它的使用位置方式产生了疑惑,典型的眼高手低。
例1与例2的代码是基本一样的,想要达到的要求是点击一个按钮,盒子大小发生变化,同时控制台输出“执行完成了这句话”
例2是我自己手撸的,测试发现,不需要点击就自动执行了,当时陷入了误区,后面才判断出来这个肯定是自执行了,因为控制台并没有报错。既然自执行,那么必然click里面是一个自执行函数,整个click监听事件并没有起作用,对比例1可以发现,例1是给click事件绑定了一个回调函数,等点击事件触发后,才会执行回调函数中的内容,出错原因就在这里。
二、js下获取某个父元素的子元素数量,并给每个子元素绑定事件(2021-05-12)
li{
width: 100px;
height: 60px;
background-color: pink;
margin-top: 10px;
list-style: none;
text-align: center;
line-height: 60px;
font-size: 30px;
}
<script src="./jquery.js"></script>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
//js下获取某个父元素的子元素数量,并给每个子元素绑定事件==>什么元素不重要,子元素数量也不重要,绑定什么事件也不重要
/* 第一种 原生方式 */
let ulObj = document.querySelector('ul');
console.log(ulObj.children.length);//输出的是HTMLCollection 一个集合的形式,伪数组,只有数组的length属性,没有相应的方法
console.log(Array.from(ulObj.children));//利用Array.from()将伪数组转成真数组,这时可以使用其中的方法了
/* Array.from(ulObj.children).forEach(v=>{
v.addEventListener("click",()=>{
console.log(v.innerHTML);
})
}) */
/* 第二种 利用JQuery方式 */ //利用children或find后代选择器,使用on绑定
console.log($('ul').children());
$('ul').children().on('click',function(){
console.log(this.innerHTML);
})
</script>
三、正则表达式
question:1: sadfasf2: fsahdfiewhi3: fdgajgnas15: 4645das5faadsfi4: asidnaskl
需要正则的问题如上,需要匹配的就是数字+英文冒号+一个空格,将其变为一个英文逗号(注:此问题从数组对象中提炼出来)
先复习下正则相关知识:
正则表达式
一、转义符
\d 表示0-9数字
\D 表示非数字
\w 数字字母下划线
\W 非数字字母下划线
\s 空格
\S 非空格
二、量词
* 表示至少0次
+ 表示至少一次
?表示最多一次
{n} 表示固定n次
{n,} 表示至少n次
{n,m} 表示n到m次之间的任何次数都可以接受;至少n次,至多m次
三、修饰符
g 全局匹配
i 忽略大小写
四、或
| 表示或
五、子集
( ) 表示子集
六、范围符
- 表示范围
七、中元符
[ ] 用来标记范围,内部所有组成都是或的关系
ok,首先是匹配1到2位的数字 \d{1,2},接着是英文的冒号\W{1},最后是一个空格\s{1} 如果想更安全,更准确,可以加上开始(^)与结束符($),结合起来写就是:^\d{1,2}\W{1}\s{1}$
正则只有常用,才会不经意间记住,特意去记反而没有什么用户,还有记住他们的特点和区别也非常重要。
四、前端经常出现的兼容问题
页面滚动条距离顶部的距离
document.documentElement.scrollTop || document.body.scrollTop
页面滚动条距离左边的距离
document.documentElement.scrollLeft || document.body.scrollLeft
获取当前网页可显示区域宽度
document.documentElement.clientWidth || window.innerWidth
获取当前网页可显示区域高度问题:ie有兼容性问题解决:
document.documentElement.clientHeight || window.innerHeight
获取event事件 event需要逐层传递,不要疏忽外部的function!!!!!
IE中: window.event
正常浏览器中:对象.on事件 = function(event){}
兼容方式:
function fn(eve){
var e = eve || window.event;
}
eg: document.onclick = function(eve){
var e = eve || window.event;
}
获取按下的键码
var keyC = eve.keyCode || eve.which
IE只有keyCode属性,
FireFox中有which和charCode属性,
Opera中有keyCode和which属性,
Chrome中有keyCode、which和charCode属性
获取非行内样式(兼容问题) getComputedStyle(obj).height
function getStyle(obj,attr){ 获取非行间样式,obj是对象,attr是值
if(obj.currentStyle){ 针对ie获取非行间样式
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr]; //针对非ie
};
};
阻止默认事件
e.preventDefault();
e.returnValue = false;
return false
处理兼容方式
if( e.preventDefault ){
e.preventDefault();
}else{
e.returnValue = false;
}
或者直接
obj.onclick = function(){
return false;
}
冒泡:从下往上(从里往外)
捕获:从上往下(从外往内)
阻止事件冒泡
eve.stopPropagation();
eve.cancelBubble = true; //兼容IE
if(eve.stopPropagation){
eve.stopPropagation()
}else{
eve.cancelBubble = true;
}
事件委托
通过e.target获取触发事件的事件源
利用事件冒泡原理,将绑定在多个子元素身上的相同事件,绑定在页面上现存的父元素身上。
var e = eve || window.event;
var target = e.target || e.srcElement;
oul.onclick = function(eve){
var e = eve || window.event;
var target = e.target || e.srcElement;
if(target.nodeName == "LI"){
console.log(target.innerHTML);
}
}
DOM2级事件绑定
事件监听器
非IE下
obj.addEventListener('click',fn,false);
obj.removeEventListener('click',fn ,false);
IE下:只有冒泡阶段,所以没有第三个参数;(这里的事件名需要加on)
obj.attachEvent();
obj.detachEvent() ;
兼容问题解决:
1.封装成对象的方式
var EventUtil={
addHandler:function(DOM,EventType,fn){
if(DOM.addEventListener){
DOM.addEventListener(EventType,fn,false);
}else if(DOM.attachEvent){
DOM.attachEvent('on'+EventType,fn)
}else{
DOM['on'+EventType]=fn
}
},
removeHandler:function(DOM,EventType,fn){
if(DOM.removeEventListener){
DOM.removeEventListener(EventType,fn,false)
}else if(DOM.detachEvent){
DOM.detachEvent('on'+EventType,fn)
}else{
DOM['on'+EventType]=null;
}
}
}
2.封装成两个函数的方式
function addEvent(obj,inci,back){
if(obj.addEventListener){
obj.addEventListener(inci,back);
}else if(obj.attachEvent){
obj.attachEvent("on" + inci,back);
}else{
obj["on"+inci] = back;
}
}
function removeEvent(obj,inci,back){
if(obj.removeEventListener){
obj.removeEventListener(inci,back,false);
}else if(obj.detachEvent){
obj.detachEvent("on" + inci,back);
}else{
obj["on"+inci] = null;
}
}
浏览器元素的尺寸
offsetParent:获取元素的最近的具有定位属性(absolute或者relative)的父级元素。
如果都没有则回body
offsetLeft:表示元素的 左外边框 至offsetParent元素的 左内边框 之间的像素距离
offsetTop:表示元素的 上外边框 至offsetParent元素的 上内边框 之间的像素距离
offsetWidth/offsetHeight:元素本身实际宽度/高度
offsetWidth = width + 左右padding + 左右border
offsetHeiht = height + 上下padding + 上下border
clientWidth/clientHeight:元素本身可视宽度/高度(客户端)
clientWidth 元素视窗宽度 clientWidth = width + 左右padding
clientHeight 元素视窗高度 clientHeight = height + 上下padding
检测相对于事件源的位置:offsetX和offsetY
当鼠标事件发生时,鼠标相对于事件发生元素左上角的位置
检测相对于浏览器的位置:clientX和clientY
当鼠标事件发生时,鼠标相对于浏览器左上角的位置
检测相对于屏幕的位置:screenX和screenY
当鼠标事件发生时,鼠标相对于屏幕左上角的位置
检测相对于文档的位置:pageX和pageY 带滚动条距离
当鼠标事件发生时,鼠标相对于文档左上角的位置。(IE7/8无)(类似于event.clientX和event.clientY)
2021-05-13
五、js报错Cannot read property ‘innerHTML’ of underfined
报错翻译:无法读取undefined的innerHTML属性
事实上,undefined没有任何属性可以供读取,因此这个报错要考虑是否是有标签节点没有被获取到,因此输出的值是undefined,所以找不到innerHTML属性
example:
//省略前置代码
<ul>
<li class="user">1</li>
<li class="user">2</li>
<li>3</li>
<li class="user">4</li>
<li class="user">5</li>
//简化li标签内容,实际工作场景中每个li标签至少3-5层层级嵌套
</ul>
//省略后序代码
问题:先获取父级元素ul节点,通过遍历其子节点,理论上可以拿到每一个innerHTML与innerText的值,但是无法获取到,反而是报上述错误。。。
排查解决思路:
1.排除是js代码异步加载问题:将js代码放到整个页面最后加载或使用Window.onload方法
2.检查遍历所有子级li标签时是否是都有指定的innerHTML与innerText,js代码加载过程中,只要出现一个未知错误,整个遍历过程便结束,程序代码也会停止执行,抛出对应的错误!
经检查,发现是第二种情况,补一个user类名即可。
六、干掉父元素下所有元素的最简洁方法
//1.js原生方法
父元素.innerHTML = "";
//2.jQuery封装方法
$(父元素).empty();//利用empty方法可以直接排空父元素
//与此对应的是remove方法,直接将整个父元素包括其在内的后代元素全部干掉
七、快排一个数组对象商品列表(对象属性有销量/新旧价格/评论量等)
let arr=[{id:1,num:456,oldPrice:852,newPrice:9.9,comment:866},{id:2,num:358,oldPrice:999,newPrice:9.9,comment:583}]
根据不同要求,进行销量/价格评论数量/综合等排序(详情参考某宝形式)
let arr=[{id:1,num:456,oldPrice:852,newPrice:9.9,comment:866},{id:2,num:358,oldPrice:999,newPrice:9.9,comment:583}]
let arr1=[];
arr.forEach((v,k)=>{
arr1.push([v.id,v.num]);
})
console.log(arr1);//带有商品id与商品销量的二维数组===>乱序
arr1.sort(function(a,b){
return a[1] -b[1];
})
console.log(arr1);//根据数量进行升序
这里拿销量做例子,形成二维数组,进行升序排列,同理,可以形成更多维数组,对比更多不同属性,最后靠商品的唯一标识符区别即可,然后进行商品的重新渲染。
八、localStorage与JSON的不解之缘
JSON.stringify()//对象转为字符串
JSON.parse()//字符串解析为json对象
localStorage.setItem()//设置localStorage,第一个参数是想要设置的key,第二个参数是想要设置的value(可以是对象)
localStorage.getItem()//获取localStorage,接收一个参数,需要获取的key名
后端传给前端的数据一般是json格式的,这就导致前端在拿到数据想放入localStorage时是无法直接用的,强行设置的话,会显示object对象,需要借助JSON.stringify存储到localStorage里面,拿出来时也要反向parse一下