四天学会JS高阶(学好vue的关键)——作用域解构箭头函数(理论+实战)(第一天)

一、作用域

提到作用域(作用域又分为局部作用域和全局作用域),就要想到变量。因为作用域规定了变量能够被访问的范围(也就是作用域是为变量而服务的),为了避免全局变量污染这一情况,所以需要使用闭包函数创建隔离作用域。
这就是接下来我们要将作用域、作用域链、闭包,与变量联系起来的思路。

1.1 局部作用域

首先局部作用域分为函数作用域和块作用域。

函数作用域

函数作用域:就是在函数内部声明的变量在函数外部不能使用

  function fn (e) {
            const i = 3
            console.log(i)
            console.log(e)
        }
        fn(4)
        //在函数外部会报错
        console.log(`这是${i}`)
        console.log(`这是${e}`)

块作用域

{ } 大花括号中的就是块作用域 比如if语句 for循环等
在块作用域中,代码块内部声明的变量外部将【有可能】无法被访问==》为什么是有可能===》因为如果是var变量,它不讲块作用域,所以外部可以访问====》但是如果是let或者const变量,外部就不可以被访问

  for (var i = 1; i <= 3; i++) {
            console.log(i)
         }
        console.log(i)
       
         for (let j = 1; j <= 3; j++) {
             console.log(j)
         }
        console.log(j)
  1. let 声明的变量会产生块作用域,var 不会产生块作用域
  2. const 声明的常量也会产生块作用域
  3. 不同代码块之间的变量无法互相访问
  4. 推荐使用 let 或 const

1.2 全局作用域

顾名思义,就是script标签和.js文件的最外层就是所谓的全局作用域,在这里定义的变量在函数内部可以被访问,函数内部就上上文讲的局部作用域。
尽量少使用,避免变量污染。所谓的变量污染,大家可以理解为例如有个变量,它正在配合一个任务按部就班地进行着(也就是下面的例子,调用一次函数,count++一次),忽然有一天,因为它是全局变量,别人给他更改了一个很大值,这时候原先的任务还在执行,调用结果就是在别人给他更改的值的基础上的++,这也就说明不能正常配合任务执行了,======》轻易地导致了全局变量的污染!

 //  count是全局变量 很容易被修改
         let count = 1
         function fn2 () {
            count++
           console.log(`函数被调用了${count}`)
        }
         fn2()

1.3 作用域链

本质上是底层的变量查找机制
也就是函数被执行时,优先从当前函数作用域中查找变量;如果当前作用域查找不到会一次逐级查找父级作用域知道全局作用域。
总结来说就是嵌套关系的作用域串联起来形成了作用域,相同作用域链中按着从小到大的规则查找变量;子作用域能够访问父作用域,父作用域无法访问子作用域(中的变量)。
在这里插入图片描述

1.4 垃圾回收机制 (这部分待完善)

JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
正因为垃圾回收器的存在,所以大家在写JS不太注意内存管理的问题
但如果不了解JS的内存管理机制,我们同样非常容易成内存泄漏(内存无法被回收)的情况,所谓的内存泄漏就是:
不再用到的内存,没有及时释放

JS环境中分配的内存, 一般有如下生命周期:

  1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存
  4. 说明:
    全局变量一般不会回收(关闭页面回收);
    一般情况下局部变量的值, 不用了, 会被自动回收掉

1.5 闭包

闭包 = 内层函数 + 外层函数的变量

两种表达方式:

 function outer () {
            // 闭包 = 内层函数 + 外层函数的变量
            let a = 10
            表达方式一:
           // function fn () {
            / /   console.log(a)
           / /}
            // return一个函数 就可以使用闭包了
            //return fn
            表达方式二:因为fn===function fn()  也就是return直接指向了function函数
             return function fn () {
                console.log(a)
            }
            return 
        }
        // outer()===fn===function fn()
        const fun = outer()
        fun()

