事件委托、cookie、JSON以及localstorage相关
事件委托
概述: 将对应的子元素的事件添加给父元素,用e.target来获取真实操作的元素 从而完成相关的操作(不能用到事件委托的 mouseenter 和 mouseleave 以及 mousemove..)
//事件委托 利用父元素添加事件 通过e.target获取真实的操作元素来进行相关的操作
//当你有许多需要同时添加一个事件行为的同级元素 这个时候我们不给这些元素加事件
// 而是给他的父元素添加事件 称为事件委托
gameList.onmouseover = function(e){
e = e || event
//控制对应的li标签的背景颜色变化 得到实际的触发对象 target
if(e.target.nodeName == 'LI'){
//先排他
for(var i=0;i<games.length;i++){
this.children[i].style.backgroundColor = 'black'
}
e.target.style.backgroundColor = 'red'
}
}
// 5, 选择某一项, 将顶部的名称改成你选择的游戏名称
gameList.onclick = function(e){
e = e || event
if(e.target.nodeName == 'LI'){ //如果当前的e.target是li的话 才执行对应的操作
title.innerText = e.target.innerText
}
}
使用事件委托的好处:
- 提高性能(事件委托中并没有使用循环给每个节点设置事件,只给一个父元素ul绑定事件)
- 后续动态添加的节点也有事件的处理
注意:事件委托底层就是通过事件冒泡来完成的,先触发父元素的事件,在通过事件对象的target属性找到具体的目
标元素,进而在处理目标元素要执行的业务逻辑。
offset家族
offsetParent 偏移的父元素(一层一层的向上找 找到定位的元素就是对应的父元素 有定位的上层元素就他的父元素 找不到的就是body)
offsetLeft 基于偏移的父元素的左偏移量
offsetTop 基于偏移的父元素的上偏移量
offsetHeight 获取偏移元素的高度(包含border以及padding)
offsetWidth 获取偏移元素的宽度(包含border以及padding)
拖拽(区间拖拽)
//拖拽的方法实现 第一个是移动的盒子 第二个在哪移动
function touch(moveBox,box){
//给moveBox添加按下事件 记录一下当前鼠标在moveBox里面点击的位置
moveBox.onmousedown = function(e){
e = e || window.event
//获取对应的第一次按下的位置
var firstX = e.offsetX
var firstY = e.offsetY
// console.log(document.body.offsetParent); //偏移的父元素
//给box添加move事件 记录每次的位置 在box的位置 设置moveBox在box的定位
box.onmousemove = function(e){
e = e || event
//这个108是对应的box离body的距离 这个距离就是box偏移的距离
//offsetLeft 得到基于父元素左偏移量 offsetTop 得到基于父元素的上偏移量
//offsetParent 基于的父元素 基于定位的 他会一层层往上找 找到定位的父元素就基于他 如果没有找到就基于body
//有奶便是娘 谁有定位他就基于谁
var currentX = e.pageX - getOffset(this).left
var currentY = e.pageY - getOffset(this).top
var targetX = currentX - firstX
var targetY = currentY - firstY
//判断边界 offsetWidth 得到盒子的宽度 offsetHeight得到盒子的高度
if(targetX<0){
targetX = 0
}
if(targetY<0){
targetY = 0
}
if(targetX>this.offsetWidth-moveBox.offsetWidth){
targetX = this.offsetWidth-moveBox.offsetWidth
}
if(targetY>this.offsetHeight-moveBox.offsetHeight){
targetY = this.offsetHeight-moveBox.offsetHeight
}
// 设置moveBox在box的定位
moveBox.style.left = targetX + 'px'
moveBox.style.top = targetY + 'px'
}
//给box添加弹起事件 清除box的move事件
document.onmouseup = function(){
box.onmousemove = null
}
}
}
获取对应的盒子离最外层body的left值及top值
//获取对应的元素离body的距离 传入一个元素
function getOffset(element){
var left = 0
var top = 0
while(element){
left += element.offsetLeft
top += element.offsetTop
element = element.offsetParent
}
return {left,top}
}
事件监听器
addEventListener (添加事件监听)任何元素都能调用(观察者模式 observer)
element.addEventListener('事件名',处理函数,'是否捕获')
removeEventListener (移除事件监听)任何元素都能调用
element.removeEventListener ('事件名',处理函数)
示例
//是否捕获 默认为不捕获(冒泡)
// 同时给一个事件加多个处理函数 (事件只会调用一次)
btn.addEventListener('click',function(){
console.log('点击了');
},true)
btn.addEventListener('click',function(){
console.log('点击了1');
},true)
btn.addEventListener('click',function(){
console.log('点击了2');
},true)
btn.addEventListener('click',function hello(){
console.log('点击了3');
})
btn.removeEventListener('click',function hello(){
console.log('点击了3');
})//不能被移除
//移除事件监听器 移除事件监听器根据对应的处理函数来的
//这个俩个函数对象不是一个对象 比对出不来 所以就删不掉
//所以我们如果需要删除对应的处理函数的话 那么必须在监听的时候 就要保证这个处理函数和对应的删除的时候的处理函数是一个
//正确示例
function sayHello(){
console.log('hello');
}
div.addEventListener('click',sayHello)
div.removeEventListener('click',sayHello)
兼容写法
//移除函数
function removeEvent(obj, type, fn, useCapture){
if (obj.removeEventListener) {
obj.removeEventListener(type, fn, useCapture);
}
else {
obj.detachEvent("on"+type, fn);
}
//三元的写法 obj.removeEventListener?obj.removeEventListener(type,fn,useCapture):obj.detachEvent("on"+type, fn);
}
//添加函数
function addEvent(obj, type, fn, useCapture){
if (obj.addEventListener) {
obj.addEventListener(type, fn, useCapture);
}
else {
obj.attachEvent("on"+type, fn);
}
//三元的写法 obj.addEventListener?obj.addEventListener(type,fn,useCapture):obj.attachEvent("on"+type, fn);
}
前端和后端
前端是展示内容的部分
后端是提供数据支持的部分
网络构成图
网络构成分为七层 最底层的物理层 数据链路层(底层维护 需要硬件支持),网络层(基于网络协议白皮书书写网络协议),传输层(网络传输的支持 tcp(直连)和udp(丢包)) 应用层相关协议(对应应用支持的协议 http网络传输协议 ftp文件传输协议等)
http和https
http,https 都是网络传输协议 是用于网络相关传输,http走的是明文传输,https走的密文传输(内部采用对称加密以及非对称加密)。对应的https安全性要高于http。https为什么会采用加密,因为他底层采用了openSSL。(open表示开源)
http的特性
- 无状态 (服务器不知道是谁访问的我)
- 无连接 (不会建立完整的连接 访问一过去 数据一返回连接就断了)
- 长连接 (连接可以建立长时间)
- 短连接 (连接对应的内容很短)
问题
由于http是无状态的!那么对应的我们在实现某些功能的时候就会出现对应的问题.比如a用户登录了 b用户也登录了,a用户可能拿到b用户的页面,b用户可以拿到a用户的页面。这个时候我们就出现问题了。
问题的解决
根据上面的问题我们可以得出对应的a可能会拿到b的内容,原因是因为对应的服务器无法区分a和b,如果我在a的访问的时候给一个唯一的标识,在b的访问的时候给一个唯一的标识,那么我是否可以区分a和b。所以对应的解决方案就是a和b拥有不一样的标识,而这个标识是在建立连接的时候。这个标识叫做sessionId。也就意味这个每个请求去建立连接都会获得一个sessionId。(sessionID服务端给的)。如果对应的sessionID是存储于服务端的话,那么服务端就会越来越大从影响对应的效率,所以我们诞生了一个内容来保存这个值到对应浏览器端,这个东西就是cookie。所以cookie的诞生就是为了保存sessionID,从而解决http无状态的问题。
cookie
概述
- cookie存在于浏览器端
- cookie为了保存sessionID出现的
- cookie的出现解决了http无状态的问题
特性
cookie是不安全的
cookie是可以被篡改和伪造的
cookie他是以字符串存储的(单一),有很多的数据类型是不支持的(二进制图片,二进制的视频,base64码的视频等等)
cookie他的大小不能超过4kb(大小只有4kb 容量小)
cookie会随请求发送
cookie可以跨域(domain来设置)
cookie的访问
//document.cookie
console.log(document.cookie)
cookie的完整格式
name=value;[expires=date];[path=路径];[domain=域名];[secure]
name随便定value随便定(存的key和value)
document.cookie = 'username=jack'
expires 过期时间设置 (如果没有设置 跟sessionID的过期时间一致 连接一断就没有了)
var date = new Date(2022,7,9,16,20)
document.cookie = 'username=jack;expires='+date
path 只有是这个路径以下的url才携带这个cookie
document.cookie = 'username=jack;expires='+date+';path=http://www.baidu.com'
domain 跨域设置 在这个域名下实现了跨域的功能
document.cookie = 'username=jack;expires='+date+';path=http://www.baidu.com;domain=www.baidu.com'
secure 安全 只有当前访问协议是https的时候才会携带
document.cookie = 'username=jack;expires='+date+';path=http://www.baidu.com;domain=www.baidu.com;secure'
cookie的相关操作(增删改查的功能)
cookie的封装
//主要是封装的cookie的增删改查的方法
//根据key来获取cookie里面的元素
// password=123456; username=123456
function getItem(key){
var str = document.cookie
//对于这个字符串进行切割
var splitArr = str.split(';') //[password=123456,username=123456]
var cookieObject = {}
//遍历这个数组
for(var splitStr of splitArr){//password=123456
var keyValueArr = splitStr.split('=')
cookieObject[keyValueArr[0].trim()] = decodeURIComponent(keyValueArr[1])
}
return cookieObject[key]
}
//设置cookie及里面的元素
function setItem(key,value,expires,path,domain,secure){
//如果没有key获取没有value 直接报错
if(!key || (!value && value!='')){
//抛出错误 后面的代码将不会执行
throw new Error('参数错误')
}
document.cookie = `${key}=${encodeURIComponent(value)}`
if(expires){//如果有过期时间拼接
document.cookie += `;expires=${expires}`
}
if(path){//如果有路径拼接
document.cookie += `;path=${path}`
}
if(domain){//如果有domain拼接
document.cookie += `;domain=${domain}`
}
if(secure){//如果有secure拼接
document.cookie += `;${secure}`
}
}
//根据key来删除对应的cookie
function removeItem(key){
if(getItem(key) || getItem(key)==''){
setItem(key,'',new Date())
}else{
console.error('当前的key值不存在')
}
}
cookie.js(第三方的js)
Cookies.remove('username')
Cookies.get('username')
Cookies.set('username','jack',{expires:10}) //设置一个username 10天以后过期
encodeURIComponent 转码
console.log(encodeURIComponent('{abdejde152}'));
decodeURIComponent 解码
var str = encodeURIComponent('{abdejde152}') //进行编码
console.log(decodeURIComponent(str));//解码
JSON
概述: json是一种数据格式,他广泛应用于数据传输,(目前大部分的数据传输的格式都是采用
json(跨平台 不区分语言)restful接口 就是使用json数据进行传输的)
json的表示形式
数组 []
var jsonStr = '[]'
对象 {}
var jsonStr = '{}'
解析json数据
var lrcObj = {"sgc":false,"sfy":false,"qfy":false,"lrc":{"version":1,"lyric":"
[00:00.000] 作词 : 交易子\n[00:01.000] 作曲 : 交易子\n[00:02.000] 编曲 : 交易子
\n[00:30.069]记忆中的海岸线没我记的那么长远\n[00:37.072]本该撕心裂肺的想念也没我想的那么热
烈\n[00:44.393]我不可能变得连告别都做不到体面\n[00:52.193]毕竟那天之前的事我也不想再经历一
遍\n[00:57.929](ok I should probably stop right there because that's the biggest
lie ever and I'm the biggest joke ever. I never stopped thinking about it. I
still do.)\n[00:58.552]\n[00:59.049]Does everyone\n[01:03.136]keep repeating
their mistakes\n[01:06.673]Or am I the only one\n[01:10.201]trapped in such
fate\n[01:12.456]\n[01:12.968]I was your\n[01:13.872]Lucky
charm\n[01:17.336]Pretty babe\n[01:19.969]Upper arm tattoo
designer\n[01:23.330]Only receiver of flowers you ever sent\n[01:26.730]I miss
your\n[01:27.656]Killing charm\n[01:31.056]Pretty face\n[01:34.456]Reckless
adventures\n[01:37.345]Where I got abandoned in the
end\n[01:40.712]\n[01:42.520]All that pain and misery, is it worth it?
\n[01:47.128]Sarah Lynn? Sarah Lynn?\n[01:49.978]Is it worth it?
\n[01:52.521]Sarah Lynn?\n[01:54.394]\n[01:55.448]你是否也会在下午五点从昏睡惊醒
\n[02:01.857]鼻尖和后背的汗珠 眼眶里凝结的水雾\n[02:08.784]黄昏特别版孤独 看太阳落幕
\n[02:16.376]但那个太阳是我人生最后一次甘甜的痛苦\n[02:21.689]\n[02:22.584]Is
life\n[02:26.136]always this hard\n[02:29.513]or is it just
when\n[02:32.929]you're a kid?\n[02:35.258]\n[02:35.624]I’m
gonna\n[02:36.192]Change my number\n[02:39.592]Smash my
house\n[02:42.984]Deactivate all my credit cards\n[02:46.481]Disappear into the
sea\n[02:49.232]You’re gonna\n[02:49.856]Take another
painkiller\n[02:53.369]Open another vermouth\n[02:56.800]Smoke another
cigarette\n[03:00.106]Forget everything about me\n[03:03.249]Life and death,
energy and peace. If I stop today, it was still worth it. Even the terrible
mistakes that I made and would have unmade if I could. The pains that have
burned me and scarred my soul, it was worth it, for having been allowed to walk
where I've walked, which was to hell on Earth, heaven on Earth, back again,
into, under, far in, and above.\n[03:04.456]\n[03:06.008]so
easily\n[03:08.401]Like it was nothing\n[03:11.864]But to me\n[03:14.065]It was
everything\n"},"tlyric":{"version":0,"lyric":""},"code":200}
获取上述的歌词
var str = lrcObj.lrc.lyric
var lines = str.split('\n')
for(line of lines){
console.log(line.split(']')[1])
}
JSON格式的要求 里面的key必须是" "括起来的
一般数据是从后台获取 他返回给的json格式的数据是字符串(虽然对应的js可以解析json格式 但是后台
如果给你的是字符串的话 那么你就需要进行序列化和反序列化)
序列化(将一个内容写入到另一个东西里面叫序列化)
var user = {
username:'jack',
password:"123"
}
//toString方法 打印栈地址
console.log(user.toString())
//将对应的对象变成json格式的字符串
console.log(JSON.stringify(user))
序列化的核心就是将对应的对象变成json格式的字符串
JSON.stringify(对象)
反过来从一个东西里面获取另一个东西 叫反序列化
将json格式的字符串变成对象
var jsonStr = '{"username":"jack"}'
console.log(JSON.parse(jsonStr).username)
localStorage(本地存储)
和cookie的区别
- cookie的大小只有4kb 对应的localstorage有5M
- cookie会随请求发送 localstorage不会随请求发送
- cookie只能存储字符串 localstorage可以存储对应的图片以及视频的二进制
- 存储的位置不一样的
- cookie是可以过期的 localstorage不能过期
共同点
- cookie和localstorage都是存储在浏览器上
- 存储的内容的形式都是以字符串形式