解鎖瀏覽器內置API,助力跨標簽/跨頁面數據通信

1 BrodcastChanner

概念

BroadcastChannel接口表示給定源的任何瀏覽上下文都可以訂閱的命名頻道。它允許同源的不同瀏覽器窗口、標簽頁、frame 或者 iframe 下的不同文檔之間相互通信。消息通過message事件進行廣播,該事件在偵聽該頻道的所有BroadcastChannel對象上觸發,發送消息的對象除外。

何為源?

  • 由用于訪問它的URL的方案(協議)、主機名(域名)和端口定義。只有當協議、主機和端口都匹配時,兩個對象才具有相同的源。

何為瀏覽上下文?

  • 瀏覽器(browser)展示文檔的環境。在現代瀏覽器中,通常是一個標簽頁(tab),也可能是一個窗體(window)或只是頁面的一部分。
構成
  • 構造函數:BroadcastChannel
  • 實例屬性:name,頻道名稱
  • 實例方法:
    • 發送消息:postMessage
    • 關閉頻道對象:close
  • 事件:
    • 收到消息時觸發:message,也可以使用onmessage屬性訪問。
使用

1.創建一個鏈接到命名頻道的對象

 const broad = new BroadcastChannel('moment')

2.綁定事件,以便接收消息

broad.onmessage = function (e) {const { value } = e.dataconsole.log('value::',value)
}

