前端精品课
学习笔记(一)
一般来说,网站的前端和后台使用不同的编程语言,前端最常用的语言有
HTML
、CSS
、JavaScript
、JSP
等,后台常用的语言有Java
、Python
、PHP
等。前端和后台之间需要传递数据,不同语言的数据类型一般不同,这就需要一种大家都能接受的文本格式传递数据,JSON
是一个很好的选择。
JSON
的全称是JavaScript
对象表示法(JavaScript Object Notation)
,是一种文本数据的交换格式,虽然JSON
使用了JavaScript
的语法,但是在很多语言里面都能使用JSON
,比如Java
和PHP
,这也是它能被用来传递数据的原因。
JSON
常用的数据格式有JSON
对象、JSON
数组和JSON
字符串。
JSON
对象(通常叫JSON
)是一种文本数据的交换格式,用于存储和传输数据。示例如下:
{"name":"Jerry", "age":15}
这就是一个简单的json
对象,它的规则是:
在实训四里面,我们讲过JavaScript
中的自定义对象。而JSON
是基于JavaScript
语法的,所以JSON
中也有对象的概念,但是和JavaScript
中的对象有一些小的区别。
定义一个JavaScript
对象:
var myObject = { id:1, name:"Peter Bruce", "first name":"Bruce", display:function() { console.log(this.name); }}
定义一个JSON
对象:
{"id":1,"name":"Peter Bruce","first name":"Bruce"}
三点区别:
JSON
对象的属性名(key
)必须被包含在双引号之中,而JavaScript
对象除了有空格的属性名、中间有连字符-
的属性名必须在双引号之中外,其它随意;JSON
对象中定义方法,而在JavaScript
对象中可以;JSON
对象可以被很多语言操作,而JavaScript
对象只有JS
自己可以识别。定义JSON对象的方法如下:用一个{}
包含在内,内部是若干个属性名和属性值构成的键值对,键值对之间用,
隔开,属性名和属性值之间用:
隔开,属性值可以是以下任意一种数据类型的数据:数字、字符串、JSON
数组、JSON
对象、null
。如:
{"a":1,"b":2.12,"c":true,"d":"string","e":null};
属性值是JSON
数组或者JSON
对象的情况稍复杂,后面的关卡将介绍。
支持JSON
的语言都能够使用JSON
对象,这里仅介绍在JavaScript
中如何使用JSON
对象。
JavaScript
中定义一个JSON
对象:var jsonObject = {"name":"js","number":2};
操作属性,使用.
或者[]
:
console.log(jsonObject.name);//读属性,输出js console.log(jsonObject["name"]);//读属性,输出js jsonObject.name = "javascript";//写属性,给name属性赋值javascript
删除属性,使用delete
:
var jsonObject = {"name":"js","number":2}; delete jsonObject.name;//删除name属性
遍历属性,使用for-in
循环:
var jsonObject = {"name":"js","number":2}; for(att in jsonObject) { console.log(jsonObject[att]);//依次输出js、2 }
JSON
键值对中的值(value
)可以是一个数组,比如:
{ "country":"China", "population":"1.3billion", "bigCity":["Peking","Shanghai","ShenZhen","HongKong"] }
属性bigCity
的值有多个,放在一个数组里面。
上面例子里面,数组的每一个元素都是字符串。其实,数组的每一个元素还可以是另外一个json
对象。比如:
{ "class":"高三一班", "studentNumber":70, "score":[ {"name":"LiMing","score":128}, {"name":"ZhangHua","score":134}, {"name":"ShenLu","score":112}] }
上面的score
属性的值是一个数组,这个数组的每一个元素是一个json
对象。
读写元素:
var myJson = { "country":"China", "population":"1.3billion", "bigCity":["Peking","Shanghai","ShenZhen","HongKong"] } console.log(myJson.bigCity[1]);//打印出Shanghai myJson.bigCity[0] = "GuangZhou";//第一个元素被赋值为GuangZhou
遍历:
var myJson = { "country":"China", "population":"1.3billion", "bigCity":["Peking","Shanghai","ShenZhen","HongKong"] } for(var i = 0;i < myJson.bigCity.length;i++) { console.log(myJson.bigCity[i]);//依次输出Peking,Shanghai,ShenZhen,HongKong }
在前端和后台之间传递数据可以使用JSON
,但是实际上传递的是JSON
字符串,而JSON
对象是不可以直接进行传递的。
JSON
字符串就是在JSON
对象两边套上'
形成的字符串,如:
var JSONObject = {"k1":"v1","k2":"v2"};//JSON对象 var JSONString1 = '{"k1":"v1","k2":"v2"}';//JSON字符串
上面的JSONString1
就是JSON
字符串,可以直接从前端传到后台或者后台传到前端。
当JavaScript
收到从后台传来的JSON
字符串后,怎么把它变成JSON
对象方便处理呢?
JSON.parse(a,b)
方法将JSON
字符串a
转换为JavaScript
对象。b
是一个可选的函数参数。
var JSONString1 = '{"k1":"v1","k2":"v2"}'; console.log(JSON.parse(JSONString1));//输出Object {k1: "v1", k2: "v2"}
函数参数b
按从里到外的顺序作用在对象的所有属性上,最后一个作用的是对象本身:
//对象的每一个属性的值加1 var text = '{ "key1":1, "key2":2, "key3":2.2}'; var obj = JSON.parse(text, function (key, value) { if(key === '')//当遇到对象本身时,不进行加1操作 return value; return value+1;//对属性值加1 }); console.log(obj);//输出Object {key1: 2, key2: 3, key3: 3.2}
如上面所示,函数的参数有两个,其中key
表示属性的名字,value
表示属性的值,当遇到对象本身时,key
的值为''
,即空字符串。
JSON.stringify(a,b,c)
,a
是待转换的JSON
对象,b
和c
为可选参数。
var JSONObject = {"k1":"v1","k2":"v2"}; JSON.stringify(JSONObject);//JSON对象转换为JSON字符串
参数b
为函数时,该函数按照从里到外的顺序处理JSON
对象的每一个属性,最后一个处理的是JSON
对象本身,处理完后再转为JSON
字符串:
//对象的所有属性值加1,再转为字符串 var JSONObject = {"k1":1,"k2":2.2}; var JSONString = JSON.stringify(JSONObject,function(k,v){ if(k === '')//处理到了JSON对象本身 return v; return v+1;//所有的属性的值加1 }); console.log(JSONString);//输出{"k1":2,"k2":3.2}
参数b
还可以是数组,数组存储的是属性的名字,用来指定只转换哪些属性:
//转换对象中特定的属性 var JSONObject = {"k1":1,"k2":2.2,"k3":3}; var JSONString = JSON.stringify(JSONObject,["k1","k2"]); console.log(JSONString);//输出{"k1":1,"k2":2.2}
这里简单介绍一下c
:
var str = ["name":"Tom","age":16]; var obj1 = JSON.stringify(str); var obj2 = JSON.stringify(str,null,4); console.log(obj1); //输出{"name":"Tom","age":16} console.log(obj2); //输出//{// "name": "Tom",// "age": 16//}
参数c
:文本添加缩进、空格和换行符,如果 c
是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 c
大于 10
,则文本缩进 10
个空格。
一些常用的无理数的表示方法:
表示 | 意义 | 约等于 |
---|---|---|
Math.E | e | 2.718 |
Math.PI | 圆周率 | 3.14 |
Math.SQRT2 | 2的平方根 | 1.414 |
Math.LN2 | 2的自然对数 | 0.693 |
console.log(Math.PI);//输出3.141592653589793 console.log(Math.pi == 3.141592653589793);//true console.log(Math.pi == 3.14);//false
Math.ceil(x)
实现向上取整,返回大于等于x
且离x
最近的整数。
console.log(Math.ceil(1.1));//输出2 console.log(Math.ceil(1));//输出1 console.log(Math.ceil(-1.1));//输出-1
Math.floor(x)
返回小于等于x
且离x
最近的整数。
console.log(Math.floor(1.1));//输出1 console.log(Math.floor(1));//输出1 console.log(Math.floor(-1.1));//输出-2
Math.random()
返回0
到1
之间的一个随机数,包含0
不包含1
。
console.log(Math.random());//输出0.1493135392665863
Math.sqrt(x)
返回x
的平方根。
Math.sqrt(4);//2 Math.sqrt(2);//1.4142135623730951
Math.round(x)
返回x
四舍五入后的整数。
Math.round(1.5);//2 Math.round(1.49);//1
Math.max(x1,x2,....xn)
返回参数的最大值,参数个数不限;
Math.max(1,2,34,100);//100 Math.max(-1,-2,-34,-100);//-1
Math.min(x1,x2,....xn)
返回参数的最小值;
Math.min(1,2,34,100);//1 Math.min(-1,-2,-34,-100);//-100
Math
还有很多的方法,如下面的表格所示:
方法 | 作用 |
---|---|
Math.abs(x) | 求x的绝对值 |
Math.pow(x,y) | 计算x的y次幂 |
Math.exp(x) | e的x次方 |
Math.log(x) | x以e为底的对数 |
Math.sin(x) | x的正弦 |
Math.cos(x) | x的余弦 |
Math.tan(x) | x的正切 |
Math.asin(x) | x的反正弦 |
Math.acos(x) | x的反余弦 |
Math.atan(x) | x的反正切(-PI/2到PI/2之间) |
Math.atan2(y,x) | x轴到点(x,y)的角度 (-PI/2到PI/2之间) |
Date
类用于处理日期和时间。
Date(x)
的参数x
可以有四种情况:
new Date();//无参数,返回当前时间 new Date(millseconds);//参数为距离1970年1月1日8时0分0秒0毫秒的毫秒数,返回对应的时间 new Date(timeString);//参数为时间字符串,返回这个时间字符串对应的时间 new Date(year,month,day,hour,minute,second,millsecond);//参数为整数序列,分别表示年、月、日、时、分、秒、毫秒,返回这些时间参数对应的一个特定的时间
以上均返回一个对应的时间对象,如下:
console.log(new Date());//输出Sat Apr 07 2018 18:56:00 console.log(new Date(1000));//输出Thu Jan 01 1970 08:00:01 console.log(new Date("April 7, 2018 18:00:00"));//输出Sat Apr 07 2018 18:00:00 console.log(new Date(2018,4,7,18,0,0,0));//输出Mon May 07 2018 18:00:00
时间对象有一系列获取和设置年、月、日、时、分、秒、毫秒的函数。
为举例方便,我们先定义一个时间。
//1970年1月1日上午8点0分0秒 var date = new Date(0);
x.getFullYear()
返回x
对应的四位数年份,x
为Date
类对象;console.log(date.getFullYear());//输出1970
setFullYear(year,month,day)
用于设置年份,month
和day
可选;date.setFullYear(2017); console.log(date);//输出Sun Jan 01 2017 08:00:00
x.getMonth()
返回x
中的月份,结果在0
(一月)到11
(十二月)之间;console.log(date.getMonth());//输出0
setMonth(month,day)
作用是设置月份,0
表示一月。1
表示二月,依次类推,day
可选;date.setMonth(2);console.log(date);//输出Sun Mar 01 1970 08:00:00
x.getDate()
返回x
对象在一个月的第几天(1
到31
),x.getDay()
返回x
对象在一个星期的第几天(0
到6
,0
为周日);console.log(date.getDate());//输出1 console.log(date.getDay());//输出4
由此可见,1970
年1
月1
号那个美好的新年第一天是个周四。
setDate(day)
设置日期对象在一个月的第几天(1
到31
);date.setDate(31); console.log(date.getDate());//输出31
获取和设置时、分、秒、毫秒的函数在形式上与上面的函数几乎相同,这里以表格的形式列出:
方法 | 作用 | 参数或者结果的范围 |
---|---|---|
getHours() | 获取小时 | 0~23 |
setHours(hour,min,sec,millsec) | 设置小时 | 0 |
getMinutes() | 获取分钟 | 0~59 |
setMinutes(min,sec,millsec) | 设置分钟 | 0 |
getSeconds() | 获取秒钟 | 0~59 |
setSeconds(sec,millsec) | 设置秒钟 | 0 |
getMillSeconds() | 获取毫秒数 | 0~999 |
setMillSeconds(millsec) | 设置毫秒数 | 0~999 |
getTime() | 获取距1970年1月1日8时0分0秒的毫秒数 | 大于等于0 |
setTime(millsec) | 设置距1970年1月1日8时0分0秒的毫秒数 | 大于等于0 |
注:以上多个参数的函数,除了第一个参数外的参数都为可选。
toString()
将日期转字符串,结果类似于Sun Jan 07 2018 20:01:14 GMT+0800 (中国标准时间)
,分别表示星期、月份、天数、年份、小时、分钟、秒和时区(中国采用东八区时间)。
console.log(new Date().toString());//输出Sat Apr 07 2018 20:40:14 GMT+0800 中国标准
用法如下:
try { //运行时可能出错的代码 }catch(err) { //处理出现的错误 }
JavaScript
在运行时抛出的错误或者异常,会被catch
语句捕捉到,其中的变量err
包含了错误的有关信息。
try { console.lo("JavaScript"); }catch(err) { window.alert("发生错误,错误信息:"+err.message); } console.log("错误已处理完毕。");
第二句有语法错误,被catch
捕捉到,错误信息console.lo is not a function
通过js弹窗告知用户。用户点击弹窗上的确定后,程序继续往下运行。
如果没有进行错误处理,程序在第二句停止运行,这样后面的所有代码都不再执行。
console.lo is not a function
显然是一个系统内置的错误类型,如果用户觉得这样的错误类型不够具体,可以自定义错误类型:
throw exception;
exception
可以是字符串、数字、逻辑值或者对象,这样的错误也会被catch
语句块捕获。
//求开方的值 function mySqrt(a) { try { if(a < 0) throw new Error("错误!负数不能开平方"); if(a > 10000) throw new Error("错误!不支持大数开平方"); return Math.sqrt(a); } catch(err) { console.log("发生错误,错误信息:"+err.message); } return "error"; }
new Error()
是一个Error
对象,括号内的参数是err.message
属性的值。
JavaScript
的动态网页开发功能
Document Object Module
,简称DOM
,中文名文档对象模型。在网页上,组成页面(又叫文档)的一个个对象被组织在树形结构中,用这种结构表示它们之间的层次关系,表示文档中对象的标准模型就称为DOM
。
DOM
的作用是给HTML
文档提供一个标准的树状模型,这样开发人员就能够通过DOM
提供的接口去操作HTML
里面的元素。
先看一段网页代码:
<html> <head> <title>这里是标题</title> </head> <body> <p>这是我学习JavaScript的网址:</p> <a href="https://www.educoder.net/paths">JavaScript学习手册</a> </body> </html>
执行后效果如下:
文档元素:指的就是<html>
、<head>
等等这样一个个的标签和里面的内容。
比如文档元素<title>
就是这样:
<title>这里是标题</title>
在JavaScript
中,元素<title>
对应一个对象,这个对象有一个属性的值是“这里是标题”。
所以,用JS
操作这些文档元素,操作的就是它们对应的JS
对象。
从代码的缩进可以知道,文档元素之间有层次关系,如下:
上面的图和数据结构中树的概念类似,被称为节点树。<html>
是根节点,网页的所有文档元素都在里面,<head>
和<body>
是两个子节点,分别存储网页标题有关内容和网页的主体部分。
JavaScript
要操作这些元素,第一步自然是获得这些元素对应的JavaScript
对象,那么,怎么获取呢?
文档元素一般都有一个id
属性,它的值在本文档中唯一,如下:
<p id="myId">这是我学习JavaScript的网址:</p>
用这个id
获取<p>
元素的方法如下:
var pElement = document.getElementById("myId");
其中document
表示整个文档,getElementById()
是document
对象的一个方法,参数是id
属性的值myId
。
获取的pElement
就代表了<p>
标签以及里面的内容,接下来,可以通过pElement
操作这个元素。比如可以用弹框展示一下<p>
标签里面的内容:
window.alert(pElement.innerText);
除了id
以外,文档元素另外一个常见的属性是类名。
文档元素的类名不唯一(存在多个文档元素的类名相同的情况),如下:
<p class="myName">段落</p> <a class="myName" href="https://www.educoder.net">这是一个链接</a>
document
的getElementsByClassName()
方法用来获取指定类名的文档元素数组(NodeList
,一般叫节点列表),如下:
var myNodeList = document.getElementsByClassName("myName");
这样,myNodeList[0]
就是<p>
元素,而myNodeList[1]
就是<a>
元素,通过这个方法的名字我们也可以知道获取的标签不唯一。
我们以弹框的形式查看一下<p>
里面的内容:
window.alert(myNodeList[0].innerText);
效果如下:
标签名指的是<>
里面的字符串,document
对象的getElementsByTagName()
获取整个文档中指定名字的所有标签,显然,结果是一个文档元素数组(节点列表),方法的名字也暗示了这一点。
<div id="div1"> <p id="p1">文本1</p> <p id="p2">文本2</p> <a name="a1">链接</a> </div><div id="div2"> <p id="p3" name="a1">文本3</p> </div>
获取所有的<div>
元素,如下:
var allDiv = document.getElementsByTagName("div");
为了显示效果,我们以页面弹框的形式展示第一个<div>
里面的内容:
window.alert(allDiv[0]);
效果如下:
这个弹框表明,我们试图弹出的内容是一个div
元素。
我们获取到的文档元素,也有getElementsByTagName()
方法,作用是获取该元素内部指定名字的所有子元素。比如,要获取第一个<div>
里面所有的<a>
元素,代码如下:
//变量allDiv上面有,这里不再重复! var allLink = allDiv[0].getElementsByTagName("a");
这样就获取了第一个<div>
里面的所有超链接元素。
css
选择器是干什么用的?简单来说,选择你想要的元素的样式。
这一块的内容对于没有学习过css
的同学来说比较难,我们分三步来理解:
第一步:先看一段html
代码:
<body> <p> CSS选择器 </p> </body>
运行的效果如下:
第二步:我们想把字体改为红色,需要使用css
来处理,假设我们已经有了一段css
代码:
.css1{ color:red; } #css2{ color:blue; }
前四行是一个名字为css1
的选择器,它是一种类选择器;后四行是一个名字为css2
的选择器,它是一种id选择器。
第三步:有了css
,我们还要把它和html
关联起来,比如我们想在p
元素上使用第一个选择器,反过来说:就是第一个选择器选择了p
元素(将它的样式应用在p
元素上)。那么给p
元素新增一个class
属性,它的值是css1
:
<body> <p class="css1"> CSS选择器 </p></body>
再来看一下效果:
这样p
元素就选择了名字为css1
的样式(反过来说也行),如果p
元素要选择名为css2
的样式,因为css2
是id
选择器,需要设置id
属性的值为css2
:
<body> <p id="css2"> CSS选择器 </p></body>
效果如下:
querySelector
返回匹配指定css
选择器的第一个元素。
以上面的html
代码作为例子,比如我们想要获得class="css1"
的元素:
css1
是一个类选择器,在css
代码里面的完整表示为.css1
,那么这个.css1
直接作为querySelector
的参数,即可获得class="css1"
的元素:
var myElement = document.querySelector(".css1"); console.log(myElement.innerText);//输出“CSS选择器”
总结一下就是:用css
选择器的完整名字作为querySelector
的参数,就可以获取该选择器控制的所有元素。
需要注意的是,querySelector
只返回一个元素,如果指定的选择器控制的元素有多个,返回第一个,下面是一个例子:
先看一段html
代码:
<body> <div class="myClass">文本1</div> <div class="myClass">文本2</div> <div class="myClass">文本3</div> </body>
显然,类名为myClass
的div
元素有3
个,使用querySelector
在控制台输出类名为myClass
的元素,看能输出几个:
var myClassElement = document.querySelector(".myClass"); console.log(myClassElement);
F12
查看一下浏览器的控制台,效果如下:
很明显,querySelector
方法只能获得第一个类名为myClass
的元素。
querySelector
只能获得第一个符合要求的文档元素,显然,我们需要一个能获取所有符合要求的文档元素的方法,querySelectorAll
就是负责这项工作的。
如果一个选择器控制的元素有多个,而且我们需要取到这些元素,就需要用querySelectorAll
方法,该方法返回指定的选择器对应的多个元素。
回顾一下前面出现过的这张图:
定义几个概念:
9
时表示Document
节点(整个文档);值为1
表示Element
节点,即前面反复提到的文档元素;值为3
表示Text
节点,即节点里面的内容为纯文本,如<p>
节点。先给一段html
代码:
<body> <div id="div1"> <div class="cl1"> <p>文本</p> <a>超链接</a> </div> <div class="cl2"> <select id="se"> <option>红</option> <option>黄</option> <option>蓝</option> </select> </div> </div> </body>
首先,我们获取最外层的div
节点:
var div1 = document.getElementById("div1");
然后获取它的第一个子节点(class
值为cl1
的节点):
//firstElementChild表示第一个子节点 var cl1 = div1.firstElementChild;
再获取cl1
的最后一个子节点,即a
节点:
//lastElementChild表示最后一个子节点 var aElement = cl1.lastElementChild;
在控制台打印出获取到的节点里面的文本:
console.log(aElement.innerText);
通过这个例子可以看出,我们的思路是顺着这个节点树从根部一直往下找,即顺着箭头的方向直到目标节点。
previousElementSibling
表示前一个兄弟节点。比如获取上面的超链接的前一个节点p
,然后在控制台打印p
的内容,代码以及效果如下:
var left = aElement.previousElementSibling; console.log(left.innerText);
nextElementSibling
表示后一个兄弟节点。显然,上面的p
元素的后一个兄弟节点是a
元素,打印一下a
的内容:
var right = left.nextElementSibling; console.log(right.innerText);
children[0]
表示第一个子节点,以此类推。比如依次在控制台打印出上面的select
标签的三个子节点:
var selectTag = document.getElementById("se"); console.log(selectTag.children[0].innerText); console.log(selectTag.children[1].innerText); console.log(selectTag.children[2].innerText);
效果如下:
children.length:子节点的个数;
console.log(selectTag.children.length);//输出3
通过前面的学习,我们可以发现,文档元素后面都会跟着相应的属性,比如<a>
后面都会有一个href
属性,用来表示超链接的地址,即点击这个超链接后跳往的目标页的地址。
怎么获取属性值呢?先看一段html
代码:
<a href="https://www.educoder.net" target="_blank">EduCoder</a>
先获取文档元素:
var aElement = document.getElementsByTagName("a").[0];
然后通过获取到的元素的属性名来得到属性值:
var hrefValue = aElement.href;console.log(hrefValue);//输出https://www.educoder.net
从上面可以看出,文档元素.属性名
即获得了该属性的值。
getAttribute(a)
用来获取属性值,a
表示属性的名字。比如上面获取超链接的href
属性值,也可以这样写:
console.log(aElement.getAttribute("href"));//输出https://www.educoder.net
区别是:getAttribute()
返回的值统一为字符串,而第一种方法会返回属性实际的值,比如<input>
的maxLength
属性的值应该是数值,第一种方法就会返回数值,getAttribute()
返回了字符串:
<input type="name" maxLength=16 id="inputId"/> //typeof检测变量的类型 var result1 = document.getElementById("inputId").maxLength;//返回16 var result2 = document.getElementById("inputId").getAttribute("maxLength");//返回"16" console.log(typeof(result1));//输出number console.log(typeof(result2));//输出string
class
等文档元素的属性,不能直接用文档元素对象.class
来获取,因为class
是JavaScript
中的关键字,需要用className
来代替。
但是,如果用的是getAttribute()
,直接用class
作为参数就行。
<a class="aClass" id="aId">超链接</a> document.getElementById("aId").className;//返回"aClass" document.getElementById("aId").getAttribute("class");//返回"aClass"
文档元素属性的值,除了可以获取外,当然也可以设置。设置属性的值也有两种方法。
用=
连接,左边是你要设置的属性变量,右边是你要赋予这个属性的具体的值。比如:
<a id="a1" href="https://www.google.com">EduCoder</a>
设置超链接的href
属性的值的表达式如下:
document.getElementById("a1").href="https://www.educoder.net";
这样,a
标签的href
属性的值就变成了https://www.educoder.net
。
需要注意:标签之间的文本用innerText
属性表示,要修改上面超链接里面的文本,需要这样:
document.getElementById("a1").innerText="educoder";
没错,setAttribute(a,b)
就是一个与getAttribute()
对应的方法,参数a
是你要设置的属性的名字,参数b
是你要设置的属性的值。
所以上面的操作(设置href
)也可以这样写:
document.getElementById("a1").setAttribute("href","https://www.educoder.net");
document.createElement("tagName")
用来创建一个新的Element
节点(即文档元素),返回值是新创建的节点,tagName
是标签的名字,比如a
、p
、img
等,需要注意的是它不区分大小写。
比如创建一个新的超链接节点:
var newA = document.createElement("a");//创建超链接节点 newA.src = "https://www.educoder.net";//设置超链接的目的地址
ul
标签在html
中表示无序列表,li
标签标识其中的列表项。
插入节点:插入一个新的文档元素。最常见的应用就是在<select>
标签里插入一个新的<option>
标签。
两种可选的方法:
node1.appendChild(node2)
表示将node2
插入到node1
的最后一个子节点中。
比如原来的选择框是这样:
<select id="s1"> <option id="cs">长沙</option> <option id="zz">株洲</option> </select>
要增加多一个选项“湘潭”,实现代码如下:
var node1 = document.getElementById("s1"); var node2 = document.createElement("option"); node2.innerText = "湘潭"; node1.appendChild(node2);
pNode.insertBefore(node1,node2)
:将node1
插入作为pNode
的子节点,并且node1
排在已存在的子节点node2
的前面。
比如要把最开始的复选框变成这样:
<select id="s1"> <option id="cs">长沙</option> <option>湘潭</option> <option id="zz">株洲</option> </select>
我们需要像下面这样操作节点:
var pNode = document.getElementById("s1"); var node1 = document.createElement("option"); node1.innerText = "湘潭"; var node2 = document.getElementById("zz");//将内容为"湘潭"的节点插入到内容为"株洲"的节点前面 pNode.insertBefore(node1,node2);
删除节点的方法是removeChild()
,调用者是父节点,参数是子节点,作用是删除这个子节点。
第一步:获取父节点,即ul
节点:
var parentNode = document.getElementById("parent");
第二步:获取待删除的子结点:
var childNode = document.getElementById("child3");
第三步:父节点调用removeChild()
方法删除子节点:
parentNode.removeChild(childNode);
replaceChild(a,b)
的调用者是要被替换的节点的父节点,a
是新的节点,b
是被替换的节点。
第一步,获取父节点:
var parNode = document.getElementById("parent");
第二步,获取要被替换的子节点:
var oldNode = document.getElementById("child3");
第三步,创建新节点:
var newChild = document.createElement("li");newChild.innerText = "武夷山";
第四步,替换:
parNode.replaceChild(newChild,oldNode);
页面上的每一个元素,会发生几种不同的事件,比如表单元素,可能会发生提交事件,也可能发生重置事件,我们需要为每一个事件绑定一个事件处理程序,也叫为事件注册事件处理程序。
下面是三种注册事件处理程序的方法。
页面上的元素对应一个JavaScript
对象,元素的每一个事件对应对象的一个属性,比如:
<form id="myForm"></form> var myForm = document.getElementById("myForm");
myForm
对应页面中id
值为myForm
的表单,myForm.onsubmit
对应表单提交事件,myForm.onreset
对应表单重置事件。通过为这些属性设置一个函数类型的值,实现事件处理程序的注册:
//为表单提交事件注册处理程序 myForm.onsubmit = function() { console.log("表单提交的事件处理程序"); } //为表单重置事件注册处理程序 myForm.onreset = function() { console.log("表单重置的事件处理程序"); }
比如,设置form
标签的onsubmit
属性的值为事件处理程序:
<form οnsubmit="submitForm()"></form> function submitForm() { console.log("表单提交的事件处理程序");}
这样提交表单时,就会触发submitForm()
函数。
页面元素对应的JS
对象,通过调用addEventListener()
函数也可以注册事件处理程序,函数的第一个参数是事件的类型,第二个参数是事件处理程序:
<form id="myForm"></form> var myForm = document.getElementById("myForm"); myForm.addEventListener("submit",function() { console.log("表单提交中");});
submit
表示这是一个表单提交事件,后面的匿名函数即表单提交的事件处理程序。
文档,指的是网页上的所有元素构成的一种格式化文本。文档加载事件指浏览器从服务器下载并渲染完文档后发生的事件。
文档加载事件名字为load
。
当文档加载完成后,就会触发文档加载事件监听程序(即上一关所说的事件处理程序),一般我们会在这个时候监测用户浏览器的类型、版本,从而加载不同的脚本。
在大多数情况下,文档记载事件绑定在body
元素上,表示网页主体加载完成后触发该事件,也有少数情况下绑定在image
等元素上,表示相关的元素加载完成后触发该事件。
文档加载完成后监测用户的浏览器类型并在控制台打印:
<body οnlοad="detectBrowser()"></body> function detectBrowser(){ var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串 if (userAgent.indexOf("Opera") > -1) {//判断是否是Opera浏览器 console.log("Opera"); }; if (userAgent.indexOf("Firefox") > -1) { //判断是否是Firefox浏览器 console.log("Firefox"); } if (userAgent.indexOf("Chrome") > -1) { //判断是否是Chrome浏览器 console.log("Chrome"); } if (userAgent.indexOf("Safari") > -1) {//判断是否是Safari浏览器 console.log("Safari"); } if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1) { console.log("IE"); }; }
说到鼠标事件,最常见的无非是鼠标单击事件click
,很多按钮都会绑定一个onclick()
函数,表示当用户单击鼠标后会执行的函数。其实还有很多鼠标事件,比如双击鼠标、按下鼠标等,下面是一个总结:
类型 | 事件处理函数 | 触发条件 |
---|---|---|
click | onclick | 按下并且释放鼠标 |
dbclick | ondbclick | 双击鼠标 |
mousedown | onmousedown | 按下鼠标按键 |
mouseup | onmouseup | 释放鼠标按键 |
mousemove | onmousemove | 移动鼠标 |
mouseover | onmouseover | 鼠标进入元素 |
mouseout | onmouseout | 鼠标离开元素 |
为页面上的某一个元素绑定一个鼠标事件,当用户在该元素上用鼠标执行了指定的动作后,就会触发指定的鼠标事件处理程序,开始执行函数。
mousedowm
表示鼠标按下的事件,onmousedown
是用户按下鼠标后会触发的事件处理程序;mouseup
表示鼠标按键释放的事件,onmouseup
表示用户释放鼠标按键后会触发的事件处理函数。
下面是一个例子,页面上有一行文字“点我”,用户在文字上按下鼠标按键后,文字会变成“鼠标已经按下”,而用户释放鼠标后,文字会变成“鼠标已经释放”。
html
代码如下:
<body> <p id="p" οnmοusedοwn="downfunc()" οnmοuseup="upfunc()"> 点我 </p> </body>
页面的效果如下:
事件处理函数的代码如下:
function downfunc() { document.getElementById("p").innerText = "鼠标已经按下"; } function upfunc() { document.getElementById("p").innerText = "鼠标已经释放"; }
用户在文字上面先按下鼠标,再释放鼠标,效果如下:
键盘事件,是指用户敲击键盘上的按键所代表的事件。
键盘事件有三种:
keydown
,用户按下键盘上的键;keyup
,用户释放按键;keypress
,用户按下并且释放了按键。keypress
表示用户点击某个按键的事件,该事件会触发onkeypress()
事件处理程序,onkeypress()
有一个event
参数,其中event.which
表示点击的按键的编码。这个编码是该按键的unicode
编码。
需要注意的是,按下键盘上的A
时,keyCode
值是a
的编码,只有同时按下shift
和A
,keyCode
的值才是A
的编码。
下面是一个例子,当用户点击键盘上的按键时,会打印出该按键的编码值:
<body οnkeypress="keyEvent(event)"> <p> keypress event </p> </body> <script> function keyEvent(event) { //如果按下"B",编码是;98(int) console.log("编码是:"+event.which); } </script>
keydown
表示用户按下按键,同上面一样,它也有一个event.which
表示按下的按键的编码。
<body οnkeydοwn="downEvent(event)"></body> <script> function downEvent(event) { console.log("编码是:"+event.which); } </script>
如果你按下按键后没有释放,控制台将会一直进行打印,比如按下的是1
,控制台的打印结果如下:
灰色的数字20
表示这条信息已经打印了20
次。
keyup
表示用户释放按键,可以有一个参数event
,event.which
表示释放的按键的编码。
<body οnkeyup="upEvent(event)"></body> <script> function upEvent(event) { console.log("编码是:"+event.which); } </script>
比如,当用户按下1
时,控制台没有输出,释放1
后,控制台输出如下:
表单,即form
,是页面最基本的元素之一,通常,用户的输入会放置在表单里面,然后提交给后台。
form
有很多子元素,分别表示不同类型的用户输入:例如input
表示文本等类型;select
表示下拉列表;button
表示按钮。
这些子元素可以被绑定一些事件,比如change
表示用户的输入发生了改变。这些事件是表单元素特有的。
change
事件表示当前元素失去焦点并且元素的内容发生了改变。失去焦点,指光标不在该元素上,比如光标本来在文本输入框里面,当用户在页面的其他地方点击了鼠标,文本框就会失去焦点。
下面是一个例子:当用户输入文本,并且鼠标点击页面上的其他地方后,我们将在控制台打印出用户的输入。
<body> <form> <input id="t1" type="text" οnchange="changeEve()"/> </form> <script> function changeEve() { var e = document.getElementById("t1"); console.log(e.value); } </script> </body>
比如当用户输入I changed
后,在页面的其他地方点击鼠标,控制台如下:
select
事件:文本框中的文本被用户选中时发生。
只能作用在<input type="text">
的文本框里面,可以用window.getSelection().toString()
获取选择的文本。
下面的例子:当用户选择了一段文本后,我们在控制台打印出用户选择的文本:
<body> <input type="text" value="赵钱孙李,周吴郑王" οnselect="selectEve()"/> <script> function selectEve() { console.log(window.getSelection().toString()); } </script> </body>
比如我们选择了郑王
,然后松开鼠标,控制台的输出如下:
表单的提交事件。
表单里面包含了用户输入的信息,最终要传到后台的服务器进行处理,这样就有一个表单的提交过程,submit
即表单提交事件。
通常情况下,在submit
的事件处理函数中,校验用户的输入是否符合要求,比如密码的长度够不够。
下面的例子,用户提交表单时,用js
校验用户输入的密码长度是否达到6
位。
<body> <form οnsubmit="subEve()"> <input type="password" id="pw"/> <input type="submit" value="提交" /> </form> <script> function subEve() { var content = document.getElementById("pw").value; if (content.length < 6) { window.alert("密码不可以小于6位"); } } </script> </body>
这时,用户在密码输入框输入123
,点击提交,页面会弹出一个警告框如下:
鼠标指向元素,按下鼠标,然后移动鼠标到另一个地方释放,即拖动元素。
相比html4
以及之前的版本,html5
增加了一个全新的属性draggable
,表示元素是否支持拖动,默认的情况下,图片和超链接元素是支持拖动的,其他元素不支持。
将元素的draggable
属性设置为true
,即表示元素支持拖动。如:下面设置了p
元素支持拖动:
<p id="p1" draggable="true"> 元素支持鼠标的拖动</p>
也可以用下面的JavaScript
代码设置p
为可拖动的:
document.getElementById("p1").draggable = true;
ondrag()
是元素正在拖动时触发的事件处理程序。如果元素一直在拖动的过程中,ondrag()
会每隔350ms
被触发一次,比如,在下面的例子中,我们一直在拖动p
元素,控制台会一直打印拖动的信息。
<body> <div> <p οndrag="dragging(event)" draggable="true">拖动我!</p> </div> <script> function dragging(event) { console.log("正在拖动"); } </script> </body>
用户开始拖动元素时触发,可以带有一个event
参数,其中的event.target
表示拖动的元素,比如,下面的例子中,用户开始拖动元素时,触发了ondragstart
程序,我们尝试打印一下event.target
的内容:
<body> <p οndragstart="dragStart(event)" draggable="true">拖动我!</p> <script> function dragStart(event) { console.log(event.target); console.log("你要拖动的文本的内容是:"+event.target.innerText); } </script> </body>
拖动文本,效果如下:
第一行是要拖动的文本元素,第二行显示了文本里面的内容。
在前面的学习中,我们说过,文档元素之间有层次关系,比如:
<body> <div οnclick="clickParent()"> <p οnclick="clickChild()">点我</p> <p id="p">content</p> </div> <script> function clickChild() { console.log("子"); } function clickParent() { console.log("父"); } </script> </body>
对应这样一个模型:
其中,箭头的方向是子节点的方向,而反过来则是父节点的方向。比如,两个p
元素的父节点(父元素)都是div
元素。
在上面的例子中,点击p
元素里面的内容,显然会触发p
元素的事件处理程序clickChild
。然后,因为p
元素是放在div
里面的,点击p
元素相当于点击了div
元素,会触发div
的事件处理程序clickParent
,这个过程被称为事件冒泡。
事件冒泡是指,某个事件触发了某个元素的事件处理程序,接下来,就会自动沿着节点树往根节点的方向依次触发经过的路径上的所有元素的某个事件的处理程序。
比如上面的例子中,用鼠标点击p
标签里面的文字点我
,控制台的打印结果为: “子 父”。
第一行是子元素的click
事件的事件处理程序的输出,第二行是父元素的,这里有一个先后的顺序,即从子元素一直到根节点。
事件冒泡不是所有的时候都受到欢迎,有的时候需要控制它的发生,使用event.stopPropagation()
即可。
比如,对于上面的例子,我们在子元素的事件处理程序clickChild()
的最后一行添加一行代码:
function clickChild() { console.log("子"); window.event?window.event.cancelBubble=true:event.stopPropagation(); }
这个时候再次点击p
里面的内容,控制台的输出: “子”。
JavaScript
中定时器的作用是在指定的时间或者时间间隔之后执行函数,可以用来对网页上的数据做实时的更新,比如网页上的北京时间的更新:
定时器的实现有两种方式,一个是window.setTimeout()
函数,一个是window.setInterval()
函数。
window.setTimeout(a,b)
用来指定函数a
在延迟b
毫秒时间后执行,即在window.setTimeout(a,b)
这句话开始执行的b
毫秒之后,再执行a
函数。
比如下面的例子中,我们点击页面上的文字,经过4
秒的延迟后弹出警告框:
<body> <p οnclick="al()"> 单击此处4秒后弹出警告框 </p> <script> var id; function al() { id = window.setTimeout(showAlert,4000); } function showAlert() { window.alert("警告框"); } </script> </body>
点击文字会触发函数a1()
,在这个函数里面设置了一个定时任务showAlert()
,定时的时间为4
秒之后。即:点击文字4
秒之后会执行showAlert()
函数。
上面代码里的变量id
是用来唯一标识这个定时任务的,它的作用是,作为函数window.clearTimeout(id)
的参数,而这个函数是用来在定时任务发生之前关闭定时任务,这好比,早晨我们在闹钟响之前关掉闹钟。
setInterval(a,b)
:每隔b
毫秒,执行一次a
函数。
下面的例子,每隔一秒钟,更新一下网页上的时间:
<body> <p οnclick="updateTime()"> 开始更新时间 </p> <p id="timeContainer"> </p> <script> var id; function updateTime() { id = window.setInterval(showTime,1000); } function showTime(){ document.getElementById("timeContainer").innerText = new Date(); } </script> </body>
点击“开始更新时间”,触发updateTime()
函数,该函数开启一个循环定时任务showTime()
,showTime()
的作用是更新网页上显示的时间。
window.clearInterval(id)
也是停止定时任务,其中的id
就是上面例子里面的变量id
,这个是为了唯一标识某一个定时任务,防止错误的取消了别的定时任务。
location
对象就是window.location
,记载了浏览器当前所在的窗口的URL
(统一资源定位符)信息,它常常被用来实现网页的跳转。
location.href
属性表示当前窗口所在页面的地址。
#这个结果应当和浏览器地址栏上内容一样 <body> <script> console.log(window.location.href); </script></body>
window.location.href
还是可写的,如果把它设置为一个新的地址,当前窗口将立即打开这个新的地址,这是实现页面跳转的一种方式。比如下面的例子:
<body> <p οnclick="toNew()"> 点我调到EduCoder首页 </p> <script> function toNew() { window.location.href = "https://www.educoder.net"; } </script> </body>
假设,当前浏览器地址栏的内容是:https://www.educoder.net:8080/shixun.html?tab=1
。我们用一个表格看一下location
对象的所有属性:
属性名 | 解释 | 属性的值 |
---|---|---|
host | 主机名和端口号 | www.educoder.net:8080 |
hostname | 主机名 | www.educoder.net |
pathname | 路径部分 | /shixun.html |
port | 端口号 | 8080 |
protocal | 协议 | https |
search | 问号开始的查询部分 | ?tab=1 |
以下用一个例子打印所有这些属性,假设我们在https://www.educoder.net:8080/shixun.html?tab=1
这个页面:
<body οnlοad="printInfo()"> location attribute <script> function printInfo() { var loc = window.location; console.log("host:"+loc.host); console.log("hostname:"+loc.hostname); console.log("pathname:"+loc.pathname); console.log("port:"+loc.port); console.log("protocal:"+loc.protocal); console.log("search:"+loc.search); } </script> </body>
载入页面后,打印结果如下:
对话框就是在浏览器页面上再弹出一个小的窗口,用于和用户直接互动,window
对象的alert()
、confirm()
和prompt()
三个方法都是用来显示对话框的。
window.alert(msg)
弹出一个警告框,表示向用户发送一条通知。前面的相关知识已经多次讲过alert()
的用法。
需要注意的是,alert()
方法弹出警告框后,其后的代码会暂停执行,直到警告框被关闭,即:alert()
方法是阻塞的。
下面的例子中,关闭警告框后,控制台才会打印信息:
<body> <p onclick="showAlert()">点我弹出警告框</p> <script> function showAlert() { window.alert("先弹出一个警告框"); console.log("然后才能在控制台打印信息"); } </script> </body>
window.confirm(msg)
弹出一个确认框,msg
是需要用户确认的信息,用户在弹出的框里面选择确认或者取消后,会返回true
或者false
。
<body> <p οnclick="showConfirm()">点我弹出确认框</p> <script> function showConfirm() { var result = window.confirm("确定今天是周五?"); console.log(result); } </script> </body>
window.prompt(a,b)
弹出一个输入框,供用户输入关键信息。其中a
是输入框的提示语,b
是输入框里面默认的内容。
如果用户不输入,直接点击确认,返回b
。如果点击取消,返回null
。
浏览器的一个标签页叫做一个窗口,window
对象可以操作浏览器窗口的打开与关闭。
window.open(url,name,specs,replace)
用来打开一个浏览器的窗口,它有四个参数:
url
表示窗口里面的文档的地址;
name
有两种情况。
如果name
里面是窗口的名字。浏览器会先判断这个窗口是否已经打开。已经打开则用新的url
里面的文档替换这个窗口里面原来的文档,反映到浏览器上是不会有新的标签页打开,但是一个已存在的标签页会刷新。没有打开则打开一个新的窗口,并且载入url
里面的文档。
如果name
是_blank
、_self
里面中的任何一个,它的含义如下:
值 | 含义 |
---|---|
_blank | 打开新的窗口,载入地址为url的文档 |
_self | 不打开新的窗口,用地址为url的文档替换掉当前的文档 |
specs
是用来控制新窗口的尺寸等特征,比如值为width=200,height=100
时,表示新窗口宽度为200px
,高度为100px
。
replace
用来控制新的窗口在浏览器的浏览历史里面如何显示。为true
表示装载到窗口的url
替换掉浏览历史中的当前条目;为false
表示装载到窗口的url
创建一个新的条目。
下面的例子展示了这些参数的具体用法:
<body> <p οnclick="openNewWindow()">name是一个窗口的名字,打开一个新的窗口,载入新的文档</p> <p οnclick="openOldWindow()">name是一个窗口的名字,打开已存在的窗口,替换掉里面的文档</p> <p οnclick="blankWindow()">name是一个target属性,值为_blank</p> <p οnclick="selfWindow()">name是一个target属性,值为_self</p> <script> function openNewWindow() { window.open("Demo1.html", "windowName"); } function openOldWindow() { window.open("Demo2.html", "windowName"); } function blankWindow() { window.open("Demo1.html", "_blank"); } function selfWindow() { window.open("Demo1.html", "_self"); } </script> </body>
效果如下所示:
如上所示,第一种情况,name
是一个窗口的名字,因为这个窗口还没有打开,所以会打开一个新的窗口,并载入url
文档。
第二种情况,name
是一个窗口的名字,因为这个窗口已打开,所以新的文档会替换掉原来的文档。
第三种情况,name
值为_blank
,会直接打开一个新的窗口。
第四种情况,name
值为_self
,会用url
里面的文档替换掉当前窗口的文档,不会打开新的窗口。
上面的window.open()
会有一个返回值result
,result.close()
用来关闭打开的窗口。比如下面的例子:
<body> <p οnclick="openNewWindow()">打开新窗口</p> <p οnclick="closeNewWindow()">关闭新窗口</p> <script> var w; function openNewWindow() { w = window.open("Demo1.html", "windowName"); } function closeNewWindow() { w.close(); } </script> </body>
相信大家都见过这样的下拉框:
它有三列,每一列都会根据前一列的结果动态的改变自己的可选项,称为下拉框的级联,那么如何实现呢?
第一步:静态的HTML的代码如下(简单起见,只考虑前两列):
<select id="province" onChange="changeCity()"> <option value="BeiJing" id="bj">北京</option> <option value="AnHui" id="ah">安徽</option> </select> <select id="city"> <option value="BeiJingCity">北京市</option> </select>
select
表示选择框,option
表示选择框里面的每一个选项,onChange="changeCity()"
表示一旦改变当前的选项,就会触发JavaScript
函数changeCity()
的执行。
对于这个静态的HTML
页面,不论你在第一列选择的是北京
还是安徽
,第二列的选项都只有北京市
一项。
第二步:获取两个选择框对应的节点元素 (以下的所有代码都是changeCity()
函数里面的内容):
var province = document.getElementById("province"); var city = document.getElementById("city");
province
变量代表第一列的选择框,city
变量代表第二列的选择框。
第三步:清空第二列中的所有内容; 根据第一列的选择结果改变第二列的内容,就是根据父节点的不同替换不同的子节点,我们采用先删除后新增的方法实现替换:
var length = city.children.length; for(var i = length-1;i >= 0;i--) { city.removeChild(city.children[i]); }
在for
循环里面,依次删除city
节点下面的所有子节点。
需要注意的是,每删除一个子节点后,表示子节点个数的属性city.children.length
都会自动减1
,所以我们需要在for
循环开始之前索取子节点的长度。
第四步:根据父节点的不同新增不同的子节点:
if(province.value == "BeiJing") { var child1 = document.createElement("option"); child1.value ="BeiJingCity"; child1.innerText="北京市" city.appendChild(child1); } else { var child1 = document.createElement("option"); child1.value="HuangShanCity"; child1.innerText="黄山市"; city.appendChild(child1); }
province.value
表示第一列选中的选项的值,即选中的option
标签的value
的值。
如果第一列选择的是北京
,我们需要增加一个选项为北京市
的option
节点,这个节点将作为city
的子节点。如果第一列选择的是安徽
,我们需要增加一个选项为黄山市
的option
节点,这个节点将作为city
的子节点。
value
属性表示option
标签的值,innerText
表示option
标签呈现出来的值。
<html> <head> <title>myTitle</title> <meta charset="utf-8" /> </head> <body> <select id="province" onChange="changeCity()"> <option value="BeiJing" id="bj">北京</option> <option value="AnHui" id="ah">安徽</option> </select> <select id="city"> <option value="BeiJingCity">北京市</option> </select> <script> function changeCity() { var province = document.getElementById("province"); var city = document.getElementById("city"); var length = city.children.length; for(var i = length-1;i >= 0;i--) { city.removeChild(city.children[i]); } if(province.value == "BeiJing") { var child1 = document.createElement("option"); child1.value="BeiJingCity"; child1.innerText="北京市" city.appendChild(child1); } else { var child1 = document.createElement("option"); child1.value="HuangShanCity"; child1.innerText="黄山市"; city.appendChild(child1); var child2 = document.createElement("option"); child2.value= "HeFeiCity"; child2.innerText = "合肥市"; city.appendChild(child2); } } </script> </body> </html>
主要知识点:鼠标事件+CSS绝对位置
在按钮上增加鼠标事件监听,否定代码的事件主要是点击之后更改为随机位置。
<script> function clickYesButton (){ var but = document.getElementById("yes"); but.innerText = "就这么说定了"; } function clickNoButton (){ var but = document.getElementById("no"); var ran1 = Math.random()*400+10; var ran2 = Math.random()*400+10; str = "position:absolute;top:"+ran1+"px;left:"+ran2+"px"; but.style=str; } var yesButton = document.getElementById("yes"); yesButton.addEventListener("click",clickYesButton); var noButton = document.getElementById("no"); noButton.addEventListener("click",clickNoButton); </script>
其中HTML中按钮的声明为,注意其中的位置是“绝对的”。
</div> <div id="yes" align="center" style="position:absolute;top:40px;left:20px"> <button>接受</button> </div> <div id="no" align="center" style="position:absolute;top:80px;left:20px"> <button>拒绝</button> </div>
在按钮上面随便提出一个问题,修改下文案,对方就不能够拒绝你啦~
效果如下: