将来我需要做的事情是
随着用户的输入检测输入的内容是不是符合规则
如果符合规则, 那么 input 取消掉 active 类名, 并且 p.error 也取消掉 active
如果不符合规则, 那么 input 要加上 active 类名, 并且 p.error 也要加上 active
问题:
input 和 p 标签本身都有个自的类名
添加类名的时候好做 直接 += ’ 要添加的类名’
删除类名的时候不好做, 我们要获取到字符串, 把里面的某些内容干掉, 再从新赋值
解决:
把他们两个的内容提出来, 放在一个公共的父级上做特殊类名标注
现在开始:
如果正则检测出现问题, 我只要给 label 标签添加 active 类名
就可以操作 label 里面的 p 标签和 input 标签了
–>
密码强度验证
代码思路:
1. 获取元素
=> 密码文本框, 因为要添加事件, 获取输入的内容, 正则验证
=> 三个 span 元素, 因为要操作 类名 来表示强度内容
2. 给 密码文本框 设置一个 input 事件
=> 随着输入随时切换密码强度
3. 在 密码文本框 的事件里面, 去操作强度类别
=> 要根据验证的强度, 来给不同的 span 标签添加类名
3-1. 准备正则
-> 一个是数字的验证
-> 一个是字母的验证
-> 一个是特殊符号的验证
3-2. 开始进行验证
-> 初始准备一个变量, 赋值为 0, 表示一个正则都没有满足
-> 挨个的正则去进行判断, 满足一个, 变量++
-> 最后, 我变量的数字就是满足了几个正则
3-3. 根据级别去设置 span 的类名
-> 级别是 0, 那么设置 0 个 span 有类名
-> 级别是 1, 那么设置索引为 [0] 的有类名, 1 个
-> 级别是 2, 那么设置索引为 [0] 和 [1] 的有类名, 2 个
-> 级别是 3, 那么设置索引为 [0] 和 [1] 和 [2] 的有类名, 3 个
3-4. 解决一个能上不能下的问题
-> 因为一直在加类名, 没有清除过, 所以加上去就回不来了
-> 当你需要给 span 添加类名的时候, 那么先给 span 还原到最初是的样子
// 1. 获取元素
// 密码文本框
var pwdInp = document.querySelector('#password')
var spans = document.querySelectorAll('p span')
// 3-1. 准备正则 => 加号(+) 表示 1 ~ 多次
var numReg = /\d+/
var zimuReg = /[a-zA-Z]+/
var fuhaoReg = /[@#$%^&]+/
// 2. 给 密码文本框 绑定一个输入事件
pwdInp.addEventListener('input', function () {
// 3-2. 开始判断
var level = 0 // 默认是 0 级, 一个正则都没有满足
// 挨个正则去判断 - 确定级别
if (numReg.test(this.value)) level++
if (zimuReg.test(this.value)) level++
if (fuhaoReg.test(this.value)) level++
// 3-4. 在加类名之前, 给所有 span 的类名还原到最初是的状态
spans[0].className = 'low'
spans[1].className = 'center'
spans[2].className = 'strong'
// 3-3. 根据级别来给 span 设置类名
for (var i = 0; i < level; i++) {
spans[i].className += ' active'
}
})
// // 1. 获取元素
// // 密码文本框
// var pwdInp = document.querySelector('#password')
// // console.log(pwdInp)
// // 三个 span 标签
// var spans = document.querySelectorAll('p span')
// // console.log(spans)
// // 3-1. 准备正则 => 加号(+) 表示 1 ~ 多次
// // 没写开头或者结尾, 表示只要字符串里面有数字就好使
// var numReg = /\d+/
// // 没写开头或者结尾, 表示只要字符串里面有字母就好使
// var zimuReg = /[a-zA-Z]+/
// // 没写开头或者结尾, 表示只要字符串里面有符号就好使
// var fuhaoReg = /[@#$%^&]+/
// // 2. 给 密码文本框 绑定一个输入事件
// pwdInp.addEventListener('input', function () {
// // console.log('用户在输入密码')
// // 3-2. 开始判断
// var level = 0 // 默认是 0 级, 一个正则都没有满足
// // 挨个正则去判断
// if (numReg.test(this.value)) level++
// if (zimuReg.test(this.value)) level++
// if (fuhaoReg.test(this.value)) level++
// // 3-4. 在加类名之前, 给所有 span 的类名还原到最初是的状态
// spans[0].className = 'low'
// spans[1].className = 'center'
// spans[2].className = 'strong'
// // 3-3. 根据级别来给 span 设置类名
// for (var i = 0; i < level; i++) {
// // 当 level === 0 的时候, i 一次都不执行
// // 当 level === 1 的时候, i === 0
// // 当 level === 2 的时候, i === 0 1
// // 当 level === 3 的时候, i === 0 1 2
// spans[i].className += ' active'
// }
// })
单独解释 level
1. 定义变量是在事件里面进行定义的
=> 就是每次触发事件的时候, 都会定义一次 level 为 0
=> 每输入一个内容就会触发一个事件
=> 每次输入内容的时候, 都会定义 level 为 0
2. 正则判断
=> 假如你输入 1
-> level === 0
-> 判断满足了一个正则, 执行一次 level++
-> level 变成 1
=> 继续输入内容 11
-> level = 0
-> 判断满足了一个正则, 执行一次 level++
-> level 变成 1
回顾作用域
1. 什么是作用域
=> 一个变量可以使用的范围
2. 作用域分类
=> 全局作用域
-> 一个 html 页面就是一个全局作用域
=> 局部作用域(私有作用域)
-> 只有函数生成私有作用域
3. 作用域的上下级关系
=> 写在哪个作用域里面的私有作用域
=> 就是哪个作用域的子级作用域
this 指向 *** 重要!!!重要!!!重要!!!
1. 定义: this 是一个使用在作用域里面的关键字
=> 作用域里面: 要么写在全局, 要么写在函数里面
=> 是个关键字: 定义变量的时候, 不能 var this
不需要定义, 我们直接使用就可以了
2. this 代表什么意思(this 指向)
=> 当你在全局作用域使用 this 的时候, this === window
-> 表示全局的意思
-> 一般很少在全局直接使用
=> 当你在函数里面使用的时候, 也就是在私有作用域里面使用的时候
-> 在 JS 里面, 很多的函数都会用到 this, 相当常用的一个关键字
-> 面试的时候, 好多的坑都是会问你 this 指向是谁而出现的
3. 函数内部的 this 指向(熟读并背诵全文)
=> 不管函数怎么定义, 不管函数在哪定义
=> 一个函数的 this 指向只和函数的调用方式有关系(箭头函数除外)
-> 函数直接调用(全局函数调用)
函数名() this -> window
-> 对象调用方式
对象名.函数名() this -> 点前面是谁就是谁
对象名’函数名’ this -> 中括号前面是谁就是谁
-> 事件处理函数
xxx.on事件类型 = function () {} this -> 事件源(绑定在谁身上的事件)
xxx.addEventListener(‘事件类型’, function () {}) this -> 事件源(绑定在谁身上的事件)
-> 定时器处理函数
setTimeout(function () {}, 时间) this -> window
setInterval(function () {}, 时间) this -> window
-> 还有一些没有学过的函数调用方式
未完待续
// 小案例
// var obj = {
// name: ‘我是 obj 对象’,
// fn: function () { console.log(this) }
// }
// var div = document.querySelector(‘div’)
// // a 这个函数才是 div 的事件处理函数
// // 是在 div 的事件处理函数里面, 以对象调用的方式在调用 obj.fn 这个函数
// div.onclick = function a() {
// // 这个位置的 this -> div 的
// // 函数是怎么调用的, 调用方式决定了函数内部的 this 指向
// // 标准的对象调用方式, 函数内部的 this 指向 点前面是谁就是谁
// obj.fn() // this -> obj
// }
// // 这么写是在把 obj.fn 这个函数当作事件处理函数使用
// div.onclick = obj.fn
// 小案例2
// var div = document.querySelector(‘div’)
// // a 这个函数才是 div 的事件处理函数
// div.onclick = function a() {
// var obj = {
// name: ‘我是 obj 对象’,
// fn: function () { console.log(this) }
// }
// // 不管函数定义在哪, 不管函数怎么定义
// // 只看函数的调用方式
// // 依旧是 对象调用 的方式, this 就是点前面是谁就是谁
// obj.fn() // this -> obj
// // 把 obj.fn 当作一个定时器处理函数去执行了
// // 定时器处理函数, this -> window
// // setTimeout(obj.fn, 1000) // this -> window
// // b 函数才是定时器处理函数
// // 只是在定时器处理函数里面使用对象调用的方式调用了 obj.fn 函数
// setTimeout(function b() {
// obj.fn() // this -> obj
// }, 1000)
// }
// 2. 对象调用方式
// var obj = {
// name: ‘张三’,
// fn: function () { console.log(this) }
// }
// 复杂数据类型的赋值
// 把 obj 里面存储的那个函数的地址, 赋值给了全局变量 f
// 从此以后, 全局变量 f 和 obj.fn 操作的是一个函数地址了
// var f = obj.fn
// // 我写 obj.fn() 和 f() 调用的是一个函数
// obj.fn() // this -> obj
// f() // this -> window
// var div = document.querySelector('div')
// // 当你点击 div 的时候, 执行 obj.fn 这个函数
// div.onclick = obj.fn // this -> div
// // 1000ms 以后, 执行 obj.fn 这个函数
// // 把 obj.fn 当作定时器处理函数在使用
// setTimeout(obj.fn, 1000) // this -> window
// 1. 普通函数调用(全局函数调用)
// function fn() {
// console.log(this) // window
// function fun() {
// console.log(this)
// }
// fun() // 本次调用的时候, 函数内部的 this 指向谁 ?
// }
// // fn() 的调用方式, 是一个标准的普通函数调用
// // 这个函数里面的 this 指向 window
// fn()
// setTimeout(function () {
// function fn() {
// console.log(this)
// }
// fn() // 本次调用的时候, 函数内部的 this ?
// }, 1000)
// var div = document.querySelector('div')
// div.onclick = function () {
// console.log(this) // this -> div
// function fn() {
// console.log(this) //window
// }
// // fn() 标准的普通函数调用, 全局函数调用
// fn() // 本次函数调用的时候, this 指向谁 ?
// }
强行改变 this 指向
因为每一种函数调用方式都有自己的 this 指向
强行改变: 不管你本身指向哪里, 我让你指向哪, 你就得指向哪
我们有三个方法改变 this 指向
1. call()
使用方式: 直接跟在函数名后面使用就可以了
调用方式 强行改变 this 指向的调用方式
fn() -> fn.call()
obj.fn() -> obj.fn.call()
参数:
call(你要改变的 this 指向, 给函数传递参数, 给函数传递参数, …)
第一个参数: 你要改变的 this 指向, 不传递或者写一个 null 都是表示 window 的意思
第二个参数开始: 依次给函数传递参数
作用:
就是改变函数内部的 this 指向
特点: 直接调用函数, 写完以后, 函数就直接执行了
2. apply()
使用方式: 直接跟在函数名后面使用就可以了
调用方式 强行改变 this 指向的调用方式
fn() -> fn.apply()
obj.fn() -> obj.fn.apply()
参数:
apply(你要改变的 this 指向, [给函数传递参数1, 给函数传递参数2, …])
第一个参数: 你要改变的 this 指向, 不传递或者写一个 null 都是表示 window 的意思
第二个参数: 是一个数组或者伪数组都可以, 里面的每一项依次是给函数传递参数
作用:
改变 this 指向
改变给函数传递参数的方式
特点: 直接调用函数, 写完以后, 函数就直接执行了
3. bind()
使用方式: 直接跟在函数名后面使用就可以了
调用方式 强行改变 this 指向的调用方式
fn() -> fn.bind()
obj.fn() -> obj.fn.bind()
参数:
bind(你要改变的 this 指向, 给函数传递的参数1, 给函数传递的参数2, …)
第一个参数: 你要改变的 this 指向, 不传递或者写一个 null 都是表示 window 的意思
第二个参数开始: 依次是给函数传递参数
作用:
改变 this 指向
改变一个不需要立即执行的函数的 this 指向的时候
特点:
不会直接调用函数, 写完以后函数没有执行
而是返回一个新的函数, 一个改变好了 this 指向的函数
一个已经被改变一次 this 指向的新函数不能被再次改变了
栗子: 事件
div.onclick = fn // fn 内部的 this 指向 div
我想修改以下, 触发点击行为的时候, 我不想函数里面的 this 指向 div
如果写成 div.onclick = fn.call(window), 点击的时候就没有函数执行了
你绑定事件的时候就把函数执行了, 而不是点击的时候再执行
// bind 小案例2
// 我想把 fn 函数当作事件处理函数来使用
// 并且 fn 函数内部的 this 改变成 obj
// function fn() {
// console.log(this)
// }
// var obj = { name: ‘我是 obj 对象’ }
// var div = document.querySelector(‘div’)
// 直接把 fn 当作事件处理函数来使用
// 但是 this 指向没有改变, 依旧会在执行的时候指向 div
// div.onclick = fn
// 如果使用 call 方法改变 this 指向
// 确实是改变了 this 指向
// 书写 fn.call() 的时候, 就已经把函数调用了, 你点击的时候, 就没有函数执行了
// div.onclick = fn.call(obj)
// 如果使用 apply 方法改变 this 指向
// 确实是改变了 this 指向
// 书写 fn.apply() 的时候, 就已经把函数调用了, 你点击的时候, 就没有函数执行了
// div.onclick = fn.apply(obj)
// 如果使用 bind 方法改变 this 指向
// 相当于把 fn 函数复制了一份, 并且改变其中的 this 指向为 obj
// 并且把返回值这个新函数给了 div.onclick
// 当你点击的时候, 执行的是 fn.bind 的返回值(那个改变好 this 指向的新函数)
// div.onclick = fn.bind(obj)
// 改变过 this 不能再次被改变
// // res 是 JS 给你制作的一个函数
// var res = fn.bind(obj)
// // res2 是把一个 JS 给你制作的函数再次改变 this 指向
// var res2 = fn.bind(100)
// console.log(res2)
// res2()
// bind 小案例
// 想把这个函数当作一个定时器处理函数来使用
// 同时又想让这个函数内部的 this 指向 obj 对象
// function fn() {
// console.log(this)
// }
// var obj = { name: ‘我是 obj 对象’ }
// 基本版本
// 把 fn 当作定时器处理函数了, 但是没有改变 this 指向, 依旧指向 window
// setTimeout(fn, 100)
// 如果使用 call 来改变 this 指向
// 把 fn 的 this 指向改变了, 但是再书写 call 的时候, 就已经把函数调用了
// 1000ms 以后就没有函数能被调用
// setTimeout(fn.call(obj), 1000)
// 如果使用 apply 来改变 this 指向
// 把 fn 的 this 指向改变了, 但是再书写 apply 的时候, 就已经把函数调用了
// 1000ms 以后就没有函数能被调用
// setTimeout(fn.apply(obj), 1000)
// 如果使用 bind 来改变 this 指向
// 把 fn 的复制了一份, 并且 this 指向改变成了 obj, 会返回一个新的函数
// 1000ms 以后, fn.bind 的返回值(也就是改变好 this 的新函数)会被调用
// 把 fn 函数同时当作了定时器处理函数, 并且也改变了 this 指向
// setTimeout(fn.bind(obj), 1000)
// 3. bind()
// function fn(a, b) {
// console.log('this: ', this)
// console.log('第一个参数: ', a)
// console.log(‘第二个参数: ‘, b)
// console.log(’’)
// }
// // 准备几个数据用于改变 this 指向的时候使用
// var obj = { name: ‘我是 obj 对象’ }
// var arr = [10, 20, 30, 40, 50]
// var reg = /^abcd / / / v a r t i m e = n e w D a t e ( ) / / / / 直 接 调 用 / / f n ( 10 , 20 ) / / 函 数 调 用 了 / / / / 使 用 b i n d 改 变 一 下 t h i s 指 向 / / / / 本 次 b i n d 会 把 f n 函 数 复 制 一 份 , 把 里 面 的 t h i s 改 变 成 o b j / / / / 100 是 给 f n 函 数 传 递 的 第 一 个 参 数 / / / / 200 是 给 f n 函 数 传 递 的 第 二 个 参 数 / / / / 注 意 : 此 时 不 会 直 接 调 用 函 数 , 而 是 会 有 一 个 返 回 值 出 现 / / / /