出现原因:页面上通过jQuery或其他方式添加某些新元素,而新元素无法和页面第一次加载的事件进行绑定。
例如:对button添加一个点击事件,当通过jQuery添加一个新的button元素时,就可能无法触发这个事件。
delegate() 方法的事件可以处理当前或者未来元素(比如有脚本创建建的新元素)
$(document).delegate("[id='support']","click",function(){ alert('点击成功~'); });
此方法是根据下滑高度加一个值大于当前页面高度来判断的,所以使用时需要自行监测滑动高度和当前页的高度,修改800这个数值具体大小。
$(function() { $(document).scroll(function() { var scrollHeight = $(document).height(); console.log('当前高度:'+$(document).scrollTop(),'页面高度'+scrollHeight) if ($(document).scrollTop()+800 >= scrollHeight) { console.log('到底了~') } }) })
在js代码中写入debugger,回到浏览器F12打开检查窗口,触发js后从debugger开始调试,按F10执行一行代码,并在代码后面显示数值。
使用 debugger 语句类似于在代码中设置断点。
先说一下结论:[1, NaN, NaN],造成这样的原因是什么呢?
首先要先理解函数的意义,map()是将数组的每个元素传递给指定的函数处理,并返回处理后的数组,原数组不改变。单纯这样看可能就会出现脑子里一开始的答案[1,2,3],但为什么不是呢,重点来了!
map()函数是将1,2,3作为元素,和下标0,1,2分别传递给parseInt()函数,其实每个效果写出来就是:parseInt('1',0),parseInt('2',1),parseInt('3',2)的结果。parseInt()函数第二个参数的意义是指明前面参数的进制,从而转化成十进制输出,区间范围是0和2-36,默认是十进制也就是0。0默认是十进制所以1还是1,1不在有效范围内所以2变成NaN,2要求前面的参数必须以二进制0和1开头开始,所以也是NaN。
先上一段代码,假设页面中有4个li标签猜猜输出什么?
var elements=document.getElementsByTagName('li'); var li_length=elements.length; for (var i=0;i<li_length;++i){ elements[i].onclick=function () { alert(i) } }
答案:不管点哪一个一直输出4。
这其实就是事件异步引发的问题,循环过程中对DOM元素事件是绑定成功的,这一点是没有问题的,但是alert中的i却一直是以变量的形式存在的,当i经过一套for循环下来后最终的值变成了4,所以当点击事件触发,去调用i这个值时,是调用的当前变量内容,而不是覆盖之前的变量内容。
其实可以更明显一点,直接在循环外面去改变i的值,比如说在for循环下面给i赋值为999,那么当你触发点击事件时就会输出999;
先上一段代码猜猜输出什么?
var arr=[]; arr[1]=9; arr[3]=99; arr[9]=999; arr['a']='b'; arr['c']='d'; console.log(arr.length)
答案:10。
这里length实际上是根据数组的下标获取,而数组下标是从0开始的,所以这里获取最大下标9,然后加1最终返回的结果10。假设没有任何一个数值下标的元素,则就会输出0。
其实在js中数组的下标是不能存在字符串的,但如果我们尝试着把字符串作为下标使用,其实js会把这个认为是属性来看待,就像我们的对象一样,以键值对的形式存在。
有些代码不是单纯赋值之后就会分割成两个个体。
var arr=[1,2,3,4,5]; var arr2=arr; arr[1]=999; console.log(arr2[1])//999
这里虽然看上去是把arr的值赋给了arr2,实际上只是把arr的地址赋给了arr2,所以当我们改变arr的值时,arr2对应的值也会改变。
要想完全复制出来一份数组可以用以下方式:
var arr=[1,2,3,4,5]; var arr2=[...arr]; arr[1]=999; console.log(arr2[1])//2
every()和some()都是迭代函数,二者都是接受一个返回值为布尔值的自定义函数,对数组中的每个元素使用该函数,最终every()或some()返回一个布尔值。不同的是every()要求数组中的每个元素通过自定义函数时都返回true,那every()本身才会返回true,而some()中的自定义函数只要有一个返回true,则some()就会返回true。
function isEven(num) { return num % 2 == 0; } var nums = [2,4,6,8,10]; var nums2 = [2,4,7,8,10]; var nums3 = [1,3,5,7,9]; console.log(nums.every(isEven));//true console.log(nums2.every(isEven));//false console.log(nums2.some(isEven));//true console.log(nums3.some(isEven));//false
而filter()也是迭代函数,和every()类似,但是他返回的不是布尔值,而是经过自定义函数返回值为true的元素。
function isEven(nums){ return nums%2==0; } var arr=[1,2,3,4,5,6,7,8,9]; var arr2=arr.filter(isEven) console.log(arr2)//[2,4,8]
ajax也分很多种,本人用的最多的是jQuery的Ajax,这篇文章就大概说一下相关的知识点。
首先下面是常用的ajax使用方式,其中的参数也是经常用到的:
$.ajax({ type:"post/get", url:"url", async:true/fasle, dataType:"json", processData:"true", contentType:"application/x-www-form-urlencoded", data:{ value_name:value }, success:function (data,status,ajaxclass) { //处理返回的数据 }, error:function () { //ajax失败时执行的方法 } })
type:
传值类型,分为POST和GET两种,不区分大小写,默认为GET。
实际上put、delete等传值方式也能使用,但仅部分浏览器支持。
url:
发送请求的地址
async:
是否异步,不写该属性时默认true。(异步是多线程,同步是单线程)
设置为true时,所有请求为异步。设置为false时,所有请求未同步。
注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
data:
发送到请求地址的数据,将自动转换为请求字符串格式。
单个值可直接写。例如name,接口可以接受到name这个值。
多个值用json格式。{参数名:值,参数名:值,……}的形式,或者直接写变量名{变量1,变量2,变量3,……}。
success:
当请求运行成功时的回调函数,并返回根据 dataType 参数进行处理后的数据。
参数一:data(这里参数名称任意)即为返回的值
参数二:status(这里参数名称任意)返回ajax的执行状态,这里返回success
参数三:ajaxclass(这里参数名称任意)返回当前ajax对象的一些数据。
error:
当请求运行失败时的回调函数,一般用作请求地址响应失败时给予用户报错提示。
dataType:
请求返回后要处理成的数据类型。常用值:
"xml": 返回 XML 文档,可用 jQuery 处理。
"html": 返回纯文本 HTML 信息;包含的 script 标签会在插入 dom 时执行。
"script": 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了 "cache" 参数。注意:在远程请求时(不在同一个域下),所有 POST 请求都将转为 GET 请求。(因为将使用 DOM 的 script标签来加载)
"json": 返回 JSON 数据 。
"jsonp": JSONP 格式。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。
"text": 返回纯文本字符串
processData:
参数值为true或false,默认为true
一般情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是一个字符串),都会处理转化成一个查询字符串,以配合默认内容类型“application/x-www-form-urlencoded”。
如果发送DOM树信息或其他不希望转换的信息,则需要设置为false。
此属性在使用FormData进行data传值时属性值必须为false
contentType:
默认值“application/x-www-form-urlencoded”,是发送信息至请求地址时内容编码类型。
此属性在使用FormData进行data传值时属性值必须为false。
end,waiting for update……
相关知识扩充:
①如果不加此参数,会出现不可预知的错误!
比如某些加了安全控件的系统,不加此参数,会直接报错403,服务器认为你的此次请求是在攻击系统。
②当ajax上传文件时,我们查看Request headers:
这时会发现content-Type这个的参数是multipart/form-data后面还会有boundary再接着一串随机字符串。
前面的参数我们并不陌生,这是form表单上传文件必须的参数,而后面的参数是当我们上传文件时,系统会自动生成一堆随机字符串,也叫分界符,目的是为了防止文件中出现分隔符导,最终致请求地址的服务器无法正确解析文件的起始位置。
换言之就是,文件传输中本质还是文件流传输(其实也就是字符代码的传输),这样就需要与其他非文件参数进行区分,而boundary生成的这个复杂随机字符串就是为了将文件流与其他参数区分开来,而将contentType设为false是为了防止jQuery对数据进行二次编码,从而失去分界符,最终导致请求地址的服务器无法正常解析文件。
按默认值也就是true,会将上传的数据转换为字符上传,而当上传文件的时候,则不需要把其转换为字符串,因此就要关闭此转换功能,也就是设置为false。
QueryList是一套用于内容采集的PHP工具,它使用更加现代化的开发思想,语法简洁、优雅,可扩展性强。相比传统的使用晦涩的正则表达式来做采集,QueryList使用了更加强大而优雅的CSS选择器来做采集,大大降低了PHP做采集的门槛,同时也让采集代码易读易维护。
QueryList是直接获取的页面上的元素内容,而不是直接获取api中的内容。
网址:https://querylist.cc/,新版环境要求php>=7.1
composer安装命令:
composer require jaeger/querylis
如果上面的composer命令太慢,请使用国内镜像:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
说明:当时使用时是在tp5中测试使用的,所以下面的内容都是基于tp5进行举例的。
$ql=QueryList::get($src);
$data=$ql->find('div')->attr("id");//获取页面上一个div的id值
QueryList有个find()方法,用于采集单个元素,它通过jQuery选择器选择DOM元素,用法同jQuery的find()方法。
$ql=QueryList::get('https://www.iqshw.com/'); //获取第一张图片的链接地址,下面四种方法完全等价 $data[]=$ql->find('div')->attr('src'); $data[]=$ql->find('div')->src; $data[]=$ql->find('div:eq(0)')->src;//等推获取第n张:img:eq(n-1) $data[]=$ql->find('div')->eq(0)->src;//等推获取第n张:eq(n-1) //获取其他属性值 $data[]=$ql->find('div')->alt; //获取其它自定义属性值,只能获取一种 //获取所有属性值 $data[]=$ql->find('div')->attr("*"); //获取元素下的HTML内容 $data[]=$ql->find('#id')->html(); $data[]=$ql->find('#id .class')->html(); //获取其它自定义属性值,只能获取一种 //获取元素下的纯文本内容 $data[]=$ql->find('.class')->text();
获取多个元素的单个属性值(QueryList中凡是涉及到集合的地方返回的都是Collection集合对象,这个对象有个all()方法,用于把当前对象转成数组,所以你会发现下面很多写法都是$data->all() )
$ql=QueryList::get('https://www.iqshw.com/'); //获取所有图片的src属性值 $data[]=$ql->find('img')->map(function ($item){ return $item->src; })->all(); //等价与下面这句话 $data[]=$ql->find('img')->attrs('src')->all(); //获取元素中所有的html内容和text内容 $data[]=$ql->find('#id')->htmls()->all(); $data[]=$ql->find('.class')->texts()->all();
列表采集才是QueryList的核心功能,这里主要涉及到两个函数的用法:rules()和range()
$rules = [ '规则名1' => ['选择器1','元素属性'], '规则名2' => ['选择器2','元素属性'], // ... ]; //代码示例: $ql=QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules=[ //采集标题 'title'=>['.postTitle2','text'], //采集内容 'text'=>['.c_b_p_desc','text'], //采集时间 'time'=>['.dayTitle','text'] ]; $data=$ql->rules($rules)->query()->getData()->all(); //等同于上面 $data=$ql->rules($rules)->queryData();
用range()函数来配合rules()进行循环采集列表内容,range()函数的作用是选择一个元素作为多个数据之间的“切片”。
$ql=QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules=[ //采集标题 'title'=>['.postTitle2','text'], //采集内容 'text'=>['.c_b_p_desc','text'], //采集时间 'time'=>['.dayTitle','text'] ]; $range='.day';//切片选择器 $data=$ql->rules($rules)->range($range)->query()->getData()->all();
利用remove()来过滤不需要的内容:
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //移除选中html中的a标签 $data = $ql->find('.c_b_p_desc:eq(0)')->remove('a')->html(); //只保留a标签中的html内容 $data = $ql->find('.day:eq(0)')->find('a')->remove()->html();
列表采集时过滤不需要的元素,使用规则:
$rules = [ '规则名1' => ['选择器1','元素属性','内容过滤选择器'], '规则名2' => ['选择器2','元素属性','内容过滤选择器'], // ... ];
内容过滤选择器参数不光可以定义要移除的内容还可以定义要保留的内容,多个值之间用空格隔开, 有如下2条规则:
内容移除规则:选择器名前面添加减号(-),表示移除该标签以及标签内容。
内容保留规则:选择器名前面没有减号(-)(此时选择器只能为HTML标签名,不支持其他选择器), 当要采集的[元素属性] 值为text时表示需要保留的HTML标签以及内容,为html时表示要过滤掉的 HTML标签但保留内容。
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], //采集内容 'text' => ['.c_b_p_desc', 'html','-a'], //采集时间 'time' => ['.dayTitle', 'text'] ]; $range = '.day';//切片选择器 $data = $ql->rules($rules)->range($range)->query()->getData()->all();
获取到数据后进行二次处理:
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], //采集内容 'text' => ['.c_b_p_desc', 'html'], //采集时间 'time' => ['.dayTitle', 'text'] ]; $range = '.day';//切片选择器 $data = $ql->rules($rules)->range($range)->query()->getData(function($item){ $qls = QueryList::html($item['text']); $qls->find('a')->remove(); $item['content'] = $qls->find('')->html(); return $item; })->all();
$ql = QueryList::get('https://www.iqshw.com/'); //定义采集规则 $rules = [ //采集标题 'title' => ['a', 'text'], ]; $range = 'li';//切片选择器 //乱码处理,设置输出编码 $data = $ql->rules($rules)->range($range) ->encoding('UTF-8','GB2312') ->query()->getData()->all(); //如果设置输出参数无法解决乱码,那就使用removeHead()方法移除html头部 $data = $ql->rules($rules)->range($range) ->removeHead()->query()->getData()->all(); //或者 $data = $ql->rules($rules)->range($range) ->encoding('UTF-8','GB2312') ->removeHead()->query()->getData()->all(); //手动转码 $html=$text=iconv("GB2312","UTF-8",file_get_contents('https://www.iqshw.com/')); $data = QueryList::html($html)->rules([ 'title' => ['.news-comm-wrap a ', 'text'], ])->range($range)->query()->getData()->all();
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], ]; $range = '.day';//切片选择器 //使用flatten()方法将多维集合转为一维的 $data = $ql->rules($rules)->range($range)->query()->getData()->flatten()->all();
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], ]; $range = '.day';//切片选择器 //take()方法返回给定数量项目的新集合,对最初的采集结果data进行处理: $data = $ql->rules($rules)->range($range)->query()->getData()->take(2)->all();
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], ]; $range = '.day';//切片选择器 //使用reverse()来倒转集合中的项目 $data = $ql->rules($rules)->range($range)->query()->getData()->reverse()->all();
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], ]; $range = '.day';//切片选择器 //filter()方法用于按条件过滤数据,只保留满足条件的数据。 //只能过滤,不能修改添加原数据,如果需要修改添加则用getData $data = $ql->rules($rules)->range($range)->query()->getData() ->filter(function ($item){ return $item['title']!='PHP使用引用实现无限极分类'; })->all();
$ql = QueryList::get('https://www.cnblogs.com/yulongcode/'); //定义采集规则 $rules = [ //采集标题 'title' => ['.postTitle2', 'text'], ]; $range = '.day';//切片选择器 //map() 方法遍历集合并将每一个值传入给定的回调。 //该回调可以任意修改项目并返回,从而形成新的被修改过项目的集合。 $data = $ql->rules($rules)->range($range)->query()->getData() ->map(function ($item){ $item['time']=time(); return $item; })->all();
attr()方法除了获取DOM元素的值外,还有第二个参数,用于设置元素属性值
text()方法是获取元素的纯文本内容,加参数表示设置元素内容
html()方法是获取元素的HTML内容,加参数表示设置元素HTML内容
以上三个用法基本和jQuery相同,添加完后再获取,才会出现在获取的数据中。
append()追加元素
replaceWith()替换元素
removeAttr()移除元素属性
parent()用户获取当前元素的父级元素
next()和prev()用于获取当前元素临近的下一个元素和上一个元素
更多使用说明请查看使用文档。