javascript基础总结(下)

在自定义对象中,大部分是比较复杂的,一般用于高级开发中。常用的对象如下:

 

array(数组)对象:

普通对象:

|    属性名    |属性值        |

|    name    |   jiojidoj     |//属性名任意

 

数组对象

|    索引    |    元素    |

|     1        |    456     |//索引为数字,并且按顺序排列,从零往后延伸

 

构造函数创建数组对象:

 

var  array=new Array();

 

//向数组中添加元素

数组[索引]=元素(值)

//获取数组长度

 

数组长度:array.length//是最大索引+1;

非连续的数组,会空置很多数组的位置;除非必要不然不要创建非连续的数组;

 

如果修改了length属性,就会增加计算数组的长度,空间就会变大。如果减少数组长度,空间会减小,会删除后面的元素。

 

向数组的最后一个索引添加元素:arr[arr.length]=值;

 

使用字面量创建数组对象:

var arr=[

 

 

]

//数组时中括号创建,对象是大括号创建。

 

使用字面创建数组时,可以在创建时,就可以创建数组元素。

索引是从0开始计算的。

 

var arr =new Array(123,456,789);

也可以通过构造函数创建数组对象。

 

var arr=[10]//创建只有值为10的数组;

var arr=new Array(10)创建一个长度为10的数组;

 

一般数组的长度在里面没有什么限制,可以在js中添加数组长度。

 

数组中的元素可以是任意的数据类型(包括对象);

 

调用数组中的函数arr[索引]();

调用对数组中的对象arr[索引].属性名或者arr[索引].方法名()

 

数组里还可以放数组:二维数组、三维数组等都可以实现;

 

数组对象的四个方法:

 

push():该方法可以向数组末尾添加一个或多个元素,并返回新数组的长度。

 

可以将想要添加的元素,作为方法的参数传递给数组;

 

该方法会将数组的新的长度返回;

 

向较于arr[arr.length]这个可以一次添加多个值;

 

pop():该方法会删除数组的最后一个元素。并将删除元素作为返回值返回。

 

unshift():向数组开头添加一个或多个元素,并且返回数组新的长度。向前面插入元素之后,其他元素的索引会依次调整。

 

shift():删除数组开头的第一个元素,并将删除元素作为返回值返回。

 

数组的遍历:

 

所谓数组的遍历,就是将数组中元素都取出来。

 

for(var i=0;i<arr.length;i++){

        console.log(arr[arr.length]);

}

 

遍历数组找到满足条件的元素,放到新的数组中返回;

 

function getAdult(arr){

            var newArr=[];

            var p=arr[i];

           for(var i=0;i<arr.length;i++){

                if(条件){

                newArr.push(p);

                        }

       

}

return newArr;

}

 

forEach();这个方法是支持ie8以上的浏览器;如果需要兼容ie8就不要使用forEach,移动端就不用紧。

forEach()需要函数作为参数;

arr.forEach(匿名函数);//如果使用普通函数的话会污染作用域,所以使用匿名函数最为方便;数组中有几个元素就执行几次函数。

每次浏览器都会将浏览器以实参的形式传递到函数中。浏览器会在回调函数创建三个参数,第一个参数是当前正在遍历的元素,第二个参数是遍历的索引号,第三个参数是整个数组对象。

arr.forEach(function(value,index,array){});

 

slice和splice:

 

slice ()可以用来提取数组中的元素。

slicu(start,end)//start,开始位置end,结束位置;

arr.slice(1,3);该方法不会改变原数组,而是将截取到的元素封装到一个新的数组中返回参数;

在start开启索引在end关闭索引。

如第二个参数可以省略不写,表示截下剩余全部;

索引也可以传递负值,表示从数组末尾倒数几个数开始或者关闭索引。

 

splice()用于删除,添加数组中的指定元素。它会对原数组有影响;

多个参数:

第一个表示删除开始索引;

第二个表示删除的数量;只是添加元素的话可以直接将第二个元素设置为0;

第三个参数开始及其以后,;会作为新元素插入到开始索引(第一个参数)的前面;

 

去除数组的重复元素:splice (嵌套for循环);