利用闭包思想,来避免全部变量受污染的情况 最好的方法就是不使用全局变量

 <script>
        //  count是全局变量 很容易被修改
        // let count = 1
        // function fn2 () {
        //     count++
        //     console.log(`函数被调用了${count}次`)
        // }
        // fn2()

        // 闭包应用:内部声明变量,实现数据的私有
        function fn () {
            let count = 1
            function fun () {
                count++
                console.log(`函数被调用${count}`)
            }
            return fun
        }
        const result = fn()
        result()
    </script>

二、预解析(了解)

2.1 变量提升 var

 <script>
        // var的变量提升
        // 所谓的变量提升就是当前变量在下面,上面使用的时候,就把所有var声明的变量提升到当前作用域的最前面
        // 只提升声明  不提升赋值
        // undefined 表示声明变量未给值
        // console.log(num + '件')
        // var num = 10
        // console.log(num + '件');

        function fn () {
            console.log(num)
            var num = 10
            // 相当于 var num
            // console.log(num)
            // num=10
        }
        fn()
    </script>

2.2 函数提升

建议:使用let或者const,遵循先声明后使用

  <script>
        // 1.会把所有函数声明提升到当前作用域的前面
        // 2.提升函数声明 不提升函数调用
        fn()
        function fn () {
            console.log('函数提升')
        }
        // 函数表达式 必须先声明和赋值 后调用 否则报错
        fun()
        var fun = function () {
            console.log('函数表达式')
        }
        // 因为上面这句话是使用var定义的,根据var的变量提升,所以会有
        // var fun
        // fun()
        // function() {
        //     console.log('函数表达式')
        // } 不可能实现声明里面没赋值就可以调用
    </script>

二、箭头函数

2.1 动态参数

  1. arguments 是一个伪数组(具有length和索引号,但是它不具有数组的push(), pop(), forEach(), map(), filter() 等方法。),只存在于函数中
  2. arguments 的作用是动态获取函数的实参
  3. 因为具有length和索引号,所以可以通过for循环依次得到传递过来的实参
  4. arguments的好处就是当我们传入的实参数量不固定时,也就是一会求两个数的和,一会求三个、四个…此时形参就是不固定的 此时使用arguments就非常好用 如下案例:
    <script>
        // 每一个函数里面默认都有一个动态参数arguments作为形参,所以不用特别将arguments写进形参中
        // function getSum () {
        //     console.log(arguments)
        // }
        // getSum(2, 5, 56)
        function getSum () {
            let sum = 0
            // arguments动态参数 只存在于函数里面
            for (let i = 0; i < arguments.length; i++) {
                sum += arguments[i]
            }
            console.log(sum)
        }
        getSum(2, 34, 5, 67, 3)
    </script>

2.2 this问题

查找this的方法:从当前作用域查找,如果查找不到 就按照作用域链来查找

案例一:最简单的函数调用中,this的指向问题
在这里有一个误区,因为是fn调用的,所以this指向fn 注意:fn()是函数的定义,不是调用者。fn()在调用时,全写为 window.fn(),所以调用者是window

function fn () {
            console.log(this)

        }
        fn() 

案例二:不要看到{},就认为是作用域
不要看到{},就认为是作用域,这样会误认为obj是函数的调用者,作用域是由函数和块级语句创建的。我们判定作用域就是如果不是函数也不是块级语句,+含有{},就不是作用域。
案例:指向的是函数的调用者=>对象

  const obj = {
            name: 'andy',
            sayHi: function () {
                console.log(this)//指向的是函数的调用者=>对象
            }
        }
        obj.sayHi()

案例三:全局作用域 指向window

// 全局作用域 指向window
        const obj1 = {
            uname: 'Pink老师',
            sayHi: () => {
                console.log(this)
            }
        }
        obj1.sayHi()

案例四:函数里面套箭头函数,指向obj2
因为箭头函数中没有this 所以往上一层找 通过上一层的函数指向了函数的调用者obj2

// 指向obj
        const obj2 = {
            uname: 'pink老师',
            sayHi: function () {
                let i = 10
                const count = () => {
                    console.log(this)
                }
                count()
            }
        }
        obj2.sayHi()

