摘要:當(dāng)引擎開(kāi)始執(zhí)行腳本是的時(shí)候,會(huì)先創(chuàng)建一個(gè)全局執(zhí)行上下文,并將其到當(dāng)前執(zhí)行棧,無(wú)論何時(shí)一個(gè)函數(shù)被調(diào)用,就會(huì)創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文并壓入棧中。當(dāng)函數(shù)執(zhí)行完畢,執(zhí)行棧會(huì)將其彈出,并把控制權(quán)交給當(dāng)前棧的下一個(gè)上下文。
從過(guò)去直到 React.lazy
寫(xiě)一個(gè)沒(méi)有 JSX 的 React
執(zhí)行上下文和執(zhí)行棧
公私有域和方法
數(shù)組在性能方面的一個(gè)注意點(diǎn)
從過(guò)去直到 React.lazy code-splitting當(dāng)我們最最開(kāi)始做前端開(kāi)發(fā)的時(shí)候,JavaScript 文件自然就一個(gè)個(gè)羅列在一起,通過(guò) script 標(biāo)簽引入到 html 里。當(dāng)然,即使在現(xiàn)在,我們也還是會(huì)在寫(xiě)一些 Demo 時(shí)使用這樣的方式。
如今,我們有了如 Webpack、Parcel 等 Module bundler 來(lái)為我們更好的組織 JavaScript 文件。我們可以使用各種模塊系統(tǒng)如 CommonJS(require、module.exports)或者 ES Modules(import、export)來(lái)定義文件之間的依賴。
然而,隨著我們的應(yīng)用越來(lái)越大,我們就會(huì)得到一個(gè)巨大的 JS bundle,而這種慢慢等待加載的體驗(yàn)是絕不能忍受的。因此,code-splitting 就成了一種廣泛接受的做法。
下面的例子就是沒(méi)有拆分過(guò)的、只會(huì)打包成一份的應(yīng)用,在加載時(shí)會(huì)同步全部加載再渲染:
import Description from "./Description"; function App() { return (); }My Movie
現(xiàn)在我們來(lái)開(kāi)始看看,如何讓我們的 Module bundler 來(lái)懶加載我們的模塊呢?
Dynamic import proposal動(dòng)態(tài) import 提案為 ES Modules 添加了新特性,使我們可以以異步的方式定義我們的依賴關(guān)系。import 語(yǔ)句可以作為一個(gè)函數(shù)來(lái)調(diào)用,并返回一個(gè) Promise,這個(gè) Promise 會(huì) resolve 我們想要加載的模塊。使用方式只需要從上面的 ES Modules 的 import 方式略加調(diào)整:
- import Description from "./Description"; + const Description = import("./Description");
上面的用法就會(huì)告訴 Webpack 或 Parcel 我們的 Description 模塊并不是立即就需要,而是可以等到加載好后再使用。并且,動(dòng)態(tài) import 就可以使得 Module bundler 將該模塊打包成多帶帶的 js 文件,而這就是所謂的 code-split。
但是還不夠,這還只是開(kāi)始。讓我們繼續(xù)往下走。
React 組件的懶加載如果我們使用上述動(dòng)態(tài) import,我們的 App 組件就要修改成如下的方式:
const LoadDescription = () => import("./Description"); class App extends React.Component { state = { Description: null, }; componentDidMount() { LoadDescription.then(Description => { this.setState({ Description: Description.default }); }); } render() { const { Description } = this.state; return (); } }My Movie
{Description ?: "Loading..."}
這樣寫(xiě)未免就有點(diǎn)蛋疼了,所幸的是我們有一個(gè)非常好用的庫(kù),即 react-loadable:
react-loadable 會(huì)幫我們省掉很多模板代碼,改寫(xiě)后的效果如下:
import Loadable from "react-loadable"; const LoadableDescription = Loadable({ loader: () => import("./Description"), loading() { returnLoading...; }, }); function App() { return (); }My Movie
這樣看上去就好多了,我們就不需要再自己去管生命周期之類的事,只需要靠它來(lái) load 我們需要的組件、指定相應(yīng)的 loading 即可使用。
既然 react-loadable 已經(jīng)這么好用了,我們還干嘛要用 React.lazy 呢?
Suspensereact-loadable 實(shí)際上還是有一些不足的,主要的一點(diǎn)就是它只作用于每一個(gè)多帶帶組件。什么意思呢?如果你有一堆想要懶加載的組件,你需要分別為他們指定 loading 狀態(tài)。當(dāng)然,你可以使用一個(gè)公用的組件,這樣你每個(gè) loading 狀態(tài)都可以復(fù)用,但是你仍然會(huì)看到每一個(gè)懶加載的組件各自有一個(gè) loading。如果你在一個(gè)頁(yè)面有很多懶加載的組件,那就牛逼了,你會(huì)看到一堆小菊花,這恐怕也不是什么好的體驗(yàn)。
說(shuō)到這一缺點(diǎn),在我們團(tuán)隊(duì)的一些項(xiàng)目中,CLI 目前是在路由層面配合使用 react-router 和 react-loadable 的,一次只會(huì) load 一個(gè)組件,因而就不存在一堆要懶加載的組件同時(shí)出現(xiàn)在頁(yè)面上;而 loading 狀態(tài),我們也可以設(shè)計(jì)一個(gè)全局的 Spin 來(lái)使用。總的來(lái)說(shuō),肯定是存在一些方法或替代方案來(lái)彌補(bǔ)或避免這些問(wèn)題的。
但是,在我們目前的工程中,仍然有可以改善的點(diǎn):
一堆 loadable 文件;
react-loadable 有除懶加載以外功能的其他代碼,這些可能是我們不需要的;
如果我們想對(duì)更深層的子組件做懶加載,就還需要引入 loadable 文件,不優(yōu)雅。
好的,讓我們來(lái)看看 React.lazy 可以做到什么吧!
與 react-loadable 不同的是,我們不需要在每一個(gè) React.lazy 處定義一個(gè) loading 狀態(tài),我們要搭配使用 Suspense,在 Suspense 這里定義一個(gè) loading 狀態(tài)。這就意味著,你可以有很多個(gè) React.lazy 組件,但你只需要給對(duì)應(yīng)的 Suspense 指定一個(gè) loading 狀態(tài)就可以了。
此外,我們可以在任意深的地方放入一個(gè) React.lazy 組件,Suspense 會(huì)統(tǒng)一的、干干凈凈的處理好懶加載的任務(wù)。
那么我們要怎樣使用 React.lazy 來(lái)改寫(xiě)上面的代碼呢?如下所示:
import React, { Suspense } from "react"; const Description = React.lazy(() => import("./Description")); function App() { return (); }My Movie
Suspense 就像是 try-catch 一樣,會(huì)「捕獲」到 React.lazy 實(shí)例,然后會(huì)進(jìn)入同一個(gè) fallback 組件。也就是說(shuō),下面的例子中,我們只會(huì)渲染同一個(gè) fallback:
import React, { Suspense } from "react"; const Description = React.lazy(() => import("./Description")); function App() { return (); } // AnotherLazyComponent.js (imagine in another file) const AndYetAnotherLazyComponent = React.lazy(() => import("./AndYetAnotherLazyComponent") ); function AnotherLazyComponent() { return (My Movie
Cast So...so..lazy..); }
如果我們想更自由的指定不同的懶加載組件的不同 loading 狀態(tài),只需要像下面一樣嵌套 Suspense 即可:
function App() { return (); }My Movie
Cast
厲害的是,如果 AnotherLazyComponent 很久都沒(méi)有加載完,沒(méi)關(guān)系,他不會(huì)影響到其他組件的渲染。React.lazy 和 Suspense 會(huì)把 AnotherLazyComponent 和他的子組件們隔離開(kāi)來(lái),避免它加載的延遲影響到其他內(nèi)容的渲染。
這樣一來(lái),與前面沒(méi)有另一個(gè) Suspense 的寫(xiě)法相比,后者就不會(huì)等待所有懶加載組件都加載好后才能呈現(xiàn),而是逐個(gè)呈現(xiàn)各個(gè)組件,這就有些像是 Promise.all 和各自異步的感覺(jué)。
最后是不是可以準(zhǔn)備改造一下項(xiàng)目了呢?
源地址:https://hswolff.com/blog/reac...
參考:https://reactjs.org/docs/code...
寫(xiě)一個(gè)沒(méi)有 JSX 的 React習(xí)慣了 JSX 的寫(xiě)法,今天來(lái)感受下沒(méi)有 JSX 的 React 的酸爽。
我們知道,通常我們?cè)谑褂?React 時(shí)所寫(xiě)的 JSX,都會(huì)被 Babel 編譯成一些方法,一個(gè)很有名的方法就是 React.createElement。
React.createElement 方法需要三個(gè)參數(shù):
type: HTML 元素或組件的類型(例如: h1、h2、p、button 等等);
props: 傳入的屬性對(duì)象;
children: 任何可以穿入的夾在元素中的東西。
簡(jiǎn)單的例子那么我們把最基本的 React 去掉 JSX 來(lái)寫(xiě),就有下面的代碼:
let welcome = React.createElement("h1",{style:{color:"red"}},`Welcome to react world`); ReactDOM.render(welcome,document.querySelector("#root"));
上面的代碼就是純 React,當(dāng)然,ReactDOM.render 方法還是一樣的。
我們調(diào)整下上面的代碼,組織成一個(gè)組件:
class Welcome extends React.Component{ render(){ return React.createElement("h1",{style:{color:"red"}}, `Welcome to ${this.props.name}`); } } ReactDOM.render(React.createElement(Welcome, {name:"Homepage"},null),document.querySelector("#root"));
我們?cè)?React.createElement 方法傳入了第二個(gè)參數(shù) {name:"Homepage"},因此在 Welcome 類內(nèi)部,就可以通過(guò) this.props.name 訪問(wèn)到這個(gè)傳入的屬性。
counter 例子const el = React.createElement; function Button(props){ return el("button", { onClick: props.handleClick }, props.name); } class Counter extends React.Component{ state= { num: 0, } handleIncrement = () =>{ this.setState({ num: this.state.num + 1, }); } handleDecrement = () =>{ this.setState({ num: this.state.num - 1, }); } render(){ return el("div",null, el(Button, { handleClick: this.handleIncrement, name:"Increment" }, null), el(Button,{ handleClick: this.handleDecrement, name:"Decrement" }, null), el("p", null, this.state.num), } } ReactDOM.render(el(Counter,null,null),document.querySelector("#root"))
可以看到,沒(méi)有 JSX,我們的 render 方法變得復(fù)雜了很多。上面代碼的效果如下圖所示:
我們?cè)倩貋?lái)看看 JSX 的寫(xiě)法:
function Button(props) { return } class Counter extends React.Component { state = { num: 0 } handleIncrement = () => { this.setState({ num: this.state.num + 1 }) } handleDecrement = () => { this.setState({ num: this.state.num - 1 }) } render() { return () } } ReactDOM.render({this.state.num}
, document.querySelector("#root"))
JSX 的可讀性原來(lái)還算好的了。
源地址:https://codeburst.io/how-to-u...
執(zhí)行上下文和執(zhí)行棧 什么是執(zhí)行上下文這可能是很多書(shū)本上都會(huì)講的基礎(chǔ)知識(shí),這里我們也帶一遍。執(zhí)行上下文就是 JavaScript 代碼求值和執(zhí)行的環(huán)境。不管跑什么代碼,都是跑在一個(gè)執(zhí)行上下文里。
執(zhí)行上下文有 3 種:
全局上下文
程序里只會(huì)有一個(gè)。
函數(shù)上下文
函數(shù)上下文可以有人以多個(gè),只要一個(gè)新的函數(shù)被調(diào)用,就會(huì)創(chuàng)建一個(gè)函數(shù)上下文,而且他們會(huì)按照一種定義好的順序逐個(gè)執(zhí)行。
Eval 上下文
這個(gè)咱們還是不多講了,危險(xiǎn)。
其實(shí)也就是調(diào)用棧。當(dāng) JavaScript 引擎開(kāi)始執(zhí)行腳本是的時(shí)候,會(huì)先創(chuàng)建一個(gè)全局執(zhí)行上下文,并將其 push 到當(dāng)前執(zhí)行棧,無(wú)論何時(shí)一個(gè)函數(shù)被調(diào)用,就會(huì)創(chuàng)建一個(gè)新的(函數(shù))執(zhí)行上下文并壓入棧中。
引擎會(huì)執(zhí)行那些在棧頂?shù)膱?zhí)行上下文。當(dāng)函數(shù)執(zhí)行完畢,執(zhí)行棧會(huì)將其彈出,并把控制權(quán)交給當(dāng)前棧的下一個(gè)上下文。
舉個(gè)例子:
let a = "Hello World!"; function first() { console.log("Inside first function"); second(); console.log("Again inside first function"); } function second() { console.log("Inside second function"); } first(); console.log("Inside Global Execution Context");
以一個(gè)圖來(lái)展示就是:
怎么個(gè)執(zhí)行真的不需要多說(shuō)了。我們還是接著講點(diǎn)不知道的吧。
執(zhí)行上下文是怎么被創(chuàng)建的?上面的內(nèi)容告訴我們 JavaScript 引擎是怎么管理執(zhí)行上下文的,現(xiàn)在我們來(lái)講下上下文是怎么被創(chuàng)建的。
執(zhí)行上下文的創(chuàng)建總共分兩步:
創(chuàng)建階段
執(zhí)行階段
創(chuàng)建階段執(zhí)行上下文其實(shí)就是在創(chuàng)建階段被創(chuàng)建的。在創(chuàng)建階段,我們會(huì)有兩種環(huán)境被創(chuàng)建:
LexicalEnvironment,我們叫作詞匯環(huán)境;
VariableEnvironment,我們叫作變量環(huán)境。
所以,執(zhí)行上下文可以從概念上標(biāo)識(shí)如下:
ExecutionContext = { LexicalEnvironment =詞匯環(huán)境, VariableEnvironment = , }
官方 ES6 是這么定義詞匯環(huán)境的:
詞匯環(huán)境是一種規(guī)范類型,用于根據(jù) ECMAScript 代碼的詞法嵌套結(jié)構(gòu)定義標(biāo)識(shí)符與特定變量和函數(shù)的關(guān)聯(lián)。詞匯環(huán)境由環(huán)境記錄和的可能為 null 引用的外部詞匯環(huán)境組成。
簡(jiǎn)單來(lái)說(shuō),詞匯環(huán)境就是一種維護(hù)標(biāo)識(shí)符到變量的映射,這里標(biāo)識(shí)符指變量或函數(shù)的名字,而變量指的是一個(gè)實(shí)際對(duì)象(包括函數(shù)對(duì)象、數(shù)組對(duì)象)或基本值的引用。
每個(gè)詞匯環(huán)境由三部分組成:
環(huán)境記錄
外部環(huán)境引用
this binding
我們還需要再繼續(xù)展開(kāi)講:
環(huán)境記錄
環(huán)境記錄,就是變量和函數(shù)聲明存儲(chǔ)在詞法環(huán)境中的位置。有兩種環(huán)境記錄:
聲明式環(huán)境記錄
對(duì)象環(huán)境記錄
前者主要就是存放變量、函數(shù)這類聲明了的,后者則是對(duì)全局的代碼進(jìn)行記錄,例如全局綁定的 window。
注意,對(duì)于函數(shù),環(huán)境記錄還會(huì)包含 arguments 對(duì)象,用于映射傳入函數(shù)的參數(shù)和記錄傳入?yún)?shù)的個(gè)數(shù)。我們舉個(gè)例子就很明白了:
function foo(a, b) { var c = a + b; } foo(2, 3); // argument object Arguments: {0: 2, 1: 3, length: 2},
外部環(huán)境引用
對(duì)外部環(huán)境的引用意味著它可以訪問(wèn)其外部詞匯環(huán)境。這意味著如果在當(dāng)前詞匯環(huán)境中找不到它們,JavaScript 引擎可以在外部環(huán)境中查找變量。
this binding
這一部分就是講 this 是怎么設(shè)置的。
在全局執(zhí)行上下文,this 指向全局對(duì)象,比如瀏覽器環(huán)境下就是 window。
【基礎(chǔ)知識(shí)】在函數(shù)執(zhí)行上下文里,this 就取決于函數(shù)調(diào)用的方式。如果是通過(guò)對(duì)象引用,那么 this 就是這個(gè)對(duì)象,不然的話,this 就會(huì)是全局對(duì)象或者 undefined (嚴(yán)格模式下)。舉個(gè)例子:
const person = { name: "peter", birthYear: 1994, calcAge: function() { console.log(2018 - this.birthYear); } } person.calcAge(); // "this" refers to "person", because "calcAge" was called with //"person" object reference const calculateAge = person.calcAge; calculateAge(); // "this" refers to the global window object, because no object reference was given
綜上:詞匯環(huán)境的偽代碼如下:
GlobalExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here } outer:變量環(huán)境, this: } } FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", // Identifier bindings go here } outer: , this: } }
它也是一個(gè)詞法環(huán)境,因此它具有上面定義的詞法環(huán)境的所有內(nèi)容。唯一的不同是,在 ES6 中,詞法環(huán)境和變量環(huán)境這兩個(gè),前者用于存儲(chǔ)函數(shù)聲明和變量(let 和 const)綁定,而后者僅用于存儲(chǔ)變量(var)綁定。
執(zhí)行階段在這個(gè)階段,變量賦值都結(jié)束了,代碼也最終被執(zhí)行掉。
舉個(gè)例子:
let a = 20; const b = 30; var c; function multiply(e, f) { var g = 20; return e * f * g; } c = multiply(20, 30);
執(zhí)行上述代碼時(shí),JavaScript 引擎會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文來(lái)執(zhí)行全局代碼。因此,在創(chuàng)建階段,全局執(zhí)行上下文將如下所示:
GlobalExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here a: < uninitialized >, b: < uninitialized >, multiply: < func > } outer:, ThisBinding: }, VariableEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here c: undefined, } outer: , ThisBinding: } }
在執(zhí)行階段,完成變量賦值。因此,在執(zhí)行階段,全局執(zhí)行上下文將看起來(lái)像這樣:
GlobalExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here a: 20, b: 30, multiply: < func > } outer:, ThisBinding: }, VariableEnvironment: { EnvironmentRecord: { Type: "Object", // Identifier bindings go here c: undefined, } outer: , ThisBinding: } }
當(dāng)遇到函數(shù) multiply(20,30) 被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文來(lái)執(zhí)行函數(shù)代碼。因此,在創(chuàng)建階段,函數(shù)執(zhí)行上下文將如下所示:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", // Identifier bindings go here Arguments: {0: 20, 1: 30, length: 2}, }, outer:, ThisBinding: , }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", // Identifier bindings go here g: undefined }, outer: , ThisBinding: } }
在此之后,執(zhí)行上下文將走完執(zhí)行階段,這意味著完成了對(duì)函數(shù)內(nèi)部變量的賦值。因此,在執(zhí)行階段,函數(shù)執(zhí)行上下文將如下所示:
FunctionExectionContext = { LexicalEnvironment: { EnvironmentRecord: { Type: "Declarative", // Identifier bindings go here Arguments: {0: 20, 1: 30, length: 2}, }, outer:, ThisBinding: , }, VariableEnvironment: { EnvironmentRecord: { Type: "Declarative", // Identifier bindings go here g: 20 }, outer: , ThisBinding: } }
函數(shù)完成后,返回的值存儲(chǔ)在 c 中。因此全局詞匯環(huán)境得到了更新。之后,全局代碼完成,程序結(jié)束。
注意!你可能發(fā)現(xiàn)一個(gè)有意思的東西,就是在創(chuàng)建階段,let 和 const 定義的變量是「未初始化」?fàn)顟B(tài),而 var 定義的則是 undefined。
這是因?yàn)?,在定義階段,代碼會(huì)掃描變量和函數(shù)聲明,函數(shù)聲明會(huì)在環(huán)境中被完整存著,對(duì) var 定義的就會(huì)被初始化成 undefined,而 let 和 const 定義的就成了未初始化狀態(tài)。
這就是為什么,我們?nèi)绻?var 定義的變量定義之前使用它,會(huì)得到 undefined,但在 let 或 const 定義的變量定義之前使用會(huì)報(bào) error。
這就是我們所說(shuō)的提升。
Javascript Hoisting:In javascript, every variable declaration is hoisted to the top of its declaration context.
另一個(gè)點(diǎn)則是,如果在執(zhí)行階段,JavaScript 引擎找不到 let 變量實(shí)際的值,他就會(huì)被賦值為 undefined。
源地址:https://blog.bitsrc.io/unders...
公私有域和方法這篇文章主要介紹 V8 v7.2 和 Chrome 72 新的 class fields 語(yǔ)法,以及即將出現(xiàn)的 private class fields。
我們來(lái)創(chuàng)建一個(gè) IncreasingCounter 實(shí)例:
const counter = new IncreasingCounter(); counter.value; // logs "Getting the current value!" // → 0 counter.increment(); counter.value; // logs "Getting the current value!" // → 1ES2015 class
如果使用 ES2015 class 語(yǔ)法,我們應(yīng)該會(huì)這么實(shí)現(xiàn) IncreasingCounter:
class IncreasingCounter { constructor() { this._count = 0; } get value() { console.log("Getting the current value!"); return this._count; } increment() { this._count++; } }
該類在原型上添上了一個(gè) value getter 和 increment 方法。類有一個(gè)構(gòu)造函數(shù),它創(chuàng)建一個(gè)實(shí)例屬性 _count,并將其默認(rèn)值設(shè)置為0。我們目前傾向于使用下劃線前綴來(lái)表示 _count 不應(yīng)該由該類的使用者直接使用,但這只是一個(gè)約定;它不是真正的「私有」屬性,只是有這個(gè)特殊語(yǔ)義而已。
const counter = new IncreasingCounter(); counter.value; // logs "Getting the current value!" // → 0 // Nothing stops people from reading or messing with the // `_count` instance property.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100756.html
摘要:目前前端主要有以下四種方法會(huì)觸發(fā)對(duì)應(yīng)的回調(diào)方法方法客戶端回調(diào)客戶端回調(diào)參考地址每日一瞥是團(tuán)隊(duì)內(nèi)部日常業(yè)界動(dòng)態(tài)提煉,發(fā)布時(shí)效可能略有延后。 showImg(https://segmentfault.com/img/remote/1460000017975436?w=1200&h=630); 「ES2015 - ES2018」Rest / Spread Properties 梳理 Thr...
showImg(https://segmentfault.com/img/remote/1460000018793640?w=900&h=500); 簡(jiǎn)介 安全、注入攻擊、XSS 13歲女學(xué)生被捕:因發(fā)布 JavaScript 無(wú)限循環(huán)代碼。 這條新聞是來(lái)自 2019年3月10日 很多同學(xué)匆匆一瞥便滑動(dòng)屏幕去看下一條消息了,并沒(méi)有去了解這段代碼是什么,怎么辦才能防止這個(gè)問(wèn)題。事情發(fā)生后為了抗議日本...
摘要:首先,我們需要一個(gè)基本框架來(lái)處理表單域變化和表格提交。最起碼我們需要提供一個(gè)來(lái)告訴如果用戶還沒(méi)有對(duì)表單域進(jìn)行改動(dòng),就不必展示錯(cuò)誤。我們需要一個(gè)來(lái)標(biāo)識(shí)用戶已嘗試提交表單,還需要來(lái)標(biāo)識(shí)表單是否正在提交以及每個(gè)表單域是否正在進(jìn)行異步校驗(yàn)。 showImg(https://segmentfault.com/img/remote/1460000017516912?w=1200&h=630); ...
摘要:配置在設(shè)置項(xiàng)中確認(rèn)包含增加設(shè)置項(xiàng),值為一個(gè)字符串路徑,必須以結(jié)尾在模板中這樣引用在的目錄存放靜態(tài)文件開(kāi)發(fā)期間使用極度低效時(shí)有別的做法注意默認(rèn)為,一個(gè)列表,表示獨(dú)立于的靜態(tài)文件存放位置。 配置 1.在INSTALLED_APPS設(shè)置項(xiàng)中確認(rèn)包含django.contrib.staticfiles 2.增加STATIC_URL設(shè)置項(xiàng),值為一個(gè)字符串(路徑),必須以‘/’結(jié)尾 3.在模板中...
閱讀 2337·2023-04-26 00:28
閱讀 3085·2019-08-30 15:55
閱讀 2755·2019-08-30 12:47
閱讀 1567·2019-08-29 11:04
閱讀 3197·2019-08-28 18:14
閱讀 957·2019-08-28 18:11
閱讀 1683·2019-08-26 18:36
閱讀 3401·2019-08-23 18:21