BOM
BOM:浏览器对象模型
window是浏览器内置中的全局对象,我们学习的所有Web APIs的知识内容,都是基于window对象实现的
window对象下包含了navigator、location、document、history、screen等5个属性,也就是所谓的BOM(浏览器对象模型)
document是实现DOM的基础,他其实是依附于window的属性
延迟函数+案例
setTimeout:JavaScript中内置的一个用来让代码延迟执行的函数
语法:
setTimeout(回调函数,等待的毫秒数)
他与setInterval()不同的是:setTimeout只会执行一次,可以理解为就是把一段代码、延迟执行,平时省略window
let timer = setTimeour(回调函数,等待的毫秒数)
clearTimeout(timer)
递归函数
递归函数:自己调用自己
let num = 0
function fn(){
num++
console.log(111)
if(num>=10){
return
}
//在函数里面,调用自己
fn()
}
fn()
使用递归函数:一定要写退出条件!!!
递归与setTimeou
setTimeout结合递归函数,模拟setInterval重复执行
let div = document.querySelector('div')
function fn(){
div.innerHTML = new Date().toLocaleString()
setTimeout(fn,1000)
}
fn()
JavaScript执行机制(重要)
1.2经典面试题
console.log(1111)
setTimeout(function(){
console.log(2222)
},1000)
console.log(3333)
输出结果:1111、3333、2222;js不会等定时器结束了才执行下面的代码。
1.3
console.log(1111)
setTimeout(function(){
console.log(2222)
},0)
console.log(3333)
输出结果:1111、3333、2222
JavaScript是单线程的,同一个时间、只能做一件事。
JavaScript是为了处理页面中用户的交互,以及操作DOM的。比如我们对某个DOM进行添加和删除、不能同时进行。应该先添加、后删除!
单线程就意味着:所有的任务需要排队,前一个任务结束后、才会执行下一个任务。这样导致了:如果JS的执行时间过长,就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
同步和异步
为了解决单线程存在的缺陷、利用多核CPU的计算能力,HTML5提出了一个标准,允许JavaScript创建多个线程、于是JS中出现了同步和异步。
同步:前一个任务结束后、再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的。
异步:在做这件事的同时,还可以去处理其他的事情。
同步任务:都在主线程上执行,形成一个执行线
异步任务:JS的异步是通过回调函数实现的
同步和异步被分别放到执行栈(同步)和执行队列(异步);
JS执行机制:
先执行执行栈中的同步任务
异步任务放入任务队列中
一旦执行栈中的所有同步任务执行完毕后、系统就会按照次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈、开始执行。
事件click、setTimeout、load加载、都是异步任务
console.log(1)
document.addEventListener('click',function(){
console.log(4)
})
console.log(2)
setTimeout(function(){
console.log(3)
},3000)
输出:1234或1243
location对象
location的数据类型是对象,他拆分并保存了URL地址的各个组成部分
常用的属性和方法:
href属性:获取完整的URL地址,对其赋值时用于地址的跳转
可以得到当前文件的URL地址
console.log(location.href)
可以通过js方式跳转到目标地址
location.href = 'http://www.baidu.com'
<a href = "http://www.njtech.edu.cn/">支付成功,5秒之后跳转首页</a>
let a = document.querySelector('a')
let num = 5
let timer = setInterval(()=>{
num--
a.innerHTML = `支付成功,${num}秒之后跳转首页`
if(num==0){
clearInterval(timer)
location.href = "http://www.njtech.edu.cn"
}
},1000)
search属性:获取地址中携带的参数,符号?后面部分
点击提交后,将input中的数据传给target.html
<form action = "target.html">
<input type = "text" name = "username">
<button>提交</button>
</form>
target.html
可以拿到index.html传来的数据信息
console.log(location.search)//?username = abc
hash属性:获取地址中的哈希值,符号#后面部分
#号最大的优势就是:页面不刷新、意味着不会重新加载资源
<a href = "#one"></a>
<a href = "#two"></a>
console.log(location.hash)//点击a标签后,返回#one或者#two
reload属性:用来刷新当前页面,传入参数true时、表示强制刷新
let btn = document.querySelector('button')
btn.addEventListener('click',function(){
location.reload(true)
})
普通刷新的时候,如果我前一次打开过这个网站,浏览器会帮我把网站中的一些图片资源什么的,存储到本地缓存中,再次普通刷新后,能够比第一次打开网页更快
ctrl+f5:强制刷新:不保存到本地存储,页面是最新的
navigator对象
navigator的数据类型是对象,该对象记录下浏览器自身的相关信息。
通过userAgent检测浏览器的版本及平台
//检测userAgent(浏览器信息)
!(function(){
const userAgent = navigator.userAgent
//验证是否为Android或IPhone
const android = userAgent.mathc(/(Android);?[\s\/]+([\d.]+)?/)
const iphone = userAgent.match(/(iPhone\sOs)\s([\d_]+)/)
//如果是Android或IPhone,则跳转至移动站点
if(android||iphone){
location.href = 'http://m.itcast.cn'
}
})()
history对象
history的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等
back():后退功能
forward():前进功能
go(参数):前进后退功能,参数如果是1:前进1个页面、如果是-1:后退一个页面
history对象在实际开发中很少使用
swiper插件
使用步骤:www.swiper.com.cn/usage/index…
本地存储
数据存储在用户浏览器中
设置、读取方便、甚至页面刷新不丢失数据
容量较大,sessionStorage和localStorage约5M
localStorage(重点)
生命周期永久生效,除非手动删除,否则关闭页面也会存在
可以多窗口(页面)共享(同一浏览器可以共享)
以键值对的形式存储使用
存储数据:localStorage.setItem(key,value)
读取数据:localStorage.getItem(key)
删除数据:localStorage.removeItem('key')
必须要加引号
//存储数据
localStorage.setItem('uname','pink老师')
//获取数据
console.log(localStorage.getItem('uname'))//pink老师
//删除数据
localStorage.removeItem('uname')
存储引用数据类型:
let obj = {
uname:'刘德华',
age:17,
address:南工大
}
//前面的key必须加引号,是key的名字,后面存的是变量,不需要写引号
localStorage.setItem('obj',obj)
但是上方的存储,会在浏览器中显示的是一个Object,并不能将数据展示出来。我们需要通过数据转换来实现:
本地只能存储字符串,无法存储复杂数据类型,需要将复杂数据类型转换成JSON字符串,在存储到本地
JSON.stringify(复杂数据类型):将复杂数据类型转换为JSON字符串、存储到本地
JSON.parse(JSON字符串):将JSON字符串转换为对象、取出的时候使用
如果不用parse转换成对象,那么取出来的就是一个字符串,而不是对象!!!
JSON的样子(属性和值都是双引号进行包含):
let obj = {
"uname":"刘德华",
"age":17,
"address":"南工大"
}
最终书写
let obj = {
uname:'刘德华',
age:17,
address:'南工大'
}
//存数据
localStorage.setItem('obj',JSON.stringify(obj))//对象--》JSON
//取数据
JSON.parse(localStorage.getItem('obj'))
sessionStorage
生命周期为:关闭浏览器窗口
在同一个窗口下、数据可以共享
以键值对的形式存储使用
用法跟localStorage基本相同
综合案例
里面的数据是缓存
<body>
<h1>新增学员</h1>
<div class="info">
姓名:<input type="text" class="uname">
年龄:<input type="text" class="age">
性别: <select name="gender" id="" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
薪资:<input type="text" class="salary">
就业城市:<select name="city" id="" class="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="曹县">曹县</option>
\
</select>
<button class="add">录入</button>
</div>
\
<h1>就业榜</h1>
<table>
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- <tr>
<td>1001</td>
<td>欧阳霸天</td>
<td>19</td>
<td>男</td>
\
<td>15000</td>
<td>上海</td>
<td>
<a href="javascript:">删除</a>
</td>
</tr> -->
</tbody>
</table>
<script>
// 读取本地存储的数据 封装为函数
// 需求①:读取本地存储数据(封装函数)
// 如果本地存储有数据,则返回 JSON.parse() 之后的对象
// 如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify() 存 储JSON 格式的数据
function getLocalData() {
let data = localStorage.getItem('data')
if (data) {
// 如果本地存储有数据,则返回 JSON.parse() 之后的对象
return JSON.parse(data) // {xxxxx}
} else {
// 如果本地存储没有数据,则默认写入三条数据,注意存储的利用JSON.stringify() 存 储JSON 格式的数据
let arr = [
{ stuId: 1001, uname: '欧阳霸天', age: 19, gender: '男', salary: '20000', city: '上海' },
{ stuId: 1002, uname: '令狐霸天', age: 29, gender: '男', salary: '30000', city: '北京' },
{ stuId: 1003, uname: '诸葛霸天', age: 39, gender: '男', salary: '2000', city: '北京' },
]
// 写入到本地存储里面
localStorage.setItem('data', JSON.stringify(arr))
}
}
// 先调用一次
getLocalData()
// 获取父元素 tbody
let tbody = document.querySelector('tbody')
// 添加数据按钮
// 获取录入按钮
let add = document.querySelector('.add')
// 获取各个表单的元素
let uname = document.querySelector('.uname')
let age = document.querySelector('.age')
let gender = document.querySelector('.gender')
let salary = document.querySelector('.salary')
let city = document.querySelector('.city')
// 渲染函数 把数组里面的数据渲染到页面中
function render() {
// 需求②:渲染模块
// 先读取本地存储数据,然后渲染
let arr = getLocalData()
\
// 先干掉以前的数据 让tbody 里面原来的tr 都没有
tbody.innerHTML = ''
// 在渲染新的数据
// 根据数据的条数来渲染增加 tr
for (let i = 0; i < arr.length; i++) {
// 1.创建tr
let tr = document.createElement('tr')
// 2.tr 里面放内容
tr.innerHTML = `
<td>${arr[i].stuId}</td>
<td>${arr[i].uname}</td>
<td>${arr[i].age}</td>
<td>${arr[i].gender}</td>
<td>${arr[i].salary}</td>
<td>${arr[i].city}</td>
<td>
<a href="javascript:" data-id="${i}">删除</a>
</td>
`
// 3.把tr追加给 tobdy 父元素.appendChild(子元素)
tbody.appendChild(tr)
\
\
}
}
// 页面加载就调用函数
render()
\
add.addEventListener('click', function () {
// 需求③:添加模块
// 注意,先取的最新的本地存储数据,然后追加
let arr = getLocalData()
// 新增了数据,要把新数据存储到本地存储别,忘记转换
\
\
// alert(11)
// 获得表单里面的值 之后追加给 数组 arr 用 push方法
arr.push({
// 得到数组最后一条数据的学号 1003 + 1
stuId: arr[arr.length - 1].stuId + 1,
uname: uname.value,
age: age.value,
gender: gender.value,
salary: salary.value,
city: city.value
})
// console.log(arr)
\
// 存储到仓库里面
localStorage.setItem('data', JSON.stringify(arr))
\
// 重新渲染我们的函数
render()
// 复原所有的表单数据
uname.value = age.value = salary.value = ''
gender.value = '男'
city.value = '北京'
})
\
\
// 删除操作, 删除的也是数组里面的数据 , 但是我们用事件委托
tbody.addEventListener('click', function (e) {
// 读取本地存储里面的数据
let arr = getLocalData()
// alert(11)
// 我们只能点击了链接 a ,才会执行删除操作
// 那我们怎么知道你点击了a呢?
// 俺们只能点击了链接才能做删除操作
// console.dir(e.target.tagName)
if (e.target.tagName === 'A') {
// alert('你点击了链接')
// 删除操作 删除 数组里面的数据 arr.splice(从哪里开始删,1)
// 我要得到a的id 需要
// console.log(e.target.id)
// console.log(e.target.dataset.id)
// 第一条数据不允许删除
if (e.target.dataset.id === '0') {
alert('当前数据不允许被删除')
return
}
arr.splice(e.target.dataset.id, 1)
\
// 存到本地里面
localStorage.setItem('data', JSON.stringify(arr))
\
// 重新渲染我们的函数
render()
}
})
</script>
</body>
自定义属性
设置自定义属性:.setAttribute('key','value')
得到自定义属性:.getAttribute('key')
移除自定义属性:.removeAttribute('key')
<div class = "box"></box>
let box = document.querySelector('.box')
box.setAttribute('myid','10')
console.log(box.getAttribute('myid'))
传统的自定义属性,没有专门的定义规则、开发者随意定值,不够规范。
所以在HTML5中推出专门的data-自定义属性,在标签上一律以data-开头
在DOM对象上一律以dataset对象方式获取:
<div class = "box" data-id="10"></div>
let box = document.querySeelctor('.box')
console.log(box.dataset.id)//10
dataset对象:存储自定义集合的一个对象
正则表达式
正则表达式:用于匹配字符串中、字符组合的模式。在JavaScript中,正则表达式也是对象。
通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。
表单验证(匹配)、过滤敏感词(替换)、字符串中提取我们想要的部分(提取)
语法
步骤分为两步:1.定义规则;2.根据规则去查找
定义语法:
let 变量名 = /表达式/
//:是正则表达式的字面量,正则表达式是一个对象。reg里面存储的是对象
例题:查找下面文本中是否包含字符串'前端'
1.定义规则
let reg = /前端/
2.根据规则去查找
reg是否在后面:reg.test('我们都在学前端')
返回的结果是true
检索
检索(查找)符合规则的字符串:exec()方法:在一个指定字符串中,执行一个搜索匹配。
语法:reg.exec(被检测的字符串)
let str = 'IT培训,前端开发,web前端'
let reg = /前端/
let re = reg.exec(str)
console.log(re)//返回的是一个数组
如果匹配成功,exec()方法返回的是一个数组,否则返回null。能够告诉我们在索引号n处,发现匹配
元字符
普通字符:大多数的字符只能够描述他们本身,例如所有的字母和数字。也就是说普通字符只能够匹配字符串中与他们相同的字符
元字符:具有特殊含义的字符,比如:规定用于只能输入英文26个英文字母,普通字符:abcdefg...、而元字符:[a-z]
正则测试工具:tool.oschina.net/regex
我们对众多的元字符进行了分类:
1.边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾)
^:表示匹配行首的文本(以谁开始)
$:表示匹配行尾的文本(以谁结束)\
console.log(/^哈/.test('二哈'))//规定了以哈开头,但这里没满足,返回false
console.log(/^哈$/.test('二哈'))//必须同时哈开头,哈结尾、返回false
2.量词(表示重复次数)
*:重复0次或多次
+:重复1次或多次
?:重复0次或1次
{n}:重复n次
{n}:重复n次或多次
{n,m}:重复n次到m次
console.log(/a*/.test('a'))//a至少出现0次或多次,有一个a返回true
//以a开头,并且a至少出现0-1次,同时以a结尾
console.log(/^a?$/.test(''))//true
//因为只能重复3次
console.log(/^a{3}$/.test('aaaa'))//fasle
//允许出现3到无限次
console.log(/^a{3,}$/.test('aaaa'))//true
3.字符类(比如\d 表示0-9)
//这个表示只能出现abc,而不是abc中任意一个字母
console.log(/abc/.test('abc'))
//字符类[]、包含abc中任意一个就行
console.log(/[abc]/.test('abc'))
字符类[-]连字符:表示一个范围:/^[a-z]$/.test('c')//true
比如:只能出现一个
[a-z]:表示a到z的26个英文字母都可以
[a-zA-Z]:表示大小写都可以
[0-9]:表示0-9都可以
/^[a-zA-Z]$/.test('d') //true
/^[a-zA-Z]$/.test('D') //true
/^[a-zA-Z]$/.test('DD') //false只能出现一次D才对
//
腾讯QQ号:^[1-9][0-9]{4,}$:以1-9开头,第二个是0-9的数字,并且([0-9])重复4到无限次,并最终以0-9结尾
补充
在[]里面加上^取反符号
[^a-z]:匹配除了小写字母外的所有字符、注意一定要写在中括号的里面!!!
.匹配除换行符之外的任何的单个字符
\d:匹配0-9之间的任意数字,相当于[0-9]
\D:匹配所有的0-9以外的字符,相当于[^0-9]
\w:匹配任意的字母、数字、下划线,相当于[A-Za-z0-9_]
\W:除了字母、数字、下划线以外的字符,相当于[^A-Za-z0-9_]
\s:匹配空格(包括换行符、制表符、空格等),相当于[\t\r\n\v\f]
\S:匹配非空格的字符,相当于[^\t\r\n\v\f]
日期格式:^\d{4}-\d{1,2}-\d{1,2}:2021-09-14或者2021-9-8;以4个数字开头,出现1-2次的数字,
用户名-案例
let reg = /[a-zA-Z0-9-_]{6,16}/
[\u4e00-\u9fa5]:\u是规定,这种一看就是中文的正则要求
<input type="text">
<span></span>
<script>
let input = document.querySelector('input')
let span = input.nextElementSibling
input.addEventListener('blur', function () {
if (/^[a-zA-Z0-9-_]{6,16}$/.test(input.value)) {
span.className = 'right'
span.innerHTML = '要输正确'
} else {
span.className = 'error'
span.innerHTML = '只能要输6~16位字符'
}
})
</script>
过滤敏感词
修饰符约束正则执行的某些细节行为,入是否区分大小写,是否支持多行匹配等。
语法:/表达式/修饰符
i:是单词ignore的缩写,正则匹配时、字母不区分大小写。
g:是单词global的缩写,匹配所有满足正则表达式的结果。
/a/i.test('a'):true
替换replace
字符串.replace(/正则表达式/,'替换的文本'):把正则里面的值,替换成后面的值。
<textarea name="" id="" cols="30" rows="10"></textarea>
<button>发布</button>
<div></div>
<script>
let btn = document.querySelector('button')
let textarea = document.querySelector('textarea')
let div = document.querySelector('div')
btn.addEventListener('click', function () {
// 过滤用户输入的内容
div.innerHTML = textarea.value.replace(/激情|基情/g, '**')
})
replace只能匹配一个激情,但是通过后面的g来实现全局匹配。
小兔鲜综合案例
立即执行函数:(function(){}())
1.发送验证码,用户点击后,显示05秒后重新获取,时间到了,自动改为重新获取
let code = document.querySelector('.code')
code.addEventListener('click',function(){
//倒计时操作
let num = 5
let timer = setInterval(function(){
num--;
//这里的this指向的是window,是定时器的调用者
code.innerHTML = `0${num}秒后重新获取`
if(num === 0){
code.innerHTML = `重新获取`
//清除定时器
clearInterval(timer)
}
},1000)
})
2.用户名验证(注意封装函数)
change事件,我的表单里面的值发生变化的时候就触发
他和input事件不同的是:input事件只要输入就会触发,而change事件:离开表单、并且值发生变化才触发
input.addEventListener('change',function(){
console.log('change事件,我的表单里面的值发生变化的时候就触发。')
})
操作:
input[属性type=text]{background-color:red}:属性选择器、input标签中,只要有type属性的,全部变成红色
因为每个input没有设置类,只写了name值,所以只能通过这种方式去获取。
//属性和值是否相等,是CSS的属性选择器
let username = document.querySelector('[name=username]')
username.addEventListener('change',verify)
//封装verify函数、鼠标离开和点击下一步都需要验证,封装一个函数专门做验证工作
let span = username.nextElementSibling
let reg = '/^[a-zA-Z0-9-_]{6,10}$/'
if(!reg.test(username.value)){
//这个表示不合格
span.innerHTML = '请输入6-10个字符'
return false
}else{
//这里说明正确,把span里面的值清空
span.innerHTML = ''
return true
}
这里需要返回true、false,为了我们后期进行点击下一步的时候,方便操作。
3.手机号验证
let reg = '/^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/'
let phone = document.querySelector('[name=phone]')
phone.addEventListener('change',verifyPhone)
function verifyPhone(){
let span = phone.nextElementSibling
let reg = '/^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/'
if(!reg.test(phone.value)){
span.innerHTML = '请输入11位手机号'
return false
}else{
span.innerHTML = ''
return true
}
}
4.验证码验证
let codeInput = document.querySelector('input[name=code]')
let reg = '/^\d{6}$/'
...相同的逻辑
5.密码验证
let reg = '/^[a-zA-Z0-9-_]{6,20}$/'
// 密码模块
let pass = document.querySelector('[name=password]')
pass.addEventListener('change', verifyPass)
function verifyPass() {
// 正则表达式
let reg = /^[a-zA-Z0-9-_]{6,20}$/
let msg = pass.nextElementSibling
if (!reg.test(pass.value)) {
msg.innerText = '设置6至20位字母、数字和符号组合';
return false;
}
msg.innerText = '';
return true;
}
// 再次密码模块
let confirm = document.querySelector('[name=confirm]')
confirm.addEventListener('change', verifyconfirm)
function verifyconfirm() {
// 正则表达式
let msg = confirm.nextElementSibling
if (confirm.value !== pass.value) {
msg.innerText = '两次密码不一致';
return false;
}
msg.innerText = ''
return true
}
6.我同意模块
let icon = document.querySelector('.icon-queren')
icon.addEventListener('click',function(){
//toggle:如果有,就删除;如果没有,就添加
this.classList.toggle('icon-queren2')
})
7.提交按钮模块
如果上面的每个模块,有一个返回的是false,则阻止提交,如果没有勾选同意协议,则提示:需要勾选
let submit = document.querySelector('.submit')
submit.addEventListener('submit',function(e){
//怎么阻止提交(阻止默认行为)
//如果返回的是false,我们取反后进行不通过的操作
if(!verifyUsername()){
//不通过,阻止submit按钮的提交
e.preventDefault()
}
然后将其他的模块进行复制粘贴
....
//是否包含某个类
if(icon.classList.contains('icon-queren2')){
alert('请勾选同意协议')
}
})
登录页面
登录按钮点击的时候,需要先判断:
如果没有勾选同意,则提示要勾选
如果勾选协议,则记住用户名和密码
登录成功则跳转到首页
注意:登录按钮需要先阻止默认行为
let dl = document.querySelector('.dl')
//复选框
let remember = document.querySelector('.remember')
let username = document.querySelector('[name=username]')
document.querySelector('[name=password]')
dl.addEventListener('click',function(){
//如果没点,取反、返回true,执行该语句
if(!remember.checked){
alert('请勾选该协议')
return
}else{
//勾选了,就记住用户名(写到本地存储)
let obj = {
uname:username.value
password:password.value
}
localStorage.setItem('data',JSON.stringify(obj))
//跳转到新的页面
lcoation.href = './index.html'
}
})
let obj = JSON.parse(localStorage.getItem('data'))
if(obj){
username.value = obj.uname
password.value = obj.password
//如果有数据,则默认勾选
remember.checked = true
}
打开页面时候,如果本地存储有数据
则自动记录显示用户名和密码,并勾选复选框
首页显示
如果有本地存储,则显示:你好 xxx,否则显示请跳转到注册页面
let li = document.querySelector('xtx_navs li:first-child')
let obj = localStorage.getItem('pink')
if(obj){
li.innerHTML = `你好,${obj.uname}`
}
所有代码
注册
(function () {
// 需求①: 发送验证码
// 用户点击之后,显示 05秒后重新获取
// 时间到了,自动改为 重新获取
let code = document.querySelector('.code')
code.addEventListener('click', function () {
// 倒计时读秒操作
this.innerHTML = '05秒后重新获取'
let num = 5
let timer = setInterval(function () {
num--
code.innerHTML = `0${num}秒后重新获取`
if (num === 0) {
code.innerHTML = `重新获取`
// 清除定时器
clearInterval(timer)
}
}, 1000)
})
// 需求②: 用户名验证(注意封装函数 verifyxxx)
// 正则 /^ [a - zA - Z0 - 9 - _]{ 6, 10 } $ /
// 如果不符合要求,则出现提示信息 并 return false
// 否则 则返回return true
// 之所以返回 布尔值,是为了 最后的提交按钮做准备
// [name=username] css 属性选择器
let username = document.querySelector('[name=username]')
// console.log(username)
// 鼠标离开需要验证, 点击下一步也需要验证,那我们为何不封装一个函数呢?
username.addEventListener('change', verifyUsername)
// 验证用户名的函数
function verifyUsername() {
// console.log(11)
let span = username.nextElementSibling
// 开始验证 正则 1. 定义规则 2. 检测
let reg = /^[a-zA-Z0-9-_]{6,10}$/
if (!reg.test(username.value)) {
// console.log('wrong')
span.innerHTML = '请输入6~10的字符'
return false
}
// console.log('right')
span.innerHTML = ''
return true
}
// 需求③: 手机号验证
// 正则: /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
// 其余同上
let phone = document.querySelector('[name=phone]')
phone.addEventListener('change', verifyPhone)
// 验证手机号的函数
function verifyPhone() {
// console.log(11)
let span = phone.nextElementSibling
// 开始验证 正则 1. 定义规则 2. 检测
let reg = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
if (!reg.test(phone.value)) {
// console.log('wrong')
span.innerHTML = '请输入11位的手机号码'
return false
}
// console.log('right')
span.innerHTML = ''
return true
}
// 需求④: 验证码验证
// 正则 /^\d{6}$/
// 其余同上
let codeInput = document.querySelector('input[name=code]')
codeInput.addEventListener('change', verifyCode)
// 验证手机号的函数
function verifyCode() {
// console.log(11)
let span = codeInput.nextElementSibling
// 开始验证 正则 1. 定义规则 2. 检测
let reg = /^\d{6}$/
if (!reg.test(codeInput.value)) {
// console.log('wrong')
span.innerHTML = '请输入6位数字'
return false
}
// console.log('right')
span.innerHTML = ''
return true
}
// 需求⑤: 密码验证
// 正则 /^[a-zA-Z0-9-_]{6,20}$/
// 其余同上
let pass = document.querySelector('input[name=password]')
pass.addEventListener('change', verifyPass)
// 验证手机号的函数
function verifyPass() {
// console.log(11)
let span = pass.nextElementSibling
// 开始验证 正则 1. 定义规则 2. 检测
let reg = /^[a-zA-Z0-9-_]{6,20}$/
if (!reg.test(pass.value)) {
// console.log('wrong')
span.innerHTML = '请输入6~20位密码'
return false
}
// console.log('right')
span.innerHTML = ''
return true
}
// 需求⑥: 再次密码验证
// 如果本次密码不等于上面输入的密码则返回错误信息
// 其余同上
let confirm = document.querySelector('[name=confirm]')
confirm.addEventListener('change', verifyConfirm)
function verifyConfirm() {
let span = confirm.nextElementSibling
if (confirm.value !== pass.value) {
span.innerHTML = '两次密码不一致'
return false
}
// console.log('right')
span.innerHTML = ''
return true
}
// 需求⑦: 我同意模块
// 切换类 .icon-queren2 则是默认选中样式
let icon = document.querySelector('.icon-queren')
icon.addEventListener('click', function () {
this.classList.toggle('icon-queren2')
})
// 需求⑧: 提交按钮模块
// 使用 submit 提交事件
// 如果上面的每个模块,返回的是 false 则 阻止提交
// 如果没有勾选同意协议,则提示 需要勾选
// 在提交之前先验证
let form = document.querySelector('form')
form.addEventListener('submit', function (e) {
// alert(11)
// e.preventDefault()
// e.preventDefault()
// 怎么阻止提交 (怎么阻止默认行为 )
// 我们如果没有验证成功,不允许提交 阻止提交的行为
// 这样说明验证不通过
// verifyUsername() === false
if (!verifyUsername()) {
// 阻止提交
// console.log(111);
e.preventDefault()
}
if (!verifyPhone()) {
// 阻止提交
e.preventDefault()
}
if (!verifyCode()) {
// 阻止提交
e.preventDefault()
}
if (!verifyPass()) {
// 阻止提交
e.preventDefault()
}
if (!verifyConfirm()) {
// 阻止提交
e.preventDefault()
}
// 勾选模块 必须勾选才能通过
// classList.add() 添加
// classList.remove() 移除
// classList.toggle() 切换
// classList.contains() 看看有没有包含某个类,如果有则返回true,么有则返回false
if (!icon.classList.contains('icon-queren2')) {
alert('请勾选同意协议')
e.preventDefault()
}
})
}());
登录
// 需求:
// 1. 登录按钮点击的时候,需要先判断
// 如果没有勾选同意,则提示要勾选
// 如果勾选协议,则记住用户名和密码
// 登录成功则跳转到首页
// 注意,登录按钮需要先阻止默认行为
let dl = document.querySelector('.dl')
// 复选框
let remember = document.querySelector('.remember')
let username = document.querySelector('[name=username]')
let password = document.querySelector('[name=password]')
dl.addEventListener('click', function (e) {
e.preventDefault()
if (!remember.checked) {
alert('请勾选协议')
return
}
let obj = {
username: username.value,
password: password.value,
}
// console.log(obj)
localStorage.setItem('pink', JSON.stringify(obj))
// 跳转到新的页面
location.href = './index.html'
})
// 2. 打开页面时候,如果本地存储有数据, 则自动记录显示用户名和密码,并勾选复选框
let obj = JSON.parse(localStorage.getItem('pink'))
if (obj) {
username.value = obj.username
password.value = obj.password
// 如果有数据则默认勾选
remember.checked = true
}
首页
<script>
// 如果本地存储有数据,则 显示 你好 xxxx
// 否则 显示 请跳转到注册页面
let li = document.querySelector('.xtx_navs li:first-child')
let obj = JSON.parse(localStorage.getItem('pink'))
if (obj) {
li.innerHTML = ` <a href="#">你好,${obj.username} 欢迎来到小兔鲜世界</a>`
}
</script>