剩余与展开

剩余参数的定义是 . . .数组名 是一个真数组 与arguments异曲同工

 function getSum (...arr) {
            // console.log(arr)
            let sum = 0
            for (let i = 0; i < arr.length; i++) {
                sum += arr[i]
            }
            console.log(sum)

        }
        getSum(1, 2, 3)

但是,因为arguments需要在函数里面,这就带来一些不方便,所以…arr,它可以实现求最值,合并数组等功能。

 <script>
        // const arr = [1, 2, 3]
        // console.log(...arr);
        // console.log(Math.max(...arr))  //里面放的只能是字符 不能是数字
        // 合并数组
        const arr1 = [1, 2, 3]
        const arr2 = [3, 4, 5]
        const arr3 = [...arr1, ...arr2]
        console.log(arr3);
    </script>

剩余参数的另一种应用

从前到后,形参和实参一一对应,但是如果实参过于多,后面的统一由剩余参数接收

 <script>
        function getSum (a, b, ...arr) {
            console.log(arr)  // 使用的时候不需要写 ...
        }
        getSum(2, 3)
        getSum(1, 2, 3, 4, 5)
    </script>

2.3 箭头函数

基本语法

 <script>
        // const fn = function () {
        //     console.log(123)
        // }
        // fn()
        // 1.箭头函数基本语法
        // const fn = () => {
        //     console.log(123)
        // }
        // fn()
        // const fn = (x) => {
        //     console.log(x)
        // }
        // fn(1)
        // 2.只有一个形参的时候 可以省略小括号
        // const fn = x => {
        //     console.log(x)
        // }
        // fn(1)
        // 3.只有一行代码的时候 可以省略大括号
        // const fn = x => console.log(x)
        // fn(1)
        // 4.只有一行代码的时候 可以直接省略return
        // const fn = x => x + x
        // console.log(fn(1))
        // 5.箭头函数可以直接返回个对象  将大括号转化为小括号
        const fn = uname => ({ uname: uname })
        console.log(fn('刘德华'));
    </script>

使用箭头函数求和

 <script>
        //箭头函数中没有arguments参数, 并且实参中传入的是字符,可以通过...转化为数组 很方便地实现数组中国数据的迭代
        const getSum = (...arr) => {
            let sum = 0
            for (let i = 0; i < arr.length; i++) {
                sum += arr[i]
            }
            return sum
        }
        const result = getSum(2, 3, 4)
        console.log(result);
    </script>
  <script>
        // 以前this的指向 谁调用的这个函数 this就指向谁
        // console.log(this)
        // function fn () {
        //     console.log(this)
        // }
        // window.fn()
        const obj = {
            name: 'anfy',
            sayHi: function () {
                console.log(this)  //指向的是对象
            }
        }
        obj.sayHi()


        const obj1 = {
            uname: 'pink老师',
            sayHi: () => {
                console.log(this)
                // this指向window  因为箭头函数中没有this  所以要去window中找
            }
        }
        obj1.sayHi()
        // 当前区域没有this  按照作用域链往上一层找  函数里面有this
        const obj2 = {
            uname: 'pink老师',
            sayHi: function () {
                let i = 10
                const count = () => {
                    console.log(this)
                }
                count()
            }
        }
        obj2.sayHi()

        btn.addEventListener('click', () => {
            console.log(this)
        })

    </script>