for(var i=0;i<arr.length;i++){

            console.log(arr[i]);

            for (var j=i+1;j<arr.length;j++){

                if(arr[i]==arr[j]{

                arr.splice(j,1);

                j--;//后面元素顶上来,会跳过删除的元素后面一个元素;需要再比一次;}

)

}

}

 

 

concat()连接两个或者多个数组,返回新的数组,不会对原数组产生影响;

 

join():这个方法可以将数组直接转换成字符串,不会对原数组产生影响,而是将转换的结果作为返回值返回。、

在join传递第一个参数,会将数组元素作为这个参数作为数组元素之间的连接返回,如果不指定,默认使用逗号,作为连接符;

 

reverse()颠倒数组的顺序,翻转数组,该方法会直接修改原数组。

 

sort()也会影响原数组,它默认会按照unicode编码排序;

 

所以如果想对纯数字的数字进行排序,这种默认的情况就不行了,它会将123,首先用第一个字符做排序,123,1234,2,23;

 

sort(function(a,b){return a-b;})

//a表示在前的元素,b为在后的元素,如果返回值大于0,就会交换位置,如果返回等于0,不换位,如果返回负值则不交换位置。a-b>0可见的这是升序排列;

 

函数方法call和apply;这是函数对象的方法;fun函数结构fun()函数功能;

fun.call();

fun.apply();

fun();

都是调用函数:

在调用call和apply可以将一个对象指定为第一个参数;

 

fun.call(obj),也就是说函数的对象是obj;

call()/apply()可以修改这个函数的this;

fun()不行;

 

fun.call(对象,参数,参数)这里的参数是原函数所要传递的参数;

fun.apply(对象,[参数,参数])参数需要封装到数组中;

 

call()和apply()的区别在于是否需要封装到数组中;

 

arguments:

在调用函数是,浏览器默认会传入两个隐含的参数,一个是this,另一个就是封装实参的对象arguments;

 

arguments:是一个类似于数组的对象,它也可以通过索引来操作对象,也可以获取长度,在调用函数时,我们传递的实参都会在arguments中保存;

 

arguments[0]第一个实参,我们即使不定义形参也可以调用实参

 

arguments还有一个属性:arguments.callee这个属性的对应的函数对象,就是当前这个函数对象;

 

Date对象:

在js中使用date对象来表示一个时间;

 

创建一个Date对象:

var d=new Date();

如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间;

 

//创建一个指定时间

var d2= new Date("15/10/2020 16:20:59");

//年份需要填写完整的位数,不然ie浏览器会出错

var date=d2.getDate();//获取当前对象为几号;1——31;

 

var day= d2.getDay();//获取当前对象为周几;   0——6;0表示周日

 

var month=d2.getMonth()://获取当前时间返回的月份0——11;0表示1月

 

var year=d2.getFullYear();//返回当前对象的年份;

 

var time =d2.getTime();//获取当前时间的时间戳,指的是从格林威治1970年1月1日0点0分0秒到现今所经历的毫秒数;方便保存,不然在计算机硬件中各种进制的数需要耗费大量的资源;一般时间都是从时间戳转换过来的;

 

注意这里的是格林威治时间,一般设置时间是本地时间的多少年多少月,如果设置1970年1月1日0时0分0秒会有时区的间隔;

 

利用时间戳测试代码的执行性能:

var d=new Date();

var start=d.getTIme();

代码

 

var end=d.getTime();

代码消耗约end-start秒

 

Math对象:

Math和其他的函数不同,他不是构造函数,它属于一个工具类不用创建对象,它里面封装了数学运算相关的属性和方法;

Math.PI表示圆周率;相对于自己写的要更精确一点;

 

abs()可以用于一个数的绝对值;

ceil()对数进行上上舍入;也就是向上取整;小数位只要有值就会自动进一;

floor()对数进行向下取整;小数部分就会舍去;

parseInt对字符串,floor()是对数值的效率更高;

round()对一个数进行四舍五入取整;

random()可以生成一个0到1的随机数;

//生成一个x到y的随机数:如果只是rando,()*(y-x)但是不可能生成x和y的,可以使用Math.round(x+Math.random()*(y-x));就可以创建0和10的啦;

 

max()/min()最大值最小值。

pow(2.3)2的3次方;

sqrt()平方根

 

包装类:

在js中提供三个包装类,可以将基本数据类型数据,转换成对象;对象比基本数据类型功能要强大一些;

 

String()转换成string对象

Number()转换成number对象

Boolean()转换成boolean对象

var x=new String(2)

基本对象比基本数据类型更加强大;

注意:在实际应用中一般不使用基本数据类型对象,在进行比较时,可能会出现意想不到的错误。对象保存对象空间的索引,而且对象转换成布尔值都是true;

 

当我们对一些基本数据类型的值去调用属性和方法时;浏览器会临时使用包装类将其转化成对象,然后在调用对象的属性和方法,调用完之后再转换成基本数据类型;

var s=1223;

s=s.toString();

s.hello=hei;//加进去属性之后,对象就直接被销毁了;所以s.hello的值为undefined;

 

基本数据类型能调用对象的属性和方法;

 

字符串的方法:

 

在底层中字符串是字符数组保存的,所以可以使用length属性查找对应的字符;

 

charAt():返回字符串中的指定位置的字符,根据参数的索引获取指定的字符;

 

charCodeAt():返回字符串中的指定位置的字符编码;

 

fromCharCode():根据字符编码获取字符;

String.fromCharCode()

 

concat():将两个字符串拼接一个新字符串返回,不会对原字符串做出修改;

 

indexOf()该方法可以检索一个字符串中是否含有指定内容;如果有返回指定内容首次出现的索引;

 

注意indecOf()的第二个参数可以指定开始查找位置,意思是说只要检查到第二个参数大于之前使用的indexOF返回的值,就能查到字符在字符串中出现的所有位置。

 

lastIndexOf();从后往前查找,返回值和indexOf()相同 第二个参数也是可以选的。

 

slice();同样不会影响原字符串;

 

substring()和slice()用法相同,但是substring()里面的参数不接受,自动转化成负值,而且能够自动调整参数的位置。

 

substr()和splice类似:参数第一个参数是开始截取位置,第二个参数是截取长度;

 

split()将字符串拆分成数组和join()功能相反,将会根据字符串拆分数组,

参数表示按照什么符号拆分数组,一般为“,”;不会影响原字符串

str.split(",");

 toUpperCase()转换成大写,不会改变原字符串

toLowerCase()转换成小写,不会改变原字符串

 

正则表达式:

 

检查用户输入的对不对(格式,符号等);比如检查电子邮件的格式;

邮件设置的规则:通过正则表达式来实现;

 

计算机根据正则表达式是否符合规则,或者将符合规则的内容提取出来;

 

创建正则表达式的对象;

 

var reg=new RegExp("正则表达式","匹配模式");

构造函数创建正则表达式:

var str="检查对象";

 

reg.test(str);

检查str

 

test()用来检查字符串是否符合正则表达式的规则;符合返回true否则返回false;

 

匹配模式可以作为第二个参数:

i是否区分大小写;

g是否是全局匹配;

 

使用字面量创建正则表达式:

 

var 变量=/正则表达式/匹配模式;

 

使用字面量创建会更简单,而构造函数会更加灵活;

                

/a|b/搜索a或b;                                |

/[a-z]/搜索a到z任意小写字母。          []包裹的内容都是或的关系

/[A-z]/任意字符          

/a[b-e]c/搜索abc acc adc aec        

/[^ab]/搜索除了a或b                            ^

 

字符串和正则相关的方法:

 

split(): 将字符串拆分成数组;

根据任意字母去拆分,方法中可以传递一个正则表达式去拆分字符串;

 

split([A-z]);这个方法及时不全部匹配也都是全局的

 

search()可以搜索字符串中是否含有指定内容;如果搜索到内容则返回搜索内容的索引,否则返回-1;这个只能查找第一个,即使设置全局匹配也没用

 

match()根据正则表达式,将符合条件的内容都提取出来。

默认情况下match()会搜索到第一个内容,找到后就停止检索;

我们可以设置正则表达式为全局匹配模式,这样就能匹配所有内容,

可以给正则表达式设置多个匹配模式,且顺序无所谓;

match()会将匹配的结果封装到一个数组中返回,即使值查询到一个结果;

提取一些有用的信息;

 

replace()可以将字符串中指定的内容替换成新的内容;

 

replace()第一个是替换的内容,默认只替换一个,可以设置全局匹配;如果想删除,可以通过空串替换;

str.replace(a,b);

 

正则表达式的语法:

 

量词,我们可以通过量词来设置一个内容出现的次数;{n}搜索它前面一个字符出现n次

var reg=/a{n}/;//搜索a出现n次;

var  reg1=/(ab){n}/; abababab,搜索这种形式的n次,使用小括号对前面内部所有字符搜索n次;

 

{1,3}出现一次到三次;{m,n}出现m到n次;{m,}m次以上;

 

+至少一个,相当于{1,}

*表示0个或多个

?表示0个或1个

^中括号中表示除了,在外部表示以什么为开头;

$表示结尾

.    表示任意字符就连@都能检查到,这样就没有办法检测它本身就是一个单纯的点,可以使用转义字符 \.  表示单纯的点;还有如\也需要写\\,在字符串中也需要使用两个\\

当然这是使用字面量创建的;

如果是在构造函数时,由于她的参数是字符串,外面还有一层正则表达式,如果想写一个\.表示单纯的点 那么就需要写\\.;

 

如果是^a$表示a即使开头也是结尾,所以只能有1个a;如果表示以a开头以a结尾^a|a$;

 

创建一个表达式检测字符串是否是一个合法的手机号;

1.不能以一开头

2.第二位3到9;

3.三位以后任意数字且只用9个;

^1[3-9][0-9]{9}$    //$这里的表示结束,这里的^和$就限制了字符串必须完全符合正则表达式的要求,不然使用test就有很大挑战如"feuhiah13098909389jiodn"返回

true

使用test()

 

\w任意字母、数字、_

\W除了字母、数字、_

\d任意数字

\D除了数字

\s空格

\S除了空格

\b单词边界

\B除了单词边界\ 单词\

 

单词边界:

当搜索/child/

而字符串中有children时,它两不是一个单词,但是如果没有单词边界,这无法判断到底是child本身,还是包含children;

需要使用/\child\/

 

去除字符串中的空格:

可以使用空串来替换空格:

str.replace(/\s/g,"");//去除所有空格;

^\s开头一个空格;需要写开头多个空格\s*$,需要使用全局模式

str.replace(/^\s*|\s*$/g,"");

 

邮件的正则表达式:

一般格式:jioaj486@djio.com.cn

还有特殊符号的.jiod@jiofa(网址字母或者数字).com.cn

 

任何字母数字下划线。任意字母数字下划线@任意字母数字.任意字母{2到5位}.任意字母{2到五位};

 

/  ^\w{3,}  (\.\w+)*  @  [A-z0-9]+  (\.[A-z]{2,5}) {1.2}  $/;

 

DOM简介:文档对象模型

 

js通过dom 操作html文档,只需要了解dom就能随心所欲的修改web页面;

 

文档表示的是就是整个的HTML网页文档

对象表示将网页中的每一个部分转换为一个对象

模型:使用模型来表示对象之间的关系,这样方便我们获取对象

 

                                文档

                                html

                    head                body

            titile    meta          {               大量模型              }

 

HTML DOM树 :

(Node)节点是构成网页中的基本组成部分;nodeName             nodeType           nodeValue

文档节点:整个html文档                            document                       9                      null

元素节点:html文档中的html标签               标签名                            1                       null

属性节点:  元素的属性                               属性名                            2                       属性值

文本节点:   文本内容                                   #text                            3                       文本内容

 

可以通过nodeType区分不同的节点类型;

通过DOM树可以查找不同的节点:节点可以通过修改改变文档的内容;

 

事件的简介:

就是用户和浏览器交互的行为;点击按钮、关闭窗口、移动鼠标;

 

我们可以在事件对应的属性中设置一些js代码,这样事件就能被触发,代码就会被执行;

οnclick="alert("hello第一次见面")"

var btn=document.getElementById("button");

btn.οnclick=function(){

};

//绑定一个单击事件绑定的函数,我们称为单击响应函数;

 

 文档的加载

由于代码是一行一行执行的,如果js的触发事件在btn前面(此时btn没有定义,这时候会发生错误),所以需要将代码放在获取的节点后面,这样就可以确保页面加载完毕后执行,这样不容易产生错误;

onload事件是在整个页面加载完成时触发;

window.οnlοad=function(){alert("nihao");}

 

如果非要将js代码放在前面或者需要将代码到页面加载之后执行,可以将执行代码放到window.οnlοad=function(){  代码      }中

但是先加载js不使用,就有点浪费网络资源了,最好写在下面。不过写在上面也有好处,就是很好改js容易维护。根据需求来写。而且有些代码需要在加载页面之前就要启动也需要写在前面;

 

dom查询:

 

document.getElementById("");

通过id属性获取的一个对象

document.getElementsByTagName("")

通过标签名获取一组对象(返回一个类数组对象,但不是一个数组)可以通l过length属性查询它的长度,通过获取对象的[索引]访问不同的数组对象;

document.getElementsByName("");

通过name属性获取一组对象(也是返回一个类数组对象,但不是一个数组)可以通过length查询它的长度,通过获取对象的[索引]访问不同的数组对象;

 

innerHTML:可以通过这个属性获得元素内部的html代码;对于自结束标签没有意义;

 

属性的获取:获取元素.属性就能访问相应属性.id   name    value这种直接元素.属性名只有class不能采用这种方式,读取class时需要使用元素.classname;(本来是不想让用户来获取class的)

 

 

info="一共有"+arr.length+"页,这是第"+index+1+"页";//这里是的+是拼串操作,如果想要加1需要将index+1用括号包裹起来

 

info="一共有"+arr.length+"页,这是第"+(index+1)+"页";

 

获取元素节点的子节点:

通过元素节点调用   元素节点.getElementsTagName()方法//之前的对象是文档对象,是从整个页面查询的。这个是在元素节点下面找;

返回当前节点的指定标签名后代节点;

 

childNodes属性(一组元素,类数组对象)://可以通过索引确定子节点,修改内容

表示当前节点的所有子节点;包括文本、注释、属性的所有节点     元素(子元素)间的空白被当成文本节点,注意在ie8及其以下没有将空白当成文本节点。一般标签之间都留有默认的空白。

children属性://可以通过索引确定子节点,修改内容

获取当前元素的所有子元素(一组元素,类数组对象):它不包括文本节点、注释节点;更合理一点;

 

firstChild属性:表示当前节点的第一个子节点;ie8不支持

获取当前节点的第一个子节点:包括文本节点;

firstElementChild:

获取当前节点的第一个子节点:不包括文本节点;

 

 

lastChild属性:表示当前节点的最后一个子节点;ie8不支持

获取当前节点的最后一个子节点:包括文本节点;

lastElementChild:

获取当前节点的第一个子节点:不包括文本节点;

 

获取父节点和兄弟节点:

 

parentNode:父节点,获取父节点

子节点.parentNode()

 

previousSibing:前一个兄弟节点:也可能获取到空白文本节点

previousElementSibing:前一个兄弟元素节点;

nextSibing:后一个兄弟节点:也可能获取到空白文本节点

nextElementSibing:后一个兄弟元素节点;

一直获取按钮这个一个重复性的工作,可以使用定义解决这个问题;

绑定单击响应函数:

function myClick(idStr,fun){

var btn=getElementById(idStr);

btn=fun;

}

idStr:表示传递的id

fun:单击响应函数

 

innerText属性:可以获取元素内部的文本内容:它会自动将内部html标签去除;

文本节点的文本内容就是nodeValue:可以通过子节点.nodeValue查看文本内容,相较于innerHTML,innerText要麻烦很多,知道意思就行。

 

全选/全不选:

var checkAllBox=document.getElementById("checkedAllBox");

checkAllBox.οnclick=function(){

for(var i=0;i<items.length-1;i++){

          items[i].checked=this.checked;//根据自身是否选中决定其他元素是否选中

}

}

 

其他元素全选,让全选按钮点亮;或者其他元素没有全选让全选灭掉;

for(var i=0;i<items.length;i++){

checkAllBox.checked=ture;

for(var j=0;j<items.length;j++){

if(!items[i].checked){

checkAllBox.checked=false;

break;//不用继续判断剩余的按钮了

}

}

}

 

dom查询的剩余方法:

获取body本身;

方法一:document.getElementByTagname()[0];

 

方法二:document.body

 

获取html:

 

document.documentElement;

 

获取all;

var all=document.all;

all.length=6

 

var all=document.getElementByTagName("*");

all代表页面中的所有元素;

 

还有一种是获取class属性的,但是这种方法不支持ie8及其以下;(获取一组元素节点对象)

var box1=document.getElementByClassName("box1");

 

获取box1中的div

document.querySelector(.box1 div);

可以根据选择找相应的对象,功能特别强大;这个方法在ie8中可以使用,虽然没有上面的方法,可以使用这种方式查找;

使用这个方法只会返回一个元素(即便有多个满足条件);这是一种局限;

 

document.querySelectorAll(.box div);这个也支持ie8,但是不同的是,它会将查询到的所用元素节点封装到一个数组中

即使只有一个元素节点,它也会返回一个数组;

 

dom增删改查:

 

创建元素节点:createElement();

document.createElement();它需要一个标签名做参数,将会根据该标签名创建元素的节点对象;

并且将创建的对象作为返回值返回。

 

var li=document.createElement("li");

 

创建文本节点:createTextNode();

document.createTextNode();它需要一个文本内容来作为参数,创建相应的文本节点。并将新的节点返回。

var text=document.createTextNode("dkop");

向父节点中添加子节点:父元素.appendChild();

li.appendChild(text);

 

获取页面存在父元素:

city.appendChild(li);在页面添加节点;

 

removeChild();删除指定子节点;

父节点.removeChild(子节点)

子节点.parentNode.removeChild(子节点),删除自己;更常用

 

replaceChild();使用新节点替换旧节点

父节点.replaceChild(新节点,旧节点)

 

insertBefore()

在指定子节点前插入新的节点;这个方法是父节点调用的

 

city.insertBefore(li,li);

父节点.insertBefore(新节点,旧节点)

 

也可以通过:

innerHTML增删改等相关操作,且比较简单;但是这种方法会比上面一种消耗更大,相当于将整个父节点和它所有的兄弟节点都发生了更改。

上一种只对自己有影响。

 

添加删除记录:

超链接默认是为了跳转,有时候需要刷新页面的时候会将事件绑定在a元素上;

 

//删除<tr>中的员工

function delA(){

var allA=document.getElementsByTagName("a");

 

for(var i=0;i<allA.length;i++){

all[i].οnclick=function(){

var tr=this.parent.parent;//这里不能使用allA[i],因为响应函数在被调用的时候才会执行,而这里for循环已经执行完毕了,也就是i为allA.length+1;这是后调用allA[i]就没有结果了。

var name=document.getElementsTagName("td")[a];

var flag=confirm("确认删除"+name+"吗?");

if(flag){

    tr.parent.removeChild("tr");

}

}

}

}

//添加员工;

<tr>

<td>name:</td>

<td>text:</td>

<td>salary:</td>

<td><a></a></td>

 

var btn=document.getElementById("addbutton");

btn.οnclick=function(){

//如果提交按钮在表单中,还需要在内部先取消默认按钮;

var name=document.getElementById("name");

var text=document.getElementById("text");

var salary=document.getElementById(salary");

 

var tr=createElement("tr");

var a=createElement("a");

a.href="javascript:void()"

 

var ntd=createElement("td");

var nte=createElement("td");

var nsal=createElement("td");

var ndel=createElement("td");

 

var cname=createTextNode(name);

var ctext=createTextNode(text);

var csal=createTextNode(salary);

var cdel=createTextNode("delete");

 

ntd.appendChild(cname);

nte.appendChild(ctext);

nsal.appendChild(csal);

a.appendChild("cdel");

ndel.appendChild(a);

 

tr.appendChild(ntd);

tr.appendChild(nte);

tr.appendChild(nsal);

tr.appendChild(ndel);

 

//获取table:

 

  var tab=documentElement('tab")//这天添加的是table里tbody外,而一般浏览器会添加一个tbody;这样就和之前的元素节点放在不同的地方了;

 

//     tab.appendChild(tr);

 

//所以需要准确的添加到tbody中

 

var tbod=tab.getElementByTagName("tbody");

tbod.appendChild(tr);

 

修改之前的单击响应函数,因为这是重新添加的内容;

delA();

 

为可简化代码:可以修改成innerHTML输入:但是注意这里修改的不是tbody这个父节点;而是先添加一个子节点tr再向其中使用innerHTML属性,这样就不会影响整个tbody;

 

var tr=document.createElement("tr");

tr.innerHTML="<td>"+name+"</td>"+ "<td>"+text+"</td>"+ "<td>"+salary+"</td>"+ "<td><a>delete</a></td>";

但是这里的超链接对象没有被创建,没有绑定单击响应函数便没有办法删除。

可以使用。

var a=tr.getElementsByTageName("a");

a.οnclick=delA;

 

操作内联样式:

 

var box1=document.getElementById("box1");

box1.style.width=120px;

box1.style.background-color=red;//这里的background-color中-在js中是不合法的,所以需要将-后面的字符改成大写。

例如:

borderTopWidth:

backgroundColor:

 

我们通过js中style属性修改的样式是内联样式,有较高的优先级;所以之前说不要在样式中使用!important;

通过style属性能读取内联样式,但是不能读到样式表中的样式。(能修改,不能读取)

 

读取元素的样式:

可以使用

元素.currentStyle.样式名  //获取当时显示的样式。如果没有该样式会显示默认值

但是这种方式只有ie支持:其他浏览器不支持;

 

在其他浏览器可以使用:getComputedStyle()这个只有ie8以下不支持,其他浏览器都支持

这是window的一种方法;需要两个参数

第一个需要获取样式的元素,第二个可以传递一个伪元素,一般设置为null

使用需要getComputedStyle(obj,null).width;

 

这个方法会返回一个对象(封装了当前元素的样式)

通过该对象.样式名;

可以查看他的当前样式,如果获取的样式没有任何样式,则会返回当前的真实的值,而不是默认值;如果没有设置 width他不回复auto而是具体的值;

 

设置一个兼容的函数:

function getStyle(obj,name){

//没有必要判断浏览器的版本,只要看有没有getComputedStyle方法,由于该方法返回的是一个对象,所以有那么必然是true,但是如果直接写getComputedStyle判断该变量的话需要从全局中寻找,最终还是会报错。所以这么写不行;但是加了window就会将这个方法变成window的一个属性,也就不会报错

if(window.getComputedStyle){

return getComputedStyle(obj,null)[name];//对象的调用方法有两种一种是对象名.属性 还有一种是类似于数组的索引对象名[索引]}

else{

return obj.currentStyle[name];}

return -1;

}

 

简化:

function getStyle(obj,name){

return window.getComputedStyle?getComputedStyle(obj,null)[name]:obj.currentStyle[name];

}

通过上面两个获取的对象是不能修改的,只能通过style属性去修改样式的值;

 

其他样式相关属性:

 

clientWidth:返回可见宽度(包括内容区和内边距不包括外框和外边距)

clientHeight:返回可见高度(包括内容区和内边距不包括外框和外边距)

 

以上参数是直接返回数字,可以进行计算,不带有px;由于这是计算值(多个值混合的),所以这些属性是只读的;

 

offsetWidth:返回元素整个宽度

offsetHeight:返回元素整个高度

 

offsetParent:定位父元素,如果父元素没有开启定位,就会返回祖先元素body,它返回的是离当前元素最近的开启定位的祖先元素;可以用于指导修改样式;

 

offsetLeft:相对于定位元素的水平偏移量

offsetTop:相对于定位元素的垂直偏移量

 

scollHeight:滚动高度;

scollWidth:滚动宽度;

scollLeft:滚动条到左侧的距离;

scollTop:滚动条到顶端的距离;

 

scollHight-scollTop=clientHeight;这样表示滚动条拖动到底部;有时候需要让用户拉动到底部才能操作其他内容;比如刷新网页,协议勾选等;

 

如果设置表单项disabled="disabled"表示表单项不可用;

可以设置将滚动条滚动到底是才能到底时disabled="false";需要使用的标签是下一步按钮和checkbox;

当滚动条滚动时触发检测滚动条是否滚动到底(onscoll);

创建事件:

p标签上''info"绑定滚动条;

var info=document.getElementById("info");

var inps=document.getElementsByTagName("input");

info.onscoll=function(){

if(info.clientHeight==scollHeight-scollTop){

inps[0].style.disabled=false;

inps[1].style.disabled=false;

}

}

 

事件对象:当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进相应函数;

在事件对象中封装了当前时间相关的一切信息,比如键盘的输入鼠标的移动,鼠标的点击,窗口的变化等等;

 

onmousemove:鼠标移动事件;

 

元素节点.οnmοusemοve=function(event){

var x=event.clientX;

var y=event.clientY;

 

 

}

 

clientX:鼠标指针的水平位置距离左边,但是ie8的event保存在window中所以需要使用window.event.clientX,火狐不支持这种方式  client是相当于浏览器的可见窗口

clientY:鼠标指针的垂直位置距离上边,但是ie8的event保存在window中所以需要使用window.event.clientY,火狐不支持这种方式   client是相当于浏览器的可见窗口

 

pageX:是获取鼠标相对于当前位置的横坐标,不兼容ie8

pageY:是获取鼠标相对于当前位置的纵坐标,不兼容ie8

 

解决事件对象兼容性问题:

解决方法和上面的getComputedStyle类似;

if(!event){

event=window.event;

}

简化:

event=event||window.event;

 

大多数浏览器有event所以使用event作为主要window.event作为防止出错的备案;

 

div跟随鼠标移动:

pageX/pageY不支持ie8;

一般使用

clientY=scollTop+Top+"px";

clientX=scollLeft+Left+"px";

等式左边clientX/clientY用来设置鼠标;

等式右边设置可以移动的对象;

 

chrome认为浏览器的滚动条是body的

firefox认为浏览器的滚动条是html的;

scollTop=document.body.scollTop||document.getElement.scollTop;

scollLeft=document.body.scollLeft||document.getElement.scollLeft;

 

事件的冒泡(bubble):

所谓的冒泡就是事件向上传导,当后代的事件被触发,向上的祖先元素的事件也会被触发。

先触发后代,然后是父元素,最后是祖先元素。

 

在开发中,冒泡大多数都是有用的。比如如果在一个顶范围内自由移动,可以通过冒泡从其他元素上经过。

 

如果不希望发生冒泡,可以通过事件取消冒泡直接event.concelBubble=true;注意之前要使用事件的兼容;这个表达式没有兼容性问题;

 

事件的委派:

之前我们给每一个超链接绑定单击响应事件,需要使用for循环遍历,而绑定之后的添加的新的超链接还需要重新绑定;这样实在太麻烦,影响性能;

我们希望只绑定一次事件即可,即使元素是后来添加的。

 

我们可以尝试将事件共同的祖先元素。而这个方法就是事件的委派。这样当我们后代元素触发时,会自动通过冒泡触发祖先元素,从而触发事件,通过减少事件的委派次数,提高程序的性能。

event.targent表示事件触发的对象

但是这个祖先元素可能包含不想触发事件的元素。可以通过在触发元素上绑定一个class属性假设为link;最后通过祖先元素触发事件进行判断:

if(event.target.className=="link"){触发此事件};但是这里的link有隐患,如果其中一个有多个classs属性,那么就和"link"不等,导致事件触发失效,可以使用正则表达式解决此类问题。/^[link]{1}|\slink\s|\slink$/;

 

事件的绑定:

通过响应函数只能当对同一个元素进行绑定同一个响应函数,绑定多个的话,后一个函数会将前一个覆盖掉;

 

可以通过

btn.addEventListener("click")// 这种方式可以为一个元素相同事件,绑定多个响应函数,它会按照事件绑定的顺序进行;它里面的this对象是触发事件的对象

参数:事件,事件的字符串,不用on;回调函数,当事件被触发是会调用;是否在捕获阶段触发事件,需要一个布尔值,一般为false;

去除事件:

removeEventListener("btn");

这种方法不支持ie8及其以下的浏览器;

 

可以使用attachEvent();这种方法也可以同时绑定多个事件,但是它是按照后绑定的先执行;它里面的this是window

两个参数:事件,字符串需要on;回调函数

dispatchEvent("btn");去除事件

兼容函数:

function bind(obj,eventStr,callback){

//需要统一方法

//需要统一event

//需要统一this

//执行顺序,也可能需要统一

if(obj.addEventListener)

{obj.addEventListener(eventStr,callback,false);}

else{

//解决this的方法,通过匿名函数call()指定obj;匿名函数是window调用的但是callback是obj调用的

//obj.attachEvent("on"+eventStr,callback);

obj.attachEvent("on"+eventStr,function(){callback.call(obj);})

}

}

 

事件的传播流程:

事件的传播,对于事件的传播网景公司和微软有不同的理解;

微软公司认为事件应该从内而外传播,也就是说事件应该在冒泡阶段执行;

网景公司认为事件应该从外往内传播的,也就是从祖先元素传递到内部阶段,这就是事件的捕获阶段;

 

w3c采用两种方案,将事件传播分为三个阶段;

1.捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是此时不会对事件进行触发;

2.目标阶段:事件捕获到目标;

3.冒泡阶段:事件从目标开始向祖先元素触发事件;

 

如果希望在捕获事件阶段就触发事件,可以是第三个参数设置为true;ie8及其以下没有捕获这个阶段。

 

拖拽:

拖拽的步骤:

当鼠标按下时,元素可以被拖动;onmousedown

当鼠标移动时,元素跟着鼠标指针移动;onmousemove

当鼠标鼠标松开时,元素会停留在当前位置onmouseup

var box1=document.getElementById("box1");

box1.οnmοusedοwn=function(event){

box1.setCapturn&&box1.setCapture();

//box1.οnmοusemοve=function(event){

 

};

//box1.οnmοuseup=function(event){

 

box1.οnmοuseοver=null;

};

//上面的这个事件是给box1绑定的,会有一定的bug,比如当鼠标移动到兄弟元素上,那么就会失去这个事件的触发;所以需要将事件绑定在document上;

var  ol=event.clientX-box1.offsetLeft;

var  ot=event.clientY-box1.offsetTop;

document.οnmοusemοve=function(event){

//需要将鼠标指针相对于box1位置不会发生变化;之前使用clientX=Left;只能获取鼠标指针在box1左上角的位置;

//需要从点击事件时就求出偏移量(鼠标到box1左上角的位置);

 

var left=event.clientX-ol;

var top=event.clientY-ot;

 

box1.style.left=left+"px";

box1.style.top=top+"px";

 

};

document.οnmοuseup=function(event){

document.οnmοuseοver=null;//此时这个事件并没有取消,所以还会被触发,所以需要取消该事件:document.οnmοuseup=null;

document.οnmοuseup=null;

};

return false;

};

//这里还有一个问题,就是当我们去在一个页面去拖拽内容时,浏览器会默认去搜索引擎搜索内容;如果不希望发生这个行为,可以通过return false取消这个行为;

//但是这对ie8不起作用:设置box1设置setCapture()(点击任何按钮都会默认点击元素,移动只会移动它一个);但是这只是捕获一次,但是当鼠标再次点击,也会触发该事件,所以需要在onmouseup中取消捕获,releaseCaptrue();但是这在chrome中会报错;可以使用元素.setCapturn&&元素.setCapture();

 

提取专门的拖拽函数:

 

function dray(obj){

//box1改为obj;给目标设置一个开启定位,就可以运行了;

}

 

滚轮事件:

onmousewheel:鼠标滚轮的时间,会在滚轮滚动的触发该事件,但是火狐不触发该事件;

wheelDelta:鼠标滚动的方向,向上滚是正值,向下滚是负值,很多浏览器这个属性返回值不同,所以不用考虑值的大小,火狐中detail向上是-3负值,向下是3正值;

if(event.wheelDelta>0||event.detail<0){向上滚动}else{向下滚}

 

//当浏览器有滚动条时,如果在指定元素上滚动会触发浏览器的默认行为;,这会使浏览器窗口和元素一起发生滚动,需要取消默认行为;

在触发某个事件函数中添加event.preventDefault();当移动到指定元素,浏览不会发生滚动事件;这个属性ie8不支持

event.preventDefault&&event.preventDefault();有就使用;

 

键盘事件:

键盘事件一般绑定在获取焦点的对象,或者文档事件;

onkeydown:键盘事件被按下;

onkeyup:键盘事件被松开;

对于事件来说当键盘一直被按下,它会一直触发事件;第一次和第二次触发的时间稍微长一点,防止误触发;

 

可以通过keycode获取按键编码;也就是说判断哪个按键被按下了;

同时按下的按键怎么判断呢?

这样?if(event.keycode===19&&event.keycode===85),这是明显错误的,没有一个值能够既等于19又等于85,可以通过单独的键盘事件判断是否同时按键;

altkey

ctrlkey

shiftkey

这三个是单独的触发的:

在文本框中输入内容是文本框中的默认行为;可以通过return false;取消默认行为;,可用于指定用户输入内容功能,不然无法显示;

 

键盘移动:

 

37左

38上

39右

40下

 

判断键盘事件可以用swith语句来判断事件,绑定操作;

//设置变量speed可以修改变量的速度;

var speed=10;

//加速;

if(event.keyctrl){speed=30;}

switch(event.keycode)

{

case 37:

box1.style.left=box1.offsetLeft-10(speed)+"px";

break;

case 38:

box1.style.top=box1.offsetTop-10(speed)+"px";

break;

case 39:

box1.style.right=box1.offsetRight+10(speed)+"px";

break;

case 40:

box1.style.bottom=box1.offsetBottom+10(speed)+"px";

break;

}

但是这个也有个缺陷,之前说过浏览器为了防止误触发,在第一次到第二次触发的时间间隔更长。需要使用定时调用来修改;

 

BOM:浏览器对象模型;

BOM可以让js操作浏览器的,在bom中定义了一组对象,用来完成对浏览器的操作;

BOM对象:

Window对象:

代表浏览器的整个窗口,同时window也是网页的全局对象;

Navigator:代表当前浏览器的信息,通过该对象可以识别不同的浏览器;

 

Location:代表当前地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面;

 

History:代表浏览器的历史记录,可以通过该对象中操作浏览器的历史记录

            由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页;

            而且该对象访问当前访问有效;

 

Screen:代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的信息;做移动端,响应式都需要使用;

 

Navigator对象:

appName:获取当前浏览器名称,除了ie9及其以下,都比较正常,而现在都会显示netscape;(通常是主流浏览器)

这里的大量属性,已经不能使用了。

以前由于ie的特殊性,很多资源不能调用,导致一些网站给ie的资源不如其他浏览器,而这也是识别ie的手段之一,后来ie就向大多数浏览器妥协,于是越来越像普通浏览器;

弃用了许多特殊的属性;就连appName也变成了netscape;

 

一般使用userAgent来判别浏览器信息;

userAgent就是一组字符串,不同的浏览器有不同的浏览器信息;

而这里面也有很多重复的内容;但也有区分信息,可以使用正则表达式来区分浏览器中有无浏览器信息;

var ua=Navigator.userAgent;

if(/firefox/i.test(ua){

//是否为火狐浏览器

}else if(/chrome/i.test(ua)){}

else if(/mise/i.test(ua)){测试ie10及其以下}

// ie11之后ie浏览器消除了这个方式

 

我们可以通过浏览器中特有的对象来判断是否是ie浏览器;

如果ActiveXObject有则判断是ie;

//if(window.ActiveXObject){这是ie浏览器;},这个也不行;,使用in来判断;它采取返回是false,一般ie采用返回true

if("ActiveXObject" in window){}//通过判断属性中有没有这个属性;有返回true;

 

History对象:

操作浏览器向前,向后翻页;

histoty.length:表示访问当前浏览器中历史记录的数量(单次访问的数量,不在具体的浏览器的数量),关闭时消失;

back():回退,可以用来回到上一个页面;

forward():前进,可以跳转到下一个页面;

go(n):跳转到当前页面第n个页面, n为正值前跳,n为负值后跳;

 

Locatiion对象:

如果直接打印location则可以获取当前地址栏上的信息;(完整的路径);

location="";如果直接修改完整的路径或者相对路径,则页面会自动跳转到该页面;并且生成相关的历史记录;

location的对象属性,将地址分为好几个部分,可以之后学习了解;

 

location的方法:

assign():

location.assign():和赋值的方式是一个样的。

 

reload();从新加载当前页面,作用和刷新按钮一样;

 

ctrl+f5:强制清空缓存;

location.reload(true);强制清空缓存;没有true不强制;

 

replace()使用新的页面替换当前页面;跳转不能回退;不会生成历史记录;

 

定时器简介:

for循环当调用一条语句的时候,不能看到具体的细节,如果希望程序每间隔一段时间调用一次,

就需要使用setInterval()定时调用,这个可以使函数每隔一段时执行一次,

第一个参数为回调函数,这个函数每隔一段时间调用一次,第二个参数是间隔的时间,单位毫秒;

它会以数字作为返回值,这个数字代表这个定时器的唯一标识

var x=setInterval(function(){},1000);

关闭定时器,

clearInterval()方法中需要定时器的标识关闭这个定时器:可以传递这个数字,一般来说直接将定时器赋值给一个指定的变量,然后将变量作为参数来关闭定时器;

clearInterval(x);//x可以传入任意一个类型,有效就会停止,无效也不会报错;

切换图片练习;

<img src="image/01.png" id="img1">

<script>

var img=document.getElementById("img1");

var imgArr=[image/01.png,image/02.png,image/03.png];

var index=0;

 

var set1=setInterval(function(){

index++;

if(index==imgArr.length){

index=0;

}

img.src=imgArr[index];

},1000)

img.οnclick=function(){

if(set1){

clearInterval(set1);

}

else{

var set1=setInterval(function(){

index++;

if(index==imgArr.length){

index=0;

}

img.src=imgArr[index];

},1000)

}

}

</script>

 

开启定时器之后需要及时关闭,不然容易在开启之后,会误创建多个定时器,由于set1被反复赋值,前一个的标识被后一个标识覆盖掉了,从而关闭不掉;

 

修改div练习:

速度交给定时器控制,方向交给键盘事件判断,然后设置一个键盘松开事件判断重置变量的方向,就能完成连贯的操作;

window.οnlοad=function(){

var speed=10;

var dir=0;

var set1= setInterval(function(dir){

switch(dir){

判断执行

}

},30)

document.οnkeydοwn=function(event){

event=event||window.event;

var dir=event.keycode;

if(event.keyctrl){

speed=50;

}};

 

document.οnkeyup=function(event){

dir=0;speed=10;

};

};

 

延时调用:

setTimeout(参数一,参数二)

这个函数参数一过参数二毫秒调用一次;应用网页上一些广告,过一段事件自动关闭;

这两个可以互相代替的的;

clearTimeout()可以清楚延时调用;

 

小功能:

ie浏览器没有设置的值都会返回默认;最好在使用的时候设置一个默认值;

将一个功能集成后,可以设置多个参数,如对象 属性 目标 方向 回调函数等;

其中的回调函数,可以让方法多次调用,更好的 与其他功能集成;

callback&&callback()表示有回调函数就调用回调函数。回调函数表示函数执行完毕之后才去调用的。其他的可以模仿这个设置,没有传参该如何执行;

轮播图:

轮播图的横向图片的宽度不要写死了,不然添加新的元素,会让多余的元素自动换行,应该通过计算内部轮播图片的数量定义轮播图的宽度。

创建导航链接随着轮播图一个跳动;这个的宽度和居中也不能写死,不然添加新元素后,它会变样,不居中;使用计算值,添加元素之后整体距离两端的距离(大容器的宽度-导航链接的宽度)除以2就能完成居中了;

对所有的超链接绑定单击响应函数,链接到相应图片;

还需要获取点击超链接的索引;

for (var i=0;i<allA.length;i++){

//给每一个a超链接绑定一个索引,这样就能知道点击的是哪一个超链接

all[i].num=i;

all[i].οnclick=function(){

index=this.name;

imgListLeft=index*(-520)+"px";

}

}

创建点击动画:动画执行一次向左滑动或者直接滑动到对应的位置,随着动画的执行,超链接的样式也需要发生变化。

创建轮播动画:每隔三秒会执行一次动画向左滑动;

这里的点击动画会和轮播动画产生冲突,可以设置在点击时取消轮播动画,当这个动作执行完成,设置轮播动画定时器,就可以避免这个问题;

这里还有就是到最后一张图片时,它会慢慢的往前滑动,滑动到时,可能就会跳转到下一个图片了,所以在这里需要多设置一个图片不绑定链接,当滑动到最后一张图时,直接以修改索引为第一张图片的索引。不让其参与动画。

 

类的操作:

通过style属性修改元素的样式,每修改一次,浏览器就需要重新渲染一次页面;当修改多个样式时,一行一行的修改样式,就会消耗大量的浏览器资源,而且在开发中,

这种js修改,还会让原本的文档更加的混乱,要修改样式还得去js中去寻找。

我们需要的做的是,

一行代码修改多个样式;

我们可以通过修改(添加)元素的class属性,来修改文本的样式,这样一来我们只需要修改一次,就能修改多个样式,浏览器只需要重新渲染一次。这种方式可以使表现和动作分离;(先在css中定义需要修改的样式;

box.className+=" b2"//b2前面有一个空格,不然的话会将两个字符串拼接在一起,从而导致原有的class属性实现,如class="b1"拼接之后有class="b1b2",需要空格隔开;

 

定义一个函数,用来向一个元素中指定的class属性值添加属性;

function addClass(obj,cn){

if(hasClass(obj.cn)){

obj.className+=" "+cn;}//这样会产生重复的class

}

function removeClass(obj,cn){

if(hasClass(obj,cn)){

var reg=new RegExp("\\b"+cn+"\\b");

obj.className=reg.replace(cn,"");

}

}

function hasClass(obj,cn){

//判断obj中是否有class;

var reg=/^(cn){1}\s|\s(cn){1}\s|\s(cn){1}$}/;   //这种方式是没有办法设置变量,需要使用构造函数;

var reg=new RegExp("\\b"+cn+"\\b");\b表示单词边界,表示cn是独立的;

return reg.test(obj.className);

}

function toggleClass(obj,cn){

//判断有删除,没有添加;

var reg=new RegExp("\\b"+cn+"\\b");

if(hasClass(obj,cn)){

obj.className+=" "+cn;

else{

obj.className=reg.replace(cn,"");}

}

 

二级菜单:

实现的相同动画的方法,最好也是相同的,这样可以节省很多代码;

动画过渡的参数,可以先从控制台上输出从而获取;

动画过渡的结束之后,可能还会残留内联样式导致下一次调用动画会失败;

 

JSON:

服务器和客户端之间,需要存在通信;而服务器和客户端的语言不同,虽然js能够读自己的对象,但是服务器不一定认识。

JSON就是特殊格式的字符串,这个字符串任何语言都能识别,并且可以转换成任意语言的对象;这样就可以将js中的对象和其他语言的对象交互;

(javascript object notation)JSON的格式和js的对象是一样的,只不过JSON字符串中的属性名必须加双引号;

 

JSON有两种:

一种是对象{}包裹;

JSON:var json='{"name":"nihao","sex":"男"}';

另一种是数组[]包裹;

JSON:var json='["name":"nihao","sex":"男"]';

 

JSON中的允许值

1.字符串

2.数值

3.布尔值

4.对象(普通对象;不包括函数对象)

5.null

6.数组;

//undefined不能,还有就是函数不能传;

需要将字符串转换成对象:

 

在js中提供了一个工具类,就叫JSON;它既可以将JSON转化成对象,也可以将对象转换成JSON;

 

JSON.parse(json);它需要将一个JSON字符串作为参数,会将字符串转换成JSON对象;它返回一个对象/数组;

 

将js对象转换成JSON;

JSON.stringify()可以将一个js对象转换成JSON字符串,需要添加一对象作参数;

 

JSON常用,作为数据交互对象:轻量级,速度较快的数据交换格式;

 

但是JSON在IE7及其以下的浏览器不支持,所以在这里调用会报错。

 

如果需要兼容ie6,ie7;需要使用eval()函数,这个函数可以执行字符串形式的代码,并将执行结果返回;

如果执行字符串中含有大括号,它会将大括号当做代码块;

如果不希望将其当做代码块解析,需要将字符串前后江上一个()

var obj=eval("("+json+")");通过eval()将JSON很容易转换成字符串;

 

eval()这个函数虽然功能强大,但是也用很大的副作用,如消耗很大,安全隐患;

 

真要兼容ie7及以下的JSON的操作,则可以通过引入一个外部的js文件来处理;在网上能够搜索到兼容ie6,7的js;

 

来自尚硅谷2016年视频 笔记(李立超的)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值