前端通信(渲染、http、缓存、异步、跨域)自用笔记

SSR/CSR:HTML拼接?网页源码?SEO/交互性

SSR (server side rende r)服务端渲染,是指由服务侧(server side)完成页面的DOM结构拼接 ,然后发送到浏览器,为其绑定状态与事件,成为完全可交互页面的过程。
CSR(client side render)客户端渲染,是指由客户端(client side)JS完成页面和数据的拼接,生成DOM结构再交由浏览器渲染成页面的过程。

浏览器从输入url到渲染页面 过程

**合成 URL->本地缓存/拦截请求->**DNS解析IP/端口号(域名缓存)

TCP->HTTP请求

  • DNS 解析:(域名系统Domain Name System)

DNS 查找数据缓存服务中是否缓存过当前域名信息,有则直接返回;

否则,会进行 DNS 解析 返回域名对应的IP 和端口号

如果没有指定端口号,http 默认 80 端口https 默认 443

DNS协议属于应用层协议,一般是运行在UDP协议之上,使用53端口。

OSI模型和TCP/IP协议

HTTP协议:无状态的协议(Cookie/Session识别->状态)

无状态是指服务端无状态是指服务端不会存储每次的会话信息,对于客户端每次发送的请求,都认为它是一个新的请求,上一次会话和下一次会话没有联系。

Http和Https

端口80/443

HTTPS = HTTP + SSl/TLS协议(传输层)

用SSL/TLS对数据进行加密和解密

SSL的全称是Secure Sockets Layer,即安全 套接 层协议

TLS的全称是Transport Layer Security,即安全 传输 层协议

明文/密文

对称加密 数据

非对称加密 秘钥

服务端的公钥和私钥,非对称加密
客户端生成的随机秘钥,对称加密

常见的请求方式

GET/POST