这里我有一个困扰 不知道大家有没有 就是我在纠结 btn.addEventListener(‘click’, () => {
console.log(this)

    })  我想的是箭头函数没有this  它可以跑到外层  外层就是add  不就可以指向函数的调用者了吗
    addEventListener 本身并不是一个作用域(scope),而是一个方法(method)。作用域是 JavaScript 中变量和函数可访问性的区域。主要由函数和代码块(如 { ... })创建。
    既然箭头函数中没有this  往外走到父级作用域  所以也就来到了全局作用域  全局作用域指向window
     addEventListener 的回调中,外层上下文并不是 addEventListener 函数本身,而是定义箭头函数的那个作用域。 箭头函数被定义在一个全局作用域或模块作用域中
 <script>
        // 1.以前this的指向 谁调用的这个函数 this就指向谁
        // console.log(this)
        // function fn () {
        //     console.log(this)
        // }
        // window.fn()   //===fn()
        const obj = {
            name: 'anfy',
            sayHi: function () {
                console.log(this)  //指向的是函数的调用者,也就是对象
            }
        }
        obj.sayHi()


        const obj1 = {
            uname: 'pink老师',
            sayHi: () => {
                console.log(this)
                // this指向window  因为箭头函数中没有this  所以要去window中找
            }
        }
        obj1.sayHi()
        // 当前区域没有this  按照作用域链往上一层找  函数里面有this
        const obj2 = {
            uname: 'pink老师',
            sayHi: function () {
                let i = 10
                const count = () => {
                    console.log(this)
                }
                count()
            }
        }
        obj2.sayHi()

        btn.addEventListener('click', () => {
            console.log(this)
        })

    </script>

三、 解构赋值

解构赋值是一种快速为变量赋值的简洁语法,本质上仍然是为变量赋值
分为:数组解构
对象解构

3.1 数组解构

数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法.
基本语法:
1.左侧的[ ]用于声明变量因为是多个,所以是批量声明变量,右侧数组的单元值将被赋值给左侧的变量中。
2.变量的顺序对应数组单元值的位置依次进行赋值操作。

 // 数组解构 赋值
        const arr = [100, 60, 80]
        // const [max, min, avg] = arr
        const [max, min, avg] = [100, 60, 80]
        console.log(max)
        console.log(min)
        console.log(avg)
        // 交换两个变量的值
        let a = 1
        let b = 2;
        [b, a] = [a, b]
        console.log(a, b);

必须加分号的两种情况:

  // 1.立即执行函数要加分号
        (function () { })();
        (function () { })()
        // 2.使用数组的时候
        const arr = [1, 2, 3]
        const str = 'pink'
            // 真正数组前面要加上分号
            ;[1, 2, 3].map(function (item) {
                console.log(item)
            })
        // 数组名不用加上分号
        // arr.map(function (item) {
        //     console.log(item)
        // })

数组解构的一些细节:

// 1.变量多 单元值少  undefined
        // const [a, b, c, d] = [1, 2, 3]
        // console.log(a)
        // console.log(b)
        // console.log(c)
        // console.log(d)

        // 2.变量少 单元值多
        const [e, f] = [1, 2, 3]
        console.log(e)
        console.log(f)

        // 3.剩余参数 变量少 单元制多
        const [g, h, ...i] = [1, 2, 3, 4]
        console.log(g)
        console.log(h)
        console.log(i)
        // 4.防止有undefined传单元值  设置默认值
        // const [a = 0, b = 0] = []
        // console.log(a)
        // console.log(b)
        // const [c = '手机', d = '华为'] = ['小米']
        // console.log(c)
        // console.log(d)
        // 5.按需导入  忽略返回值  以逗号隔开
        // const [a, b, , d] = [1, 2, 3, 4]
        // console.log(a)
        // console.log(b)
        // console.log(d)
        // 6.支持多维数组结构
        // 一般的多维数组
        // const arr = [1, 2, [3, 4]]  //二维
        // console.log(arr[0])
        // console.log(arr[1])
        // console.log(arr[2][0]);
        // 数组解构
        const [a, b, [c, d]] = [1, 2, [3, 4]]  //二维
        console.log(a)
        console.log(b)
        console.log(c)
        console.log(d);

3.2 对象解构

对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法

