Web APIs - 第5章笔记

目标:

依托 BOM 对象实现对历史、地址、浏览器信息的操作或获取

具备利用本地存储实现学生就业表案例的能力

  • BOM操作
  • 综合案例

JavaScript的组成

  • ECMAScript:
    • 规定了js基础语法核心知识。
    • 比如:变量、分支语句、循环语句、对象等等
  • Web APIs :
    • DOM 文档对象模型 , 定义了一套操作HTML文档的API
    • BOM 浏览器对象模型 ,定义了一套操作浏览器窗口的API

window对象

BOM (Browser Object Model ) 是浏览器对象模型

  • window对象 是一个全局对象,也可以说是JavaScript中的顶级对象
  • 像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
  • 所有通过var定义 在全局作用域中的变量、函数都会变成window对象的属性和方法
  • window对象下的属性和方法调用的时候可以省略window

定时器-延迟函数

JavaScript 内置的一个用来让代码延迟执行 的函数,叫setTimeout

语法:

复制代码
setTimeout(回调函数, 延迟时间毫秒)

setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window

间歇函数setInterval : 每隔一段时间就执行一次, 平时省略window

清除延时函数

复制代码
let timerId = setTimeout(回调函数, 延迟时间毫秒)
clearTimeout(timerId)

注意点

  1. 延时函数需要等待,所以后面的代码先执行
  2. 返回值是一个正整数,表示定时器的编号
javascript 复制代码
<body>
  <script>
    // 定时器之延迟函数

    // 1. 开启延迟函数
    let timerId = setTimeout(function () {
      console.log('我只执行一次')
    }, 3000)

    // 1.1 延迟函数返回的还是一个正整数数字,表示延迟函数的编号
    console.log(timerId)

    // 1.2 延迟函数需要等待时间,所以下面的代码优先执行

    // 2. 关闭延迟函数
    clearTimeout(timerId)

  </script>

</body>

随堂练习

需求:5秒钟之后,广告自动消失

需求拆解:

①:点击关闭按钮可以关闭

②:设置延迟函数时间为5秒

③:调用点击事件 click()

