产品展示放大镜效果
// 1. 鼠标经过小盒子,中盒子显示
// 获取小盒子
const small = document.querySelector('.small')
// 获取中盒子
const middle = document.querySelector('.middle')
// 获取大盒子
const large = document.querySelector('.large')
small.addEventListener('mouseover', function(e) {
if(e.target.tagName === 'IMG') {
// 移除原有active
document.querySelector('.small .active').classList.remove('active')
// 添加active
e.target.parentNode.classList.add('active')
// 将小盒子图片src给中盒子图片
middle.querySelector('img').src = e.target.src
large.style.backgroundImage = `url(${e.target.src})`
}
})
// 2. 鼠标经过中盒子,大盒子显示
middle.addEventListener('mouseenter', show)
middle.addEventListener('mouseleave', hide)
// 只开一个定时器
let timeid = 0
function show() {
// 进入时先关闭定时器
clearTimeout(timeid)
large.style.display = 'block'
}
function hide() {
timeid = setTimeout(function() {
large.style.display = 'none'
},200)
}
// 3.鼠标进入大盒子,大盒子显示和隐藏
large.addEventListener('mouseenter', show)
large.addEventListener('mouseleave', hide)
// 4. 鼠标进入中等盒子,显示黑色遮罩层
// 获取黑色遮罩层
const layer = document.querySelector('.layer')
middle.addEventListener('mouseenter', function(e) {
layer.style.display = 'block'
})
middle.addEventListener('mouseleave', function() {
layer.style.display = 'none'
})
// 5. 获取鼠标在中等盒子中的坐标
// x坐标 = 鼠标的页面坐标 - 盒子的可视窗口坐标 - 页面滚动的坐标
middle.addEventListener('mousemove', function(e) {
let x = e.pageX - middle.getBoundingClientRect().left - document.documentElement.scrollLeft
let y = e.pageY - middle.getBoundingClientRect().top - document.documentElement.scrollTop
if(x > 0 && x <= 400 && y > 0 && y <= 400) {
let mx = 0 , my = 0
if(x < 100) mx = 0
if(x >= 100 && x < 300) mx = x - 100
if(x > 300) mx = 200
if(y < 100) my = 0
if(y >= 100 && y < 300) my = y - 100
if(y > 300) my = 200
layer.style.left = mx + 'px'
layer.style.top = my + 'px'
// 6. 中等盒子移动,大盒子跟着移动
large.style.backgroundPositionX = -2 * mx + 'px'
large.style.backgroundPositionY = -2 * my + 'px'
}
})
1. 作用域
1.1 局部作用域
- 函数作用域:函数内部变量,函数内才能访问
- 块作用域:{}包裹的就是块作用域,外部有可能无法访问,如let和const声明的变量
1.2 全局作用域
- 声明在script标签内或js文件中的变量为全局变量
- 函数中未使用任何关键词声明的变量为全局变量
1.3 作用域链
- 本质上是底层的变量查找机制
- 先找当前作用域,没有则逐级向上查找
- 子作用域可以访问父作用域,父级则无法访问子级
1.4 js垃圾回收机制(GC)
-
生命周期:内存分配-内存使用-内存回收
-
全局变量一般不回收,页面关闭时才回收
-
局部变量,如函数内部变量,在使用完后就会回收
-
回收算法:
- 引用计数法
- 标记计数法:从根部开始扫描变量,找不到的视为没用了,就回收;能找到就视为还在使用
-
内存泄露:如果变量无法正常回收,这种情况称为内存泄漏
1.5 闭包
- 闭包 = 内层函数 + 外层函数变量
- 闭包会导致内存泄漏
// 闭包,使外部函数调用内部函数变量,可以实现数据私有,不受外部操作影响
function out() {
let i = 2
function fn() {
console.log(i)
}
return fn
}
out()
const fun = out()
fun()
1.6 变量提升
- 代码解析时,会把所有var声明的变量提升到当前作用域的最前面
- 只提升声明,不提升赋值
2. 函数进阶
2.1 函数提升
- 代码解析时,会把所有函数声明提升到当前作用域的最前面
- 只提升函数声明,不提升函数调用
2.2 函数参数
- 动态参数:arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
- 作用就是动态获取函数的实参,通过循环依次得到传递过来的实参
// 动态参数
function sum() {
let sum = 0
for(let i = 0; i < arguments.length; i++) {
sum += arguments[i]
}
console.log(sum)
}
sum(2,3)
sum(2,3,6,9,9,5,3)
- 剩余参数:…是语法符号,置于最末,用于获取多余的实参,借助…获取的参数,是个真数组
// 剩余参数
function fn(a, b, ...arr) {
console.log(arr)
}
fn(2,3,4,5)
- 展开运算符
const arr = [1,2,3]
console.log(...arr)//可以将数组展开
console.log(Math.max(...arr))//求出数组最大值
3. 箭头函数
3.1 基本语法
// 箭头函数
const fn = () => {
console.log(123)
}
fn()
// 只有一个参数时,小括号可以省略
const fn = x => {
console.log(x)
}
fn(1)
// 函数体只有一行代码,大括号可以省略,并且自动做为返回值被返回
const fn = x => console.log(x)
fn(1)
// 加括号的函数体返回对象
const fn = (uname) => ({name:uname})
console.log(fn('张三'))
3.2 箭头函数参数
- 箭头函数没有动态参数,但有剩余参数
3.3 箭头函数的this
- 箭头函数不会创建自己的this,只会沿用上一层作用域的this
4. 解构赋值
4.1 数组解构
- 数组解构就是把数组的单元值批量赋值给一系列的变量的简便语法
const arr = [1,2,3]
const [max,min,avg] = arr
console.log(max,min,avg)
// 简便的交换两个变量
let a = 1
let b = 2;//必须加分号隔开
[b,a] = [a,b]
console.log(a,b)
- 用剩余参数的方法解决单元值多于参数的情况
- 通过给变量赋初值,解决单元值少于变量,然后undefined的情况
- 同时支持多维数组的解构,
const [a,b,[c,d]] = [1,2,[3,4]]
4.2 对象解构
- 对象解构就是把对象的属性和方法批量赋值给一系列的变量的简便语法
// 对象解构
const obj = {
uname:'乔治',
age:1000
}
const {uname,age} = obj//变量名必须和对象属性名相同
console.log(uname,age)
// 使用新的变量名
const {uname:name,age} = obj
console.log(name)
// 数组对象解构
const arr = [
{uname:'小白',age:66}
]
const [{uname,age}] = arr
console.log(uname,age)
// 多级对象解构
const obj = {
name:'乔治',
family:{
father: '猪爸爸',
mother: '猪妈妈'
}
}
const {name,family:{father,mother}} = obj
console.log(father)
console.log(mother)
// 1. 这是后台传递过来的数据
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [
{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
},
]
}
// 需求1: 请将以上msg对象 采用对象解构的方式 只选出 data 方面后面使用渲染页面
const {data} = msg
console.log(data)
// 需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做参数传递给 函数
function render({data}) {
// 我们只要 data 数据
// 内部处理
console.log(data)
}
render(msg)
// 需求3, 为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为 myData
function render({data:myData}) {
// 要求将 获取过来的 data数据 更名为 myData
// 内部处理
console.log(data)
}
render(msg)
4.3 forEach遍历数组,返回新数组
//渲染商品案例
// 1. foreach遍历数组
let str = ''
goodsList.forEach(item => {
// 解构数组对象
const {name,price,picture} = item
// 使用字符串拼接
str += `
<div class="item">
<img src=${picture} alt="">
<p class="name">${name}</p>
<p class="price">${price}</p>
</div>
`
})
// 放到div中
document.querySelector('.list').innerHTML = str
价格筛选案例
<div class="filter">
<a data-index="1" href="javascript:;">0-100元</a>
<a data-index="2" href="javascript:;">100-300元</a>
<a data-index="3" href="javascript:;">300元以上</a>
<a href="javascript:;">全部区间</a>
</div>
<div class="list">
<!-- <div class="item">
<img src="" alt="">
<p class="name"></p>
<p class="price"></p>
</div> -->
</div>
<script>
// 2. 初始化数据
const goodsList = [
{
id: '4001172',
name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
price: '289.00',
picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
},
{
id: '4001594',
name: '日式黑陶功夫茶组双侧把茶具礼盒装',
price: '288.00',
picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
},
{
id: '4001009',
name: '竹制干泡茶盘正方形沥水茶台品茶盘',
price: '109.00',
picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
},
{
id: '4001874',
name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
price: '488.00',
picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
},
{
id: '4001649',
name: '大师监制龙泉青瓷茶叶罐',
price: '139.00',
picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
},
{
id: '3997185',
name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
price: '108.00',
picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
},
{
id: '3997403',
name: '手工吹制更厚实白酒杯壶套装6壶6杯',
price: '100.00',
picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
},
{
id: '3998274',
name: '德国百年工艺高端水晶玻璃红酒杯2支装',
price: '139.00',
picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
},
]
// 渲染函数
function render(arr) {
// 1. foreach遍历数组
let str = ''
arr.forEach(item => {
// 解构数组对象
const {name,price,picture} = item
// 使用字符串拼接
str += `
<div class="item">
<img src=${picture} alt="">
<p class="name">${name}</p>
<p class="price">${price}</p>
</div>
`
})
// 放到div中
document.querySelector('.list').innerHTML = str
}
render(goodsList)
// 筛选
document.querySelector('.filter').addEventListener('click', e => {
// 解构e.target
const {tagName,dataset} = e.target
if(tagName === 'A') {
let arr = goodsList
if(dataset.index === '1') {
arr = goodsList.filter(item => item.price > 0 && item.price <= 100)
}else if(dataset.index === '2') {
arr = goodsList.filter(item => item.price >= 100 && item.price <= 300)
}else if(dataset.index === '3') {
arr = goodsList.filter(item => item.price > 300)
}
render(arr)
}
})
</script>