对象解构的几种情况:

 <script>
        // 1.对象解构
        // const obj = {
        //     // 对象里面为属性  对象外面的为变量
        //     uname: 'pink老师',
        //     age: 18
        // }
        // 2.解构的语法  变量名字 属性名字相同  
        // const { uname, age } = {
        //     // 对象里面为属性
        //     uname: 'pink老师',
        //     age: 18
        // }
        // console.log(uname)
        // console.log(age)
        // 3.对象解构的变量名 可以重新改名  旧变量名:新变量名
        // const { uname: username, age } = { uname: 'pink老师', age: 18 }
        // console.log(username)
        // console.log(age);

        // 4.数组对象解构
        const pig = [
            {
                uname: '佩奇',
                age: 18
            }
        ]
        const [{ uname, age }] = pig
        console.log(uname);
    </script>

多级对象解构

 // 多级对象解构 也就是对象里面套对象
        const pig = {
            name: '佩奇',
            family: {
                mother: '猪妈妈',
                father: '猪爸爸',
                sister: '乔治'
            },
            age: 7
        }
        const { name, family: { mother, father, sister } } = pig
        console.log(name)
        console.log(mother)
        console.log(father)
        console.log(sister);

对象解构综合案例

  <script>
        // 1. 这是后台传递过来的数据
        const msg = {
            "code": 200,
            "msg": "获取新闻列表成功",
            "data": [
                {
                    "id": 1,
                    "title": "5G商用自己,三大运用商收入下降",
                    "count": 58
                },
                {
                    "id": 2,
                    "title": "国际媒体头条速览",
                    "count": 56
                },
                {
                    "id": 3,
                    "title": "乌克兰和俄罗斯持续冲突",
                    "count": 1669
                },

            ]
        }
        // 需求一,将以上msg对象 采用对象解构的方式 只选出data数据使用来作为渲染页面的数据

        // const { data } = msg
        // console.log(data)

        // 需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做参数传递给 函数
        // msg虽然很多属性 但是我们利用解构只要data值
        // const { data } = msg
        // 所以这个{}相当于在说要对那个对象进行对象解构
        function render ({ data }) {
            // const { data } = arr
            console.log(data)
        }
        render(msg)
        // 需求3, 为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为 myData
        function render ({ data: myData }) {
            console.log(myData)
        }
        render(msg)
    </script>

forEach方法

<script>
        const arr = ['red', 'green', 'pink']
        // item是必须要写的 
        // foreach就是纯遍历  加强版的for循环  适合于遍历数组对象
        const result = arr.forEach(function (item, index) {
            console.log(item)//每个数组元素
            console.log(index)//索引号
        })
        console.log(result)//不返回值
    </script>

综合案例

综合案例一:

小热身,先讲一个结合forEach方法小案例:


首先这个案例其实就是页面已经设计好了,只要我们拿到数据,渲染到页面就行了,下面的item就是需要填写的数据,这些数据如果没有js,我们填入的都是死的数据,现在有了js,数据就变成活得了,将获得的数据填写在item中,然后将item追加到list大页面中。又下面的item都是字符串,所以我们采用字符串拼接,最后追加到list中。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8aad29cd731a4d18903cda7d7f5609d0.png)
***完整代码 我贴在最后了***
```javascript
  //1.声明一个字符串变量
        let str = ''
        // 2.遍历数据,遍历8次
        goodsList.forEach(item => {
            // console.log(item)
            const { id } = 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>`
        })
        //最后追加
        document.querySelector('.list').innerHTML = str

filter 筛选数组 返回的是真数组

<script>
        const arr = [10, 20, 30]
        // const newArr = arr.filter(function (item, index) {
        //     // 也有用item和index
        //     // console.log(item)
        //     // console.log(index)
        //     return item >= 20
        // })
        // console.log(newArr);
        // 写成箭头函数
        const newArr = arr.filter(item => item >= 20)
        console.log(newArr);
    </script>

综合案例二、渲染函数——筛选(filter)