html 复制代码
<!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>5秒钟自动关闭广告</title>
  <style>
    body {
      background-color: #07090c;
    }

    .ad {
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }

    .close {
      position: absolute;
      top: 95px;
      right: 4px;
      width: 20px;
      height: 20px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="ad">
    <img src="./images/ad.png" alt="">
    <span class="close"></span>
  </div>
  <script>
    // 5秒钟之后自动关闭广告
    const closeBtn = document.querySelector('.close')

     // 1. 利用延迟函数自动关闭调用 click()
    let timerID= setTimeout(function () {
      closeBtn.click()        
    }, 5000)

    // 2. 点击关闭按钮可以关闭广告    
    closeBtn.addEventListener('click', function () {
      this.parentNode.style.display = 'none'
      clearTimeout(timerID)  // 清除延迟期
    })

   
  </script>
</body>

</html>

location对象

location是一个对象 它拆分并保存了 URL 地址的各个组成部分

|----------|-------------------------------|
| 属性/方法 | 说明 |
| href | 属性,获取完整的 URL 地址,赋值时用于地址的跳转 |
| search | 属性,获取地址中携带的参数,符号 ?后面部分 |
| hash | 属性,获取地址中的啥希值,符号 # 后面部分 |
| reload() | 方法,用来刷新当前页面,传入参数 true 时表示强制刷新 |

html 复制代码
<body>
  <form>
    <input type="text" name="search"> 
    <button>搜索</button>
  </form>

  <a href="#/music">音乐</a>

  <a href="#/download">下载</a>

  <button class="reload">刷新页面</button>

  <script>
    // location 对象  
    // 1. href属性 (重点) 得到完整地址,赋值则是跳转到新地址
    console.log(location.href)
    // location.href = 'http://www.itcast.cn'

    // 2. search属性  得到 ? 后面的地址 
    console.log(location.search)  // ?search=笔记本

    // 3. hash属性  得到 # 后面的地址
    console.log(location.hash)

    // 4. reload 方法  刷新页面
    const btn = document.querySelector('.reload')
    btn.addEventListener('click', function () {
      // location.reload() // 页面刷新
      location.reload(true) // 强制页面刷新 ctrl+f5
    })
  </script>

</body>

随堂练习

需求:用户点击可以跳转,如果不点击,则5秒之后自动跳转,要求里面有秒数倒计时

分析:

①:利用定时器间歇函数设置链接里面的数字倒计时

②:时间到了,关闭定时器 同时自动跳转 到新的页面 (location.href

html 复制代码
<!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>5秒倒计时跳转页面</title>
  <style>
    span {
      color: red;
    }
  </style>
</head>

<body>
  <a href="http://www.itcast.cn">支付成功<span>5</span>秒钟之后跳转到首页</a>
  <script>
    // 5秒钟之后跳转页面
    // 1. 利用间歇函数来实现链接里面的文字变化 num-- 
    const a = document.querySelector('a')
    // 声明变量 num
    let num = 5
    // 开启间歇函数
    let timerId = setInterval(function () {
      num--
      // console.log(num)
      a.innerHTML = `支付成功<span>${num}</span>秒钟之后跳转到首页`

      // 2. 时间到了,就自动跳转到新的页面 location.href
      if (num === 0) {
        // 停止定时器
        clearInterval(timerId)
        location.href = 'http://www.ithome.com'
      }
    }, 1000)

    a.addEventListener('click',function(e){
        e.preventDefault()
         clearInterval(timerId)
        location.href = 'http://www.ithome.com'
    })
  </script>
</body>

</html>

navigator是对象,它记录了浏览器自身的相关信息

常用属性和方法:

  • 通过 userAgent 检测浏览器的版本及平台
  • 获取剪贴板内容:navigator.clipboard.readText()
javascript 复制代码
// 检测浏览器版本及平台
navigator.userAgent

// 读取当前剪贴板内容
navigator.clipboard.readText()
    .then(res=>{
      console.log(res)      
    })

history对象

history (历史)是对象,主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退等

使用场景

history对象一般在实际开发中比较少用,但是会在一些OA 办公系统中见到。

常见方法:

javascript 复制代码
<body>
  <button class="back">←后退</button>

  <button class="forward">前进→</button>

  <script>
    // histroy对象

    // 1.前进
    const forward = document.querySelector('.forward')
    forward.addEventListener('click', function () {
      // history.forward() 
      history.go(1)
    })
    // 2.后退
    const back = document.querySelector('.back')
    back.addEventListener('click', function () {
      // history.back()
      history.go(-1)
    })
  </script>
</body>

本地存储(今日重点)

本地存储:将数据存储在本地浏览器中,分为两种技术方案:

  1. localStorage

页面刷新或者关闭不丢失数据,实现数据持久化

  1. sessionStorage

只在当前打开的浏览器中有效,关闭浏览器后数据丢失

sessionStorage和 localStorage 存储容量约 5M 左右

localStorage(重点)

作用: 数据可以长期保留在本地浏览器中,刷新页面和关闭页面,数据也不会丢失

**特性:**以键值对的形式存储,并且存储的是字符串

基本操作方法:

html 复制代码
<!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>本地存储-localstorage</title>

</head>

<body>
  <script>
    // 本地存储 - localstorage 存储的是字符串 
    // 1. 存储
    localStorage.setItem('age', 18)

    // 2. 获取
    console.log(typeof localStorage.getItem('age'))

    // 3. 删除
    localStorage.removeItem('age')
  </script>

</body>

</html>

sessionStorage(了解)

特性:

  • 用法跟localStorage基本相同
  • 区别是:当页面浏览器被关闭时,存储在 sessionStorage 的数据会被清除

存储:sessionStorage.setItem(key,value)

获取:sessionStorage.getItem(key)

删除:sessionStorage.removeItem(key)

localStorage 存取复杂数据类型

存复杂类型

**问题:**本地只能存储字符串,无法存储复杂数据类型.

**解决:**需要将复杂数据类型转换成 JSON字符串,再存储到本地

语法: JSON.stringify(复杂数据类型数组或者对象)

什么是JSON字符串:

  • 首先是1个字符串
  • 属性名使用双引号引起来,不能单引号
  • 属性值如果是字符串型也必须双引号
html 复制代码
<body>
  <script>
    // 本地存储复杂数据类型
    const goods = {
      name: '小米',
      price: 1999
    }
    // localStorage.setItem('goods', goods)
    // console.log(localStorage.getItem('goods'))

    // 1. 把对象转换为JSON字符串  JSON.stringify
    localStorage.setItem('goods', JSON.stringify(goods))
    // console.log(typeof localStorage.getItem('goods'))

  </script>

</body>
取复杂类型

**问题:**因为本地存储里面取出来的是字符串,不是对象,无法直接使用

**解决:**把取出来的字符串转换为对象

**语法:**JSON.parse(JSON字符串)

javascript 复制代码
<body>
  <script>
    // 本地存储复杂数据类型
    const goods = {
      name: '小米',
      price: 1999
    }
    // localStorage.setItem('goods', goods)
    // console.log(localStorage.getItem('goods'))

    // 1. 把对象转换为JSON字符串  JSON.stringify
    localStorage.setItem('goods', JSON.stringify(goods))
    // console.log(typeof localStorage.getItem('goods'))

    // 2. 把JSON字符串转换为对象  JSON.parse
    console.log(JSON.parse(localStorage.getItem('goods')))

  </script>

</body>
总结
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <button class="add">保存简单类型数据</button>
    <button class="add1">保存对象</button>
    <button class="get">获取简单类型数据</button>
    <button class="get1">获取对象</button>
    <button class="del">删除</button>
    <script>
        const addBox = document.querySelector('.add')
        const add1Box = document.querySelector('.add1')
        const getBox = document.querySelector('.get')
        const get1Box = document.querySelector('.get1')
        const delBox = document.querySelector('.del')

        // 1. 向当前网站的本地存储中保存一个人的名字
        // setItem
        addBox.addEventListener('click', function () {
            // 保存数据
            // 如果key没有数据的情况下,新增,否则修改
            localStorage.setItem('uname', '小林哥哥')
            localStorage.setItem('uage', 21)
        })

        // 2. 获取本地存储中的数据
        getBox.addEventListener('click', function () {
            // 获取数据
            // let unameRes = localStorage.getItem('uname')
            // 如果获取的key不存在,则返回null
            let unameRes = localStorage.getItem('uname')
            let ageRes = localStorage.getItem('uage')
            // console.log(typeof ageRes)           


            document.write('结果:' + unameRes + ageRes)
        })

        // 3. 移除本地存储的数据
        // 注意点:移除的是指定的key的数据
        delBox.addEventListener('click', function () {
            // removeItem根据指定的key删除本地存储的数据之后,不会返回
            localStorage.removeItem('uage')

        })


        // 5. 将一个对象或者数组存储到localStroage中,需要使用JSON.stringify()转成json字符串之后再保存才可以
        add1Box.addEventListener('click', function () {
            let obj = [{ uname: '小林', uage: 20 },{ uname: '小林1', uage: 21 }]
            // JSON.stringify(对象)
            /*
              概念:JSON字符串
              就是一个对象或者[数组]的字符串表示法,将来可以用在前端与后端进行数据通讯过程中
              一个标准的JSON字符串:
              1. 所有属性名称,都会使用双引号包裹起来
              2. 值,如果是字符串类型,则使用双引号包裹,其他类型的值可以不用

              json字符串和对象之间可以相互转换
              1. json字符串转成对象 , JSON.parse()
              2. 对象转json字符串, JSON.stringify()
            */
            let jsonStr = JSON.stringify(obj)
            // console.log(jsonStr);
            //  json字符串转成对象 -> 可以很方便的去取得字符串里面的相关数据
            // let jsonStr1 = '{"pigName":"佩奇","isMan":false,"age":4}'
            // let pig = JSON.parse(jsonStr1)
            // console.log(pig.pigName,pig.isMan,pig.age)

            //
            localStorage.setItem('person', jsonStr)
        })

        // 6. 从localStorage中获取复杂数据
        get1Box.addEventListener('click', function () {
            // 从localStorage中获取复杂数据拆解
            // 1.  localStorage.getItem('person')
            let jsonStr = localStorage.getItem('person')
            // console.log(jsonStr)            

            // 2. 使用JSON.parse() 转成js 对象
            let personObj = JSON.parse(jsonStr)

            personObj.forEach((item,index)=>{
                console.log(item.uname,item.uage)                
            })

            // console.log(personObj);
            
            // console.log(personObj[1].uname,personObj[1].uage)
        
        })


        // 变体:请保存如下对象数据到本地存储中(studs)再获取出来,遍历在控制台打印
        /*
          const initData = [
                {
                    stuId: 1,
                    uname: '迪丽热巴',
                    age: 22,
                    salary: '12000',
                    gender: '女',
                    city: '北京',
                    time: '2099/9/9 08:08:08'
                }
            ]
        */ 

    </script>

</body>

</html>

渲染渲染业务:

  1. 进入页面读取本地存储中key 为data 里面的数据
  2. 将json字符串转换成对象(数组)
  3. 遍历数组的数据,生成网页的结构将数据显示在页面上
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>学生就业统计表</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="css/index.css" />
</head>

<body>
  <h1>学生就业统计表</h1>
  <form class="info" autocomplete="off">
    <input type="text" class="uname" name="uname" placeholder="姓名" />
    <input type="text" class="age" name="age" placeholder="年龄" />
    <input type="text" class="salary" name="salary" placeholder="薪资" />
    <select name="gender" class="gender">
      <option value="男">男</option>
      <option value="女">女</option>
    </select>
    <select name="city" class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">
      <i class="iconfont icon-tianjia"></i>添加
    </button>
  </form>

  <div class="title">共有数据<span>0</span>条</div>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>薪资</th>
        <th>就业城市</th>
        <th>录入时间</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- <tr>
        <td>1</td>
        <td>张三</td>
        <td>20</td>
        <td>女</td>
        <td>12000</td>
        <td>深圳</td>
        <td>2099/9/9 08:08:08</td>
        <td>
          <a href="javascript:">
            <i class="iconfont icon-shanchu"></i>
            删除
          </a>
        </td>
      </tr> -->
    </tbody>
  </table>
  <script>
    // 参考数据
    // const initData = [
    //   {
    //     stuId: 1,
    //     uname: '迪丽热巴',
    //     age: 22,
    //     salary: '12000',
    //     gender: '女',
    //     city: '北京',
    //     time: '2099/9/9 08:08:08'
    //   }
    // ]

    // 1. 渲染业务
    // 1.2 准备一个函数getData专门来读取本地存储中的数据
    function getData() {
      // 读取本地存储中key 为data里面的数据
      let dataStr = localStorage.getItem('data')

      // 判断如果本地存储没有数据的时候,返回的是[]否则返回的是正常数据数组
      if (dataStr !== null) {
        return JSON.parse(dataStr)
      } else {
        return []
      }
    }

    // 1.2 准备一个函数render专门用来根据数据渲染界面的
    function render() {
      // 1. 调用getData获取本地存储的数据,得到一个数组
      let dataArr = getData()

      // 2. 遍历数组中的每一个元素拼接成tr字符串
      /*
        item的格式:    
      {
        stuId: 1,
        uname: '迪丽热巴',
        age: 22,
        salary: '12000',
        gender: '女',
        city: '北京',
        time: '2099/9/9 08:08:08'
      }
        
      */
     let trStrs= ''
      dataArr.forEach((item, index) => {
        trStrs+=`
            <tr>
            <td>${item.stuId}</td>
            <td>${item.uname}</td>
            <td>${item.age}</td>
            <td>${item.gender}</td>
            <td>${item.salary}</td>
            <td>${item.city}</td>
            <td>${item.time}</td>
            <td>
              <a href="javascript:">
                <i class="iconfont icon-shanchu"></i>
                删除
              </a>
            </td>
          </tr>
        `
      })
      // 3. 将tr的字符串加入到tbody这个元素中(innerHTML)
      document.querySelector('tbody').innerHTML = trStrs
    }


    // 进入页面渲染数据
    render()
  </script>
</body>

</html>

删除业务:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>学生就业统计表</title>
  <link rel="stylesheet" href="./iconfont/iconfont.css">
  <link rel="stylesheet" href="css/index.css" />
</head>

<body>
  <h1>学生就业统计表</h1>
  <form class="info" autocomplete="off">
    <input type="text" class="uname" name="uname" placeholder="姓名" />
    <input type="text" class="age" name="age" placeholder="年龄" />
    <input type="text" class="salary" name="salary" placeholder="薪资" />
    <select name="gender" class="gender">
      <option value="男">男</option>
      <option value="女">女</option>
    </select>
    <select name="city" class="city">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="广州">广州</option>
      <option value="深圳">深圳</option>
      <option value="曹县">曹县</option>
    </select>
    <button class="add">
      <i class="iconfont icon-tianjia"></i>添加
    </button>
  </form>

  <div class="title">共有数据<span>0</span>条</div>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>薪资</th>
        <th>就业城市</th>
        <th>录入时间</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <!-- <tr>
        <td>1</td>
        <td>张三</td>
        <td>20</td>
        <td>女</td>
        <td>12000</td>
        <td>深圳</td>
        <td>2099/9/9 08:08:08</td>
        <td>
          <a href="javascript:">
            <i class="iconfont icon-shanchu"></i>
            删除
          </a>
        </td>
      </tr> -->
    </tbody>
  </table>
  <script>
    // 参考数据
    // const initData = [
    //   {
    //     stuId: 1,
    //     uname: '迪丽热巴',
    //     age: 22,
    //     salary: '12000',
    //     gender: '女',
    //     city: '北京',
    //     time: '2099/9/9 08:08:08'
    //   }
    // ]

    // 1. 渲染业务
    // 1.2 准备一个函数getData专门来读取本地存储中的数据
    // 职责单一
    function getData() {
      // 读取本地存储中key 为data里面的数据
      let dataStr = localStorage.getItem('data')

      // 判断如果本地存储没有数据返回[],否则返回的是正常数据数组
      if (dataStr !== null) {
        return JSON.parse(dataStr)
      } else {
        return []
      }
    }

    // 1.2 准备一个函数render专门用来根据数据渲染界面的
    function render() {
      // 1. 调用getData获取本地存储的数据,得到一个数组
      let dataArr = getData()  // [{},{}] , []

      // 2. 遍历数组中的每一个元素拼接成tr字符串
      /*
        item的格式:    
      {
        stuId: 1,
        uname: '迪丽热巴',
        age: 22,
        salary: '12000',
        gender: '女',
        city: '北京',
        time: '2099/9/9 08:08:08'
      }
        
      */
      let trStrs = ''
      dataArr.forEach((item, index) => {
        trStrs += `
            <tr>
            <td>${item.stuId}</td>
            <td>${item.uname}</td>
            <td>${item.age}</td>
            <td>${item.gender}</td>
            <td>${item.salary}</td>
            <td>${item.city}</td>
            <td>${item.time}</td>
            <td>
              <a href="javascript:" data-id="${item.stuId}">
                <i class="iconfont icon-shanchu"></i>
                删除
              </a>
            </td>
          </tr>
        `
      })
      // 3. 将tr的字符串加入到tbody这个元素中(innerHTML)
      document.querySelector('tbody').innerHTML = trStrs
    }


    // 2. 新增数据业务
    // 2.1 准备一个函数setData专门用来新增数据到本地存储
    function setData(uname, age, salary, gender, city) {
      // 先从本地存储将老数据取出
      let oldDataArr = getData()
      let arrLng = oldDataArr.length  //数组长度  [1] -> 1

      // b。2.在老数据的基础上追加一条新数据    
      oldDataArr.push({
        stuId: arrLng + 1,  // 动态计算id
        uname: uname, //'迪丽热巴',
        age: age,//22,
        salary: salary, //'12000',
        gender: gender, //'女',
        city: city, //'北京',
        time: new Date().toLocaleString()//'2099/9/9 08:08:08'  //新增时间
      })

      // c.3.将新数据转换成json字符串
      localStorage.setItem('data', JSON.stringify(oldDataArr))
    }

    const unameBox = document.querySelector('.uname')
    const ageBox = document.querySelector('.age')
    const salaryBox = document.querySelector('.salary')
    const genderBox = document.querySelector('.gender')
    const cityBox = document.querySelector('.city')

    // 2.2 给添加按钮注册点击事件,调用setData向本地存储追加数据
    document.querySelector('.add').addEventListener('click', function (e) {
      e.preventDefault() //阻止浏览器对于form表单的默认提交行为

      let uname = unameBox.value
      let age = ageBox.value
      let salary = salaryBox.value
      let gender = genderBox.value
      let city = cityBox.value

      // 增加数据非空判断

      // setData向本地存储追加数据
      setData(uname, age, salary, gender, city)

      // 由于数据发生了改变,所以要重新渲染页面
      render()
    })

    // 3. 删除数据
    // 3.1 封装删除业务的方法
    function delData(id) {
      // 1. 获取老数据
      let oldArray = getData()   // [{stuId:,uname:,....},{}]

      // 2. 根据id从数组中删除数据 
      let index
      oldArray.forEach((item, ind) => {
        // ✨✨😒注意===的吭
        if (parseInt(id) === item.stuId) {
          index = ind
        }
      })

      if (index != undefined) {
        // splice 删除数据后,原有组数据会修改
        oldArray.splice(index, 1)

         // 3. 重新将新数据写回到本地存储
         localStorage.setItem('data',JSON.stringify(oldArray))
      }
    }
    

    // 3.2 注册点击事件,调用delData方法传入id值即可完成删除
    document.querySelector('tbody').addEventListener('click',function(e){
      if(e.target.tagName === 'A') {
        e.preventDefault()  // ✨✨✨😒阻止浏览器默认行为
        // alert(e.target.dataset.id)
        let id = e.target.dataset.id
        // console.log(typeof id);
        
        delData(id)  // 删除本地存储的数据
        render() //重新渲染页面
      }
    })

    // 进入页面渲染数据
    render()
  </script>
</body>

</html>
相关推荐
腾讯TNTWeb前端团队1 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰4 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪4 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪4 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy5 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom6 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom6 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom6 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom6 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试