3.按需進行消息發送?

    broad.postMessage({value: 'Hi,my baby'
    })
    
    代碼落地
    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>index</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')ul.addEventListener('click', (e) => {//   console.log(e.target.dataset.index)const index = e.target.dataset.indexconst imgUrl = avatarList[index]useBroadSendMsg(imgUrl)img.src = imgUrl//   console.log(imgUrl)})const broad = new BroadcastChannel('moment')broad.onmessage = function (e) {const { value } = e.dataimg.src = value}const useBroadSendMsg = (data) => {setTimeout(() => {broad.postMessage({value: data})}, 500)}</script>
    </html>
    
    <!-- other.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>other</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')ul.addEventListener('click', (e) => {//   console.log(e.target.dataset.index)const index = e.target.dataset.indexconst imgUrl = avatarList[index]useBroadSendMsg(imgUrl)img.src = imgUrl//   console.log(imgUrl)})const useBroadSendMsg = (data) => {setTimeout(() => {broad.postMessage({value: data})}, 500)}const broad = new BroadcastChannel('moment')broad.onmessage = function (e) {const { value } = e.dataimg.src = value}</script>
    </html>
    
    /* common.css */
    * {padding: 0;margin: 0;box-sizing: border-box;
    }ul {list-style: none;
    }.avatar-list {margin: 20px auto;width: 300px;display: flex;justify-content: space-around;
    }
    .user-info {text-align: center;
    }
    .avatar {width: 100px;height: 100px;border-radius: 10px;
    }.avatar-item {width: 80px;height: 80px;
    }
    .avatar-item:hover {cursor: pointer;
    }
    .avatar-item:nth-child(1) {background-image: url('../images/1.jpg');background-size: 100% 100%;
    }.avatar-item:nth-child(2) {background-image: url('../images/2.jpg');background-size: 100% 100%;
    }.avatar-item:nth-child(3) {background-image: url('../images/3.png');background-size: 100% 100%;
    }
    

    2 ServiceWorker

    概念

    ServiceWorker接口提供了對 service worker 的引用。各個瀏覽上下文(例如頁面、worker 等)可以與相同的 service worker 相關聯,每個瀏覽上下文都可以通過唯一的ServiceWorker對象訪問。

    Service worker 運行在 worker 上下文:因此它無法訪問 DOM,相對于驅動應用的主 JavaScript 線程,它運行在其他線程中,所以不會造成阻塞。

    何為worker上下文?

    • 在瀏覽器環境中,Web Worker 是一種可以在瀏覽器后臺運行腳本的機制,它允許在主線程之外創建獨立的線程來執行 JavaScript 代碼。Service Worker 就是基于 Web Worker 技術實現的,它運行在一個特殊的 worker 上下文環境中。

    何為無法訪問DOM?

    • 由于 Service Worker 運行在獨立的 worker 上下文中,與主頁面的 DOM 環境是隔離的。
    • 這意味著 Service Worker 不能直接對頁面上的元素進行修改,比如改變文本內容、修改樣式等。如果需要更新頁面內容,Service Worker 可以通過向主頁面發送消息,由主頁面的 JavaScript 代碼來完成 DOM 操作。

    運行在其他線程中?

    • 在瀏覽器中,主 JavaScript 線程負責處理用戶交互、頁面渲染和執行主頁面的 JavaScript 代碼。如果主線程執行了耗時的操作,如大量的計算或長時間的網絡請求,會導致頁面卡頓,用戶體驗變差。
    • 而 Service Worker 運行在獨立于主 JavaScript 線程的其他線程中,它有自己的執行棧和事件循環。這意味著 Service Worker 中的代碼執行不會阻塞主頁面的渲染和交互。

    既然是獨立出來的,那如何操作呢?

    self

    • 在 Service Worker 中,self是一個全局對象,它類似于主頁面中的window對象。self代表當前的 Service Worker 實例本身,通過它可以訪問 Service Worker 的各種方法和屬性,也可以監聽 Service Worker 生命周期中的各種事件。

    self.clients

    • self.clients是一個Clients對象,它代表了當前與 Service Worker 關聯的所有客戶端(通常是瀏覽器的標簽頁或窗口)。通過self.clients可以對這些客戶端進行管理和操作,比如獲取客戶端列表、向客戶端發送消息等。
    • 可以通過client.postMessage()方法向指定的客戶端發送消息。
    代碼落地
    // service-worker.js
    // 監聽消息事件
    self.addEventListener('message', function (event) {// 獲取發送消息的客戶端 IDconst senderId = event.source.id// 獲取所有受控的客戶端self.clients.matchAll().then(function (clients) {clients.forEach(function (client) {// 避免將消息發送回發送者if (client.id !== senderId) {// 向其他客戶端發送消息client.postMessage(event.data)}})})
    })
    
    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>index</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')if ('serviceWorker' in navigator) {window.addEventListener('load', function () {navigator.serviceWorker.register('./service-worker.js').then(function (registration) {console.log('Service Worker registered successfully:', registration)// 監聽來自Service Worker 的消息navigator.serviceWorker.addEventListener('message', function (event) {const { type, value } = event.dataif (type === 'change-avatar') {img.src = value}})// DOM操作ul.addEventListener('click', (e) => {//   console.log(e.target.dataset.index)const li = e.targetif (li.tagName === 'LI') {const index = li.dataset.indexconst imgUrl = avatarList[index]// 發送消息navigator.serviceWorker.controller.postMessage({type: 'change-avatar',value: imgUrl})img.src = imgUrl}})}).catch(function (error) {console.error('Service Worker registration failed:', error)})})}</script>
    </html>
    <!-- other.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>other</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')if ('serviceWorker' in navigator) {window.addEventListener('load', function () {navigator.serviceWorker.register('./service-worker.js').then(function (registration) {console.log('Service Worker registered successfully:', registration)// 監聽來自 Service Worker 的消息navigator.serviceWorker.addEventListener('message', function (event) {const { type, value } = event.dataif (type === 'change-avatar') {img.src = value}})// 發送消息的按鈕點擊事件// DOM操作ul.addEventListener('click', (e) => {//   console.log(e.target.dataset.index)const li = e.targetif (li.tagName === 'LI') {const index = li.dataset.indexconst imgUrl = avatarList[index]// 發送消息navigator.serviceWorker.controller.postMessage({type: 'change-avatar',value: imgUrl})img.src = imgUrl}})}).catch(function (error) {console.error('Service Worker registration failed:', error)})})}</script>
    </html>

    ?

    3 postMessage

    概念

    **window.postMessage()**方法可以安全地實現跨源通信。通常,對于兩個不同頁面的腳本,只有當執行它們的頁面位于具有相同的協議(通常為 https),端口號(443 為 https 的默認值),以及主機 (兩個頁面的模數Document.domain設置為相同的值) 時,這兩個腳本才能相互通信。

    從廣義上講,一個窗口可以獲得對另一個窗口的引用(比如targetWindow = window.opener),然后在窗口上調用targetWindow.postMessage()方法分發一個MessageEvent消息。接收消息的窗口可以根據需要自由處理此事件。

    怎么拿到另一個窗口的引用?

    其他窗口的一個引用,比如 iframe 的 contentWindow 屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。

    代碼落地
    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>index</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /><link rel="stylesheet" href="./c-post.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul><div class="edit-box"><button class="btn1">打開other頁面</button></div></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')let targetWindow = nullconst btn1 = document.querySelector('.btn1')const btn2 = document.querySelector('.btn2')btn1.onclick = () => {targetWindow = window.open('./other.html')}ul.addEventListener('click', (e) => {const li = e.targetif (li.tagName === 'LI') {const index = li.dataset.indexconst imgUrl = avatarList[index]targetWindow.postMessage({ value: imgUrl }, 'http://127.0.0.1:5500')img.src = imgUrl}})</script>
    </html>
    
    <!-- other.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>other</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /><link rel="stylesheet" href="./c-post.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')const btn = document.querySelector('button')window.addEventListener('message', function (event) {if (event.origin == 'http://127.0.0.1:5500') {const { value } = event.dataimg.src = value}})</script>
    </html>
    

    ?

    4 Storage

    當存儲區域(localStorage 或 sessionStorage)被修改時,將觸發 storage 事件。

    對于全局localstorage,知道的是:

    • 鍵值對形式
    • 存儲只能存儲字符串內容,復雜類型數據需要使用JSON做序列化處理;
    • 不會隨頁面刷新而丟失
    使用

    借助storage事件——在當前修改的這個頁面不會觸發,也就是行為發生的頁面的storage事件不會觸發。

    三個常用字段:

    1. key:"鍵值對"
    2. newValue:"新值"
    3. oldValue:"舊值"
    代碼落地
    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>index</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')ul.addEventListener('click', (e) => {const li = e.targetif (li.tagName === 'LI') {const index = li.dataset.indexconst imgUrl = avatarList[index]// 存儲數據localStorage.setItem('avatar', imgUrl)img.src = imgUrl}})window.addEventListener('storage', (e) => {const newUrl = e.newValueimg.src = newUrl})</script>
    </html>
    
    <!-- other.html -->
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>other</title><link rel="icon" type="image/png" href="../images/applogo.png" /><link rel="stylesheet" href="../css/common.css" /></head><body><div class="user-info"><img class="avatar" src="../images/2.jpg" alt="" /><p class="u-name">姓名:昔冰</p><p class="u- signature">個簽:積善者必有余慶</p></div><ul class="avatar-list"><li class="avatar-item" data-index="0"></li><li class="avatar-item" data-index="1"></li><li class="avatar-item" data-index="2"></li></ul></body><script>const img = document.querySelector('.avatar')const avatarList = ['../images/1.jpg', '../images/2.jpg', '../images/3.png']const ul = document.querySelector('.avatar-list')ul.addEventListener('click', (e) => {const li = e.targetif (li.tagName === 'LI') {const index = li.dataset.indexconst imgUrl = avatarList[index]// 存儲數據localStorage.setItem('avatar', imgUrl)img.src = imgUrl}})window.addEventListener('storage', (e) => {const newUrl = e.newValueimg.src = newUrl})</script>
    </html>
    

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/news/896664.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/news/896664.shtml
    英文地址,請注明出處:http://en.pswp.cn/news/896664.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    Mysql-如何理解事務?

    一、事務是什么東西 有些場景中&#xff0c;某個操作需要多個sql配合完成&#xff1a; 例如&#xff1a; 李四這個月剩下的前不夠交房租了&#xff0c;找張三借1000元急用&#xff1a; &#xff08;1&#xff09;給張三的賬戶余額 減去1000元 updata 賬戶表 set money money -…

    《deepseek FlashMLA :高效的 MLA 解碼內核》:此文為AI自動翻譯

    FlashMLA GitHub - deepseek-ai/FlashMLA FlashMLA 是適用于 Hopper GPU 的高效 MLA 解碼內核&#xff0c;針對可變長度序列服務進行了優化。 當前發布&#xff1a; BF16、FP16塊大小為 64 的分頁 kvcache 快速開始 安裝 python setup.py install 基準 python tests/test_fl…

    Windows對比MacOS

    Windows對比MacOS 文章目錄 Windows對比MacOS1-環境變量1-Windows添加環境變量示例步驟 1&#xff1a;打開環境變量設置窗口步驟 2&#xff1a;添加系統環境變量 2-Mac 系統添加環境變量示例步驟 1&#xff1a;打開終端步驟 2&#xff1a;編輯環境變量配置文件步驟 3&#xff1…

    藍橋杯 之 填空題-位運算與循環

    文章目錄 循環握手問題門牌制作-循環小球反彈幸運數藝術與籃球跑步 位運算3個1美麗的2024 位運算 可以關注這個Lowbit(x) 如何判斷最低位是否是1&#xff1f; num&1 1就說明num最低位是1 循環 循環 握手問題 握手問題 思路分析&#xff1a; 可以直接計算出來&#xff…

    Java進階——反射機制超全詳解

    反射能在運行時動態操作類和對象的能力&#xff0c;極大地增強了程序的靈活性。但是反射的使用也伴隨著性能開銷和安全風險。本文將由博主帶你一起深入探討 Java 反射的核心概念、關鍵類和方法&#xff0c;以及在日常開發中的應用場景。 本文目錄 一、反射的核心概念1. 運行時類…

    OAK相機的抗震性測試

    在工業環境中&#xff0c;雙目視覺相機必須具備與工作環境同等的堅固性。鑒于部分客戶會將我們的相機應用于惡劣環境&#xff08;例如安裝在重型機械上&#xff09;&#xff0c;我們依據EN 60068-2-6:2008標準對相機進行了振動耐受性測試。 測試涉及的相機型號包括&#xff1a…

    Express MVC

    1. 安裝依賴 npm init -y npm install express npm install --save-dev typescript ts-node ejs types/node types/express tsc --init 2. 項目目錄結構如下&#xff0c;沒有的手動創建 /my-app/src/modelsuser.ts/viewsindex.ejsuserList.ejs/controllersuserController.ts…

    apache-maven-3.2.1

    MAVEN_HOME D:\apache-maven-3.2.1 PATH D:\apache-maven-3.2.1\bin cmd mvn -v <localRepository>d:\localRepository</localRepository> setting.xml <?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Soft…

    合并兩個有序鏈表:遞歸與迭代的實現分析

    合并兩個有序鏈表&#xff1a;遞歸與迭代的實現分析 在算法與數據結構的世界里&#xff0c;鏈表作為一種基本的數據結構&#xff0c;經常被用來解決各種問題。特別是對于有序鏈表的合并&#xff0c;既是經典面試題&#xff0c;也是提高編程能力的重要練習之一。合并兩個有序鏈…

    破解密碼防線:滲透測試中的密碼攻擊手法匯總

    密碼是網絡安全中的一道重要防線&#xff0c;然而&#xff0c;若密碼策略不嚴密&#xff0c;往往會為攻擊者提供可乘之機。本文將簡要介紹滲透測試中關于密碼的幾種常見攻擊思路和手法。 1. 確認使用默認及常見的賬號密碼 在滲透測試的初期&#xff0c;攻擊者通常會嘗試使用系…

    CSS Selectors

    當然&#xff0c;理解純CSS選擇器&#xff08;CSS Selectors&#xff09;對于進行UI自動化測試非常重要。CSS選擇器允許您通過元素的屬性、層級關系、類名、ID等來精準定位頁面上的元素。下面我將詳細講解CSS選擇器的常見用法&#xff0c;并結合您的需求提供具體的示例。 1. 基…

    【java】@Transactional導致@DS注解切換數據源失效

    最近業務中出現了多商戶多租戶的邏輯&#xff0c;所以需要分庫&#xff0c;項目框架使用了mybatisplus所以我們自然而然的選擇了同是baomidou開發的dynamic.datasource來實現多數據源的切換。在使用初期程序運行都很好&#xff0c;但之后發現在調用com.baomidou.mybatisplus.ex…

    淺入淺出Selenium DevTools

    前言 在自動化測試領域&#xff0c;Selenium一直是主流工具之一。隨著前端技術的不斷發展&#xff0c;瀏覽器的功能也在不斷豐富。 Selenium 3版本前&#xff0c;一套通用的采集流程如上圖所示&#xff1a; 打開Charles&#xff0c;設置Session自動導出頻次及導出路徑Seleniu…

    04 路由表的IP分組傳輸過程

    目錄 1、路由表的核心結構 2、IP分組傳輸過程和數據包轉發過程 2.1、IP分組傳輸過程 2.2、數據包轉發過程 2.3、IP分組傳輸過程和數據包轉發的區別 3、數據包的變化 3.1、拓撲結構 3.2、傳輸過程詳解&#xff08;主機A → 主機B&#xff09; 3.2.1、主機A發送數據 3.2…

    【子網掩碼計算器:Python + Tkinter 實現】

    子網掩碼計算器&#xff1a;Python Tkinter 實現 引言代碼功能概述代碼實現思路1. 界面設計2. 功能實現3. 事件處理 子網掩碼計算器實現步驟1. 導入必要的庫2. 定義主窗口類 SubnetCalculatorApp3. 創建菜單欄4. 創建界面組件5. 判斷 IP 地址類別6. 計算子網信息7. 其他功能函…

    【練習】【貪心】力扣1005. K 次取反后最大化的數組和

    題目 1005 K 次取反后最大化的數組和 給你一個整數數組 nums 和一個整數 k &#xff0c;按以下方法修改該數組&#xff1a; 選擇某個下標 i 并將 nums[i] 替換為 -nums[i] 。 重復這個過程恰好 k 次。可以多次選擇同一個下標 i 。 以這種方式修改數組后&#xff0c;返回數組 可…

    3dsmax中使用python創建PBR材質并掛接貼圖

    前言 筆者處理模型時下載到一個pbr材質庫貼圖包&#xff0c;手動每次創建材質過于麻煩&#xff0c;因此計劃使用自動化腳本根據貼圖名自動創建材質。 3dsmax的原本腳本使用的是maxscript&#xff0c;語法有點奇怪懶得學&#xff0c;發現也支持使用python編寫腳本&#…

    Metal學習筆記九:光照基礎

    光和陰影是使場景流行的重要要求。通過一些著色器藝術&#xff0c;您可以突出重要的對象、描述天氣和一天中的時間并設置場景的氣氛。即使您的場景由卡通對象組成&#xff0c;如果您沒有正確地照亮它們&#xff0c;場景也會變得平淡無奇。 最簡單的光照方法之一是 Phong 反射模…

    JAVA學習筆記038——bean的概念和常見注解標注

    什么是bean? Bean 就是 被 Spring 管理的對象&#xff0c;就像工廠流水線上生產的“標準產品”。這些對象不是你自己 new 出來的&#xff0c;而是由 Spring 容器&#xff08;一個超級工廠&#xff09;幫你創建、組裝、管理。 由 Component、Service、Controller 等注解標記的…

    start DL from stratch (2)!!!

    start DL from stratch &#xff08;2&#xff09;!!! 一、CPU and GPUcpuGPU安培架構愛達洛夫萊斯架構 二、使用conda創建一個新的虛擬環境三、autodl操作先知Linux復習目錄文件和數據上傳對于整個鏡像的操作守護進程Tips 四、autodl租用創建實例<big>沒有所需要的版本的…