完整代码见 ## 完整代码2

  // 1.渲染函数 封装
        function render (arr) {
            //声明空字符串
            let str = ''
            //遍历数组
            arr.forEach(item => {
                // 解构
                const { name, picture, price } = item
                str += `<div class="item">
      <img src=${picture} alt="">
      <p class="name">${name}</p>
      <p class="price">${price}</p>
    </div>`
            })
            //追加给list
            document.querySelector('.list').innerHTML = str
        }
        render(goodsList)//页面一打开就需要渲染
        // 2.过滤筛选
        document.querySelector('.filter').addEventListener('click', e => {
            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)
            }
        })

完整代码1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商品渲染</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .list {
            width: 990px;
            margin: 0 auto;
            display: flex;
            flex-wrap: wrap;
            padding-top: 100px;
        }

        .item {
            width: 240px;
            margin-left: 10px;
            padding: 20px 30px;
            transition: all .5s;
            margin-bottom: 20px;
        }

        .item:nth-child(4n) {
            margin-left: 0;
        }

        .item:hover {
            box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
            transform: translate3d(0, -4px, 0);
            cursor: pointer;
        }

        .item img {
            width: 100%;
        }

        .item .name {
            font-size: 18px;
            margin-bottom: 10px;
            color: #666;
        }

        .item .price {
            font-size: 22px;
            color: firebrick;
        }

        .item .price::before {
            content: "¥";
            font-size: 14px;
        }
    </style>
</head>