HEAD(报文首部,验证URI有效性

PUT/DELETE(报文文件)

OPTIONS(查询URI支持的HTTP方法)

HTTP标头

Connection: keep-aliveTCP 就会一直保持连接。

隔开一段时间 之后发送几次没有数据内容的网络请求来判断当前连接是不是应该继续保留。

可能会造成大量的无用途连接,白白占用系统资源

Cache-Control

public:响应可以被任何缓存(客户端/代理服务器)缓存

private:响应只能被客户端缓存

no-cache:不应直接使用缓存的副本,而是需要先进行验证

no-store:响应和请求都不应被缓存,即不在本地存储中保存副本。

max-age=<seconds>:秒

Last-Modified/If-Modified-Since

如果将资源的最后修改日期Last-Modified <=**If-Modified-Since,**会 304(Not Modified)

ETag/If-None-Match:服务器生成的资源标识符(哈希值/实体标签)

使用了该头部,即为条件请求,若请求标识符==资源的当前标识符,则304

If-None-Match: "d41d8cd98f00b204e9800998ecf8427e"

主体:服务端响应/客户端请求

Content-Length:字节Byte为单位

Content-Length: 123

Content-Type/Accept:type/subtype ;parameter

应用程序类型(application):

application/x-www-form-urlencoded ​​​​​​​(默认)(URL encoded)表单数据被转换成键值对

application/json:JSON 数据(axios传递对象时默认)
application/xml:XML 数据

多媒体类型(multipart):

multipart/form-data:用于在 HTML 表单上传文件时的数据类型。

文本类型(text):

text/plain:纯文本文件,例如 .txt 文件。

text/html:HTML 文档,用于网页。

text/css:层叠样式表文件,控制网页的样式。

text/xml:XML 数据。

Content-Encoding/Accept-Encoding

Accept-Encoding: gzip, deflate

请求头

User-Agent:发起请求的用户代理(浏览器/应用程序)

Host:访问的主机名+端口

Origin:跨域请求时,指示请求的来源

Origin: https://www.example.com

Connection: keep-alive​​​​​​​

Accept-Language:客户端 偏好的语言。

Accept-Language: en-US,en;q=0.5

凭证Credentials

(例如 cookies、HTTP 认证(用户名和密码)等)

Authorization:在需要身份验证的情况下,包含用于认证的凭据

Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

withCredentials:是否发送凭据

Cookie: sessionid=abc123; username=johndoe​​

响应头

​​​​​Access-Control-Allow-Origin​​​​​​​

Access-Control-Allow-Credentials:是否允许在跨域请求中包含凭据Credentials

Server:HTTP服务器的信息

Server: Apache/2.4.29 (Ubuntu)

Location:客户端重定向的URL。

Location: https://www.example.com/new-page

Content-Disposition:如何显示响应体,通常用于下载文件

Content-Disposition: attachment; filename="document.pdf"​​​​​​​

缓存:Cache-Control+max-age​​​​​​​(HTTP/1.1)>``​​​​​​​Expires( HTTP/1.0****

http版本

1.0->1.1(一次传输多个文件,默认Connection: keep-alive

http1.x解析基于文本

http2.0采用二进制格式 ,新增特性 多路复用、header压缩、服务端推送(静态html资源)

HTTP/2和HTTP/3,主要支持 并发处理减少延迟方面。​​​​​​

HTTP/1.0

短连接(关闭连接)

无持久化(单个连接单个请求/响应)

无管道化(无法并发发送请求)

HTTP/1.1

持久(单个连接不同时间多个请求/响应)

管道化

分块/流式传输(边收边处理)

HTTP/2

二进制传输(更小的帧)

多路复用(单个连接同时多个请求/响应)

头部压缩

可服务器推送

HTTP/3

(QUIC协议)UDP代替TCP(时延,拥塞)

传输层也能多路复用

0-RRT握手

改进头部压缩

http状态码

1xx Informational(信息):接受请求正在处理

100 Cotinue

2xx Successful(成功):请求正常处理完毕

200 OK:有返回内容

201 Created:服务器创建新资源

204 No Content:无返回内容

3xx - Redirection(重定向):附加操作已完成请求

301 Moved Permanently:永久重定向

服务器返回此响应(对GETHEAD 请求的响应)时,会自动将请求者转到新位置。

302 Found:临时重定向

A.cookie 失效 有 CORS 问题

B.代理服务器的目标地址请求的不对,config/index.js 配置的 proxy 的 target

javascript 复制代码
//响应拦截器
if (error.response && error.response.status === 302) {
    if (window.location.host === 'expenseexternal.xx.cn') {
        window.location.href = 'https:///passport-cloud.xxx.cn/login?service=' + encodeURIComponent(window.location.href)
    } 
}

304 Not Modified:304资源缓存

表示客户端发送了一个带有条件的请求 (通常If-Modified-SinceIf-None-Match

4xx Client Error(客户端错误): 服务器无法处理请求

400 Bad Request:请求无效,服务器无法理解

401 Unauthorized:请求未经授权,需要提供凭证
403 Forbidden:服务器理解请求,但拒绝授权访问
404 Not Found:请求的资源不存在

5xx Server Error(服务器错误):服务器处理请求出错

500 Internal Server Error:服务器遇到了错误,无法完成请求

502 Bad Gateway:作为代理或网关的服务器从上游服务器接收到无效响应
503 Service Unavailable:连接超时

强制刷新:重新请求

后端查看配置 Nginx 反向代理参数有没有问题或者重启 Nginx 服务

缓存

强制缓存:Cache-Control+max-age​​​​​​​(HTTP1.1)>``​​​​​​​Expires( 1.0****

​状态码为灰色的请求则代表使用了强制缓存,请求对应的Size值则代表该缓存存放的位置,分别为from memory cache 和 from disk cache。

  • 浏览器读取缓存的顺序为memory --> disk。
  • 访问URL--> 200 --> 关闭标签页 --> 重新打开URL--> 200(from disk cache) --> 刷新 --> 200(from memory cache)

协商缓存:If-None-Match/If-Modified-Since

存储​​​​​​​:js/图片(内存,刷新),css(硬盘,渲染)

本地存储

Cookie:客户端内存/用户硬盘

属性

必选:Name,Value

Domain:域名或 ip(作用域,无法跨域,与端口无关),默认当前域名

一级域名和二级域名之间是允许共享使用的

如果设成 .example.com,那么子域名 a.example.comb.example.com 都可以使用.example.com 的 cookie;反之不可以。

Expires/Max-Age:两种存储类型的Cookie:会话性(默认)持久性

​​​​​​​ 会话性 cookie仅保存在客户端内存中,并在隐私浏览模式 中用户关闭 整个 浏览器时失效

(会话恢复​​​​​​​/恢复 上次打开的标签页​​​​​​​,导致浏览器保留会话 信息,包括Session Cookie

迫使服务器为 session 设置了一个失效时间,

当距离客户端上一次使用 session 的时间超过这个失效时间时,

**服务器就认为客户端已经停止了活动,才会把 session 删除以节省存储空间)**​​​​​​​

持久性 Cookie会保存在用户的硬盘 中(txt ),直至生存期 到或用户直接在网页中单击"注销"等按钮结束会话时才会失效

Max-Age:失效时间(单位秒)

负数 ,该 cookie 为临时 cookie关闭浏览器即失效,

如果为 0 ,表示删除 该 cookie 。默认为 -1

如果 Max-Age 和 Expires 同时存在,以 Max-Age 为准

**HttpOnly:**为 true 时,只有 http 能读取, js不能读,防止恶意脚本通过Cookie 攻击

但能通过 Application 中手动修改 cookie,所以还是没办法防止 XSS 攻击

**Secure:**默认为false,为true表示只有 https 的请求可以携带

SameSite:限制第三方 URL 是否可以携带 cookie(Chrome51 新增,chrome80+ 强制)

一个站点可以包含多个网页,例如个人博客

Lax(默认):在顶级导航和POST请求中发送Cookie,但在跨站点的GET请求中不会发送

"顶级导航" 指的是从一个站点的一个URL 跳转到另一个站点的URL ,通常是通过点击链接输入网址来实现的。

None:任意发送 cookie,但需要同时设置 Secure ,即必须采用https

Priority:优先级

​​​​​​​js操作cookie

​​​​​​​读/改 document.cookie:HttpOnly为 true 时,只有 http 能读取, js不能读取

设置 public /index.html /<script>
html 复制代码
<script>document.cookie = "sso_ticket=ST-xx-cn"</script>

删除:expires=new Date(0)

new Date(0) :970年1月1日UTC时间,0代表的是 Unix 时间戳的起始时间

javascript 复制代码
document.cookie = 'cookieName=; expires=${new Date(0)}; path=/;';

基本刷新只是从本地硬盘中重新拿取数据到浏览器

跨域请求

服务端设置cookie:SameSite=None(任意发送cookie)Secure=true(https)

响应头Access-Control-Allow-Credentials=true(允许发送Credentials)

请求头withCredentials=true(会发送Credentials)

session:存储在服务端,首次会话创建Cookie(name/value:'JSESSIONID'/id)

大小/数量:一般单个cookie 保存的数据大小不超过 4kb,单个域名最多保存 30 个 cookie(浏览器不同有差异),session 没有大小和数量限制;

存储格式:cookie ,localstorage只能存字符串,session 可以存对象;

Token存在cookie/localstorage

复制代码
http://www.example.com/user?token=xxx
服务端不用存储session
避开同源策略:token 完全由应用管理
移动端对cookie支持不友好,存于localstorage

WebStorage

localStorage

javascript 复制代码
localStorage.setItem('uname','zwq')
localStorage.getItem('uname')
localStorage.key(0)
localStorage.removeItem('uname')
localStorage.clear()

sessionStorage

IndexDB 运行在浏览器的非关系型数据库)

​​​​​​​ 前端/后端路由

位置

    • 前端路由:处理在浏览器中展示的页面之间 的导航,单页面应用程序(SPA )中常见,如ReactVue Router。
    • 后端路由:处理服务器端资源的请求和响应,确定服务器如何处理不同的 URL 请求,并返回适当的数据或页面。这是服务器端框架 (如Express、Django)中的基本组成部分。
  1. 导航方式

    • 前端路由:更改 URL一部分 ,而不会重新加载整个页面。这使得用户体验更加流畅,因为只有局部内容 会被刷新,使用浏览器的前进,后退 键的时候会重新发送请求 ,没有合理地利用缓存。单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置。
    • 后端路由:在后端路由中,当用户点击链接或发出请求时,整个页面可能会重新加载,因为服务器会根据请求的 URL 来返回相应的页面或资源。
  2. SEO(搜索引擎优化)

    • 前端路由:由于前端路由一般是基于单页面应用程序,搜索引擎的爬虫可能会遇到困难,因为页面内容大部分是通过 JavaScript 动态生成的。需要额外的工作来优化 SEO。
    • 后端路由:后端路由通常更利于 SEO,因为页面内容在服务器端就已经存在,搜索引擎可以直接索引。

同步 js标签跨域、url

<img src>,<link href>

异步

web-worker(创建分线程):适用于计算密集型任务

当在 HTML 页面中执行脚本 时,页面的状态是不可响应的,直到脚本已完成。

web worker 是运行在后台 的 JavaScript,独立于其他脚本,不会影响页面的性能

Web Worker 线程无法 直接访问 DOM (文档对象模型)元素、操作页面内容,也不能访问浏览器的 Window 和 Document 对象。这是为了防止 Web Worker 影响主页面的交互

index.js为加载到html页面中的主线程(js文件)

work.js为在index中创建的分线程

javascript 复制代码
index.js:
创建分线程  
var w =new webwork('work.js')//创建 Web Worker 对象
向子线程发送数据
w.postmesage('数据') 

work.js:
onmessage = function(ev) {
     console.log(ev);//接受主线程发送过来的ev.data数据
     this.postMessage('数据')//通过 postmesage('数据') 向主线程发送数据
}

通过w.onmessage=function(ev){ev.data} ev.data 接受  a 的值.
w.terminate();//终止 Web Worker

异步ajax、websock协议

ajax是异步的技术术语,最早的api是xhr(XMLHttpRequest)

axios

同构:同样的代码在nodejs端,浏览器端都可用

在浏览器用xhr,Node.js中使用Node的内置http模块
javascript 复制代码
// 在浏览器中,根据其Content-Type头信息,自动转换数据
axios.get('/api/data').then(response => {
  // response.data 将是一个JavaScript对象
});

// 在Node.js中手动设置响应数据类型
axios.get('/api/data', { responseType: 'json' }).then(response => {
  // response.data 将是一个JavaScript对象
});
  • axios 新版本也支持了fetch
  • 第三方库都是基于原生API的,所以axios也还是基于xhr的

fetch es6 api:基于promise,简单易用

javascript 复制代码
window.fetch(url, { method: 'get'})   //fetch() 返回响应的promise 
    // 第一个then  设置请求的格式
        .then(res => return res.json())  // 第一层then返回的是:响应的报文对象  
        .then((data) => {             //第二层:如果想要使用第一层的数据,必须把数据序列化  
                                       res.json() 返回的对象是一个 Promise对象再进行then()
         <!-- data为真正数据 -->
    }).catch(e => console.log("Oops, error", e))

回调函数:参数为函数,且满足条件才执行该参数函数

隐式return 原promise对象/ 显式return (非promise会包装成promise)

then/catch/finally/async

创建 Promise实例

await 值=Promise.resolve(值)

**Promise.resolve(值):**如果该值本身就是一个 promise实例,将直接被返回

Promise.reject(值)

constructor的函数参数:起始函数;同步(立即执行)

起始函数的函数参数(均可选):resolve (起始函数成功时调用)、reject( 失败时调用**)**

状态:都没有的话,状态为pending[待定]初始状态
javascript 复制代码
//​​什么都不输出​​​​​
new Promise(()=>{}).then(()=>{
  console.log("then")
}).finally(()=>{
  console.log("finally")
})

Promise

Promise.prototype(实例)方法

then回调函数:

resolveFn的形参=resolve的参数

catch回调函数:

rejectFn的形参=reject的参数

finally回调函数:

Promise并发方法

allSettled() :多个不依赖于彼此成功完成的异步任务时,或者:想知道每个 promise 的结果时

all:当异步操作之间不存在结果的依赖时,all中的所有方法是一同执行的

javascript 复制代码
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');//setTimeout(function[, delay, arg1, arg2, ...]);
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// Expected output: Array [3, 42, "foo"]
map:promise.reslove(catch)

catch方法返回的promise实例会被**promise.reslove()**包裹,这样传进promise.all的数据都是resolved状态的。

javascript 复制代码
let p1 = Promise.resolve(1)
let p2 = Promise.resolve(2)
let p3 = Promise.resolve(3)
let p4 = Promise.resolve(4)
let p5 = Promise.reject("error")
let arr = [p1,p2,p3,p4,p5];

let all = Promise.all(arr.map((promise)=>promise.catch((e)=>{console.log("错误信息"+e)})))
all.then(res=>{console.log(res)}).catch(err=>console.log(err));

async/await函数

javascript 复制代码
Promise.resolve(a)
  .then(b => {
    // do something
  })
  .then(c => {
    // do something
  })

//等价于
async () => {
  const a = await Promise.resolve(a);
  const b = await Promise.resolve(b);
  const c = await Promise.resolve(c);
}

async关键字+函数

await 操作符 +promise对象

promise对象变成reject状态时,整个async函数会中断

处理异常: try-catch 块
javascript 复制代码
async function asyncFunc() {
    try {
        await new Promise(function (resolve, reject) {
            throw "Some error"; // 或者 reject("Some error")
        });
    } catch (err) {
        console.log(err);
        // 会输出 Some error
    }
}
asyncFunc();

宏任务,微任务,事件循环event loop

微任务 microtask(异步 ):Promise async/await

微任务宏任务

宏任务 macrotask: setTimeout ,setInterval 定时 事件,Ajax,DOM事件,script 脚本的执行、I/O 操作、UI 渲 等。

微任务是JS 级别的,宏任务是宿主 级别的,是包含关系,不是先后关系。

1.macro task先执行

2.当前所有micro task逐条执行

3.下一条macro task执行", 重复上面loop

setTimeout(delay=0)=setImmediate:下个**Event Loop执行**

javascript 复制代码
setTimeout(_ => console.log(5))

new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
}).finally(_=>{
  console.log(4)
})

console.log(2)
// 1 2 3 4 5

url:?(分割url和参数) &(参数分隔符 )#(锚点,id)

http://example.com/page?param1=value1\&param2=value2#section1

跨域

jsonpjs、css,img 静态资源,仅get方式,

现在浏览器兼容性高 了,逐步淘汰

JSONP(JSON With Padding )是利用**<script src=XXX>**跨域

因为是动态创建script标签 ,所以它只支持get请求不支持post请求

**代理服务器:**服务器间不用同源

正向代理主要是用来解决访问限制问题;

反向代理则是提供负载均衡、安全防护等作用。

Nginx反向代理 ​​​​​​​:类似cors字段设置+proxy_pass

前端应用运行在 http://localhost:3000,跨域访问后端 API ,它运行在 http://localhost:8000

javascript 复制代码
server {
    #HTTP 协议来监听请求,应该使用 listen 80;
    listen 80;
    server_name localhost;

    location /api {
        proxy_pass http://localhost:8000;

        # 允许来自前端应用的跨域请求
        add_header 'Access-Control-Allow-Origin' 'http://localhost:3000';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';

        # 支持 OPTIONS 请求,用于预检请求
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' 'http://localhost:3000';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';

            # 响应预检请求,直接返回 204 No Content
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            return 204;
        }
    }
}

proxy

vue.config.js

javascript 复制代码
const configStatic = {
  proxy: {
    '/test': {
      target: 'http://www.xx.cn',// 设置目标服务器的地址
      changeOrigin: true,
      pathRewrite: {
        '^/test': '/'
      }
    }
}

module.exports = configStatic

cors (浏览器IE10以下不支持

服务端Access-Control-Allow-Origin

preflight预检查:跨域复杂请求前,OPTIONS 请求

预检请求是指浏览器在发送跨域请求之前,会先发送一个**OPTIONS 请求,**用于询问服务器是否接受实际的请求。

预检请求主要用于对复杂请求 (例如包含自定义请求头 或使用非简单标头字段的请求)进行安全验证。

简单请求:GET/HEAD/POST+Content-Type:text/plain,multipart/form-data,application/x-www-form-urlencoded

条件2:除了被允许自定义请求头(例如:X-PINGOTHER),请求头仅包含一些简单标头字段,如:Accept、Accept-Language、Content-Language、Content-Type,Range。

其中Content-Type 的值仅限于下列三者之一:

  • text/plain无格式 正文(可以有效避免XSS漏洞)
  • multipart/form-data(键值对型数据)
  • application/x-www-form-urlencoded(URL encoded)(默认

应用

当服务端没有设置跨域时,可以将json伪装成text/plain

原理:

包装成简单请求,以躲过预检查。但是有些客户端或者代理还是会预检查

安全:

浏览器对于 JSON 响应的默认处理机制是自动将其解析为 JavaScript 对象。

当浏览器接收到响应时,如果响应的 Content-Type 是application/json没有指定 Content-Type ,浏览器会自动 将响应体解析为 JSON, JavaScript 对象 ,如果是恶意代码可能会被执行,导致安全漏洞或攻击。

通过将 JSON 响应伪装成 text/plain 类型,可以避免浏览器将响应自动解析为 JavaScript 对象的默认行为。

这样一来,JavaScript 代码需要手动对响应进行解析,确保数据的安全性和正确性。这种伪装可以提供额外的安全层,防止对于响应的自动解析可能带来的安全风险。

javascript 复制代码
//请求头
GET /example HTTP/1.1
Host: example.com
Accept: text/plain
//响应头
HTTP/1.1 200 OK
Content-Type: text/plain
//响应体
{"foo": "bar"}

跨源资源共享(CORS) - HTTP | MDN

Cross-Origin Resource Sharing (CORS) - HTTP | MDN

websocket:HTML5新特性,TCP

兼容性不好 ,只适用于主流浏览器和IE10+

HTML5 的一个持久化 的协议,它实现了浏览器与服务器全双工通信

WebSocketHTTP 都是应用层协议 ,都基于TCP 协议

WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了

原生WebSocket API使用起来不太方便

Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容

本地文件socket.html向localhost:3000发生数据和接受数据:

javascript 复制代码
// socket.html
<script>
    let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('我爱你');//向服务器发送数据
    }
    socket.onmessage = function (e) {
      console.log(e.data);//接收服务器返回的数据
    }
</script>
javascript 复制代码
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
  ws.on('message', function (data) {
    console.log(data);
    ws.send('我不爱你')
  });
})

web安全

XSS跨站脚本攻击Cross-Site Scripting(登陆时执行脚本读取)

解决:

  • url参数使用encodeURIComponent方法转义
  • 尽量不用InnerHtml插入HTML内容

CSRF跨站请求伪造Cross-site request forgery(凭证请求)

解决:添加验证码 、使用token

SQL注入攻击(交表单/输域名 执行SQL命令)

解决:表单输入时通过正则表达式将一些特殊字符进行转换

DDoS攻击分布式拒绝服务 Distributed Denial of Service(请求过载)

解决:

  • 限制单IP请求频率。
  • 检查特权端口的开放
相关推荐
慧一居士6 分钟前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead8 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
陈洪奇6 小时前
注册中心学习笔记整理
笔记·学习
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子6 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年6 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子6 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina6 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路7 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说7 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js