<body>
    <div class="list">
        <!-- <div class="item">
      <img src="" alt="">
      <p class="name"></p>
      <p class="price"></p>
    </div> -->
    </div>
    <script>
        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: '99.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',
            },
        ]
        //1.声明一个字符串变量
        let str = ''
        // 2.遍历数据,遍历8次
        goodsList.forEach(item => {
            // console.log(item)
            const { id } = 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>`
        })
        //最后追加
        document.querySelector('.list').innerHTML = str
    </script>
</body>

</html>

完整代码2

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商品渲染</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .list {
            width: 990px;
            margin: 0 auto;
            display: flex;
            flex-wrap: wrap;
        }

        .item {
            width: 240px;
            margin-left: 10px;
            padding: 20px 30px;
            transition: all .5s;
            margin-bottom: 20px;
        }

        .item:nth-child(4n) {
            margin-left: 0;
        }

        .item:hover {
            box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
            transform: translate3d(0, -4px, 0);
            cursor: pointer;
        }

        .item img {
            width: 100%;
        }

        .item .name {
            font-size: 18px;
            margin-bottom: 10px;
            color: #666;
        }

        .item .price {
            font-size: 22px;
            color: firebrick;
        }

        .item .price::before {
            content: "¥";
            font-size: 14px;
        }

        .filter {
            display: flex;
            width: 990px;
            margin: 0 auto;
            padding: 50px 30px;
        }

        .filter a {
            padding: 10px 20px;
            background: #f5f5f5;
            color: #666;
            text-decoration: none;
            margin-right: 20px;
        }

        .filter a:active,
        .filter a:focus {
            background: #05943c;
            color: #fff;
        }
    </style>
</head>

<body>
    <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>
        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: '99.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',
            },
        ]
        // 1.渲染函数 封装
        function render (arr) {
            //声明空字符串
            let str = ''
            //遍历数组
            arr.forEach(item => {
                // 解构
                const { name, picture, price } = item
                str += `<div class="item">
      <img src=${picture} alt="">
      <p class="name">${name}</p>
      <p class="price">${price}</p>
    </div>`
            })
            //追加给list
            document.querySelector('.list').innerHTML = str
        }
        render(goodsList)//页面一打开就需要渲染
        // 2.过滤筛选
        document.querySelector('.filter').addEventListener('click', e => {
            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>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/626614.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关闭 Visual Studio Code 项目中 的eslint的语法校验 lintOnSave: false;; 项目运行起来之后 自动打开浏览器 端口

1、在 vue.config.js 配置 一个属性 lintOnSave: false 2、配置两个属性 open: true, // 自动打开浏览器 port: 3000 // 端口 port 端口号根据自己的项目实际开发来 配置

C++类细节,反汇编,面试题02

文章目录 2. 虚函数vs纯虚函数3. 重写vs重载vs隐藏3.1. 为什么C可以重载&#xff1f; 4. struct vs union4.1. 为什么要内存对齐&#xff1f; 5. static作用6. 空类vs空结构体6.1. 八个默认函数&#xff1a;6.2. 为什么空类占用1字节 7. const作用7.1 指针常量vs常量指针vs常量…

用友网络的危与机:2023年亏损约10亿元,王文京面临严肃拷问

“企业在新的产业浪潮来临时&#xff0c;应该主动推进新阶段的产品和业务创新&#xff0c;这样才能够在新的浪潮成为主流的时候&#xff0c;走到行业前面&#xff0c;否则就会从产业发展的潮流中掉下来”。用友网络创始人王文京&#xff0c;曾用“冲浪理论”形容一家企业成功的…

国内好用的测试用例管理工具有哪些?

目前市面上的测试用例管理工具有很多&#xff0c;但由于针对的项目、领域、目标用户&#xff0c;功能也并不一致&#xff0c;所以选择一款适合的测试管理平台并不轻松。做好这件事&#xff0c;首先要需求明确你用测试管理工具干什么&#xff1f;最终想要达到什么目标&#xff1…

C语言学习(八)typedef 虚拟内存 malloc/free

目录 一、typedef 类型重定义&#xff08;一&#xff09;使用&#xff08;二&#xff09;define和typedef的区别1. 编译处理的阶段不同2. 功能不同 二、虚拟内存&#xff08;一&#xff09;虚拟内存分布&#xff08;二&#xff09;内存分布1. 静态分配2. 动态分配 三、malloc/f…

用sunoAI写粤语歌的方法,博主已经亲自实践可行

粤语歌还是很好听的&#xff0c;那么如何使用suno进行粤语歌的创作呢&#xff1f; 本文和大家进行分享下如何进行粤语歌曲的创作。 访问地址如下&#xff08;电脑端/手机端一个地址&#xff09;&#xff1a; ​https://suno3.cn/#/?i8NCBS8_WXTT 在微信浏览器中也可以直接…

RT-DETR改进教程|加入SCNet中的SCConv[CVPR2020]自校准卷积模块!

⭐⭐ RT-DETR改进专栏|包含主干、模块、注意力机制、检测头等前沿创新 ⭐⭐ 一、 论文介绍 论文链接&#xff1a;http://mftp.mmcheng.net/Papers/20cvprSCNet.pdf 代码链接&#xff1a;https://gitcode.com/MCG-NKU/SCNet/ 文章摘要&#xff1a; CNN的最新进展主要致力于设计更…

文字转成活码的3步操作,手机扫码即可查看文本信息

现在经常会通过二维码的方式来传递通知的文字信息&#xff0c;只需要分享文字生成二维码的图片到微信群或者印刷出来&#xff0c;其他人就可以通过扫码来查看文字内容&#xff0c;有利于其他人更快速的获取信息。 目前文本静态码无法通过微信来扫码展示&#xff0c;那么想要解…

服务器被后台爆破怎么处理

服务器后台遭受密码爆破攻击是网络安全中常见的威胁之一&#xff0c;这种攻击通过不断尝试不同的用户名和密码组合来破解系统登录凭证&#xff0c;一旦成功&#xff0c;攻击者便能非法访问系统资源。 本文将介绍如何识别此类攻击&#xff0c;并采取有效措施进行防御&#xff0c…

ETL-kettle数据转换及组件使用详解

目录 一、txt文本转换成excel 1、新建、转换 2、构建流程图 3、配置数据流图中的各个组件 3.1、配置文件文本输入组件 3.2、 配置Excel输出组件 4、保存执行 二、excel转换成mysql &#xff08;1&#xff09;在MySQL数据库中创建数据库&#xff0c;这个根据自身情况。我…

(python)cryptography-安全的加密

前言 cryptography 是一个广泛使用的 Python 加密库&#xff0c;提供了各种加密、哈希和签名算法的实现。它支持多种加密算法&#xff0c;如 AES、RSA、ECC 等&#xff0c;以及哈希函数&#xff08;如 SHA-256、SHA-384 等&#xff09;和数字签名算法(如 DSA、ECDSA 等). 目录 …

一本书打通SLAM在智能汽车/自动驾驶领域应用

自动驾驶技术已成为当今数字化时代汽车行业的热点话题之一。随着技术的不断成熟&#xff0c;越来越多的车辆采用激光SLAM&#xff08;即时定位与地图构建&#xff09;和视觉SLAM技术&#xff0c;实现更高层次的智能网联汽车。SLAM技术在智能网联汽车中的应用是非常重要的&#…

[XYCTF新生赛]-PWN:baby_gift解析(函数调用前需清空eax)

查看保护 查看ida 这里有一处栈溢出&#xff0c;并且从汇编上看&#xff0c;程序将rbp0x20处设置为了rdi&#xff0c;让我们可以控制rdi的值。而程序没有可利用的pop。 完整exp&#xff1a; from pwn import* pprocess(./babygift) premote(gz.imxbt.cn,20833) printf_plt0x4…

如何通过ETL工具对数据进行去重

在数据处理流程中&#xff0c;数据去重是一个至关重要的环节&#xff0c;它能够确保数据分析的准确性和效率。ETL&#xff08;Extract, Transform, Load&#xff09;工具作为数据集成的重要组成部分&#xff0c;提供了强大的功能来帮助用户实现数据的抽取、转换和加载&#xff…

【Unity Shader入门精要 第7章】基础纹理(一)

1. 纹理映射 每一张纹理可以看作拥有一个属于自己的2D坐标空间&#xff0c;其横轴用U表示&#xff0c;纵轴用V表示&#xff0c;因此也称为UV坐标空间。 UV空间的坐标范围为[0&#xff0c;0]到[1&#xff0c;1]&#xff0c;在Unity中&#xff0c;UV空间也是从左下到右上&#…

神经网络复习--卷积神经网络及其扩展

文章目录 卷积卷积网络反向传播已知池化层误差&#xff0c;反向求上一层隐藏层误差已知卷积层的误差&#xff0c;推导该层的W, b的梯度 注意力机制Transformer卷积变体 卷积 卷积神经网络是一个多层的神经网络&#xff0c;每层由多个二维平面组成&#xff0c;每个平面由多个独…

免费pr相册模板mogrt|手机壁纸AI绘画摄影作品照片展示模板视频素材

pr相册模板mogrt&#xff0c;手机壁纸、电脑桌面壁纸、AI绘画、摄影作品、照片展示模板视频素材。 Premiere Pro 2023及以上版本。 全高清&#xff08;19201080&#xff09;分辨率/30fps。 通用表达式&#xff08;适用于所有特效语言&#xff09;。 免费下载&#xff1a;https…

防火墙技术的演进,什么是下一代防火墙(NGFW)?

防火墙技术的演进 防火墙技术的演进经历了不同阶段&#xff0c;从包过滤防火墙到状态检测防火墙&#xff0c;再到集成多种安全功能的UTM&#xff08;统一威胁管理&#xff09;设备&#xff0c;最终发展到具备应用识别能力的NGFW&#xff08;下一代防火墙&#xff09;。 包过滤…

49.乐理基础-拍号的类型-单拍子、复拍子

当前写的东西&#xff0c;如果只是想要看懂乐谱的话&#xff0c;它是没什么意义的&#xff0c;就像我们要把 0&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5。。。称为自然数&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5称为正整…

鸿蒙OS开发:【Stage模型应用程序包结构】

Stage模型应用程序包结构 为了让开发者能对应用程序包在不同阶段的形态更有清晰的认知&#xff0c;分别对开发态、编译态、发布态的应用程序结构展开介绍。 开发态包结构 在DevEco Studio上[创建一个项目工程]&#xff0c;并尝试创建多个不同类型的Module。根据实际工程中的…