合集:2023年最全前端面試題考點HTML5+CSS3+JS+Vue3+React18+八股文+手寫+項目+筆試_參宿7的博客-CSDN博客
*表示回顧基礎(chǔ)知識
項目為二面三面,面試官基本就是照著簡歷里面的項目技術(shù)點切入然后深入展開。
為了簡潔,相關(guān)文章參考鏈接在標(biāo)題里
目錄
模塊化規(guī)范
require與import的區(qū)別和使用
js的運行環(huán)境
瀏覽器
Node
特點
js包管理器
npm(Node Package Manager )
yarn(實際開發(fā) 包管理)
優(yōu)勢
用法區(qū)別
npx(Node Package Runner)單獨執(zhí)行包
nvm(Node Version Runner)版本切換
項目規(guī)范
命令(創(chuàng)建運行)
項目文件結(jié)構(gòu)
package.json
package-lock.json
node_modules
git代碼管理
常用命令
分支
git多人協(xié)同merge沖突
暫時保存更改
性能優(yōu)化
webpack打包管理
原理
Babel
loader
plugin
loader和plugin的區(qū)別
熱加載原理
TS4 加分項
類型
never,any,unknown
類型斷言as與非空斷言!
函數(shù)類型和void
泛型
應(yīng)用
變量
?*類型注解
數(shù)組
函數(shù)
類
類型判斷
is
Narrowing down sets
樣式
Ant Design
Css、less、Sass?(SCSS)
Sass
瀑布流
css
js
共性
問項目中有哪些難點,怎么解決的
代碼遇到?jīng)_突怎么辦
業(yè)務(wù)系統(tǒng)的搭建過程
復(fù)盤過程
拆分組件
如何實現(xiàn)自適應(yīng)頁面
*個性
介紹
實現(xiàn)功能
后端接口
登陸注冊
*0.0.0.0,localhost,127.0.0.1
0.0.0.0
localhost
127.0.0.1
分頁
彈窗組件modal
如何實現(xiàn)點擊彈窗外面區(qū)域,彈窗消失
相關(guān)技術(shù)
模塊化規(guī)范
一個模塊是實現(xiàn)一個特定功能的一組方法。
- 由于函數(shù)具有獨立作用域的特點,最原始的寫法是使用函數(shù)來作為模塊,幾個函數(shù)作為一個模塊,但是這種方式容易造成全局變量的污染,并且模塊間沒有聯(lián)系。
// 模塊A
var ModuleA = {
func1: function() {
// ...
},
func2: function() {
// ...
}
};
// 模塊B
var ModuleB = {
func3: function() {
// ...
}
};
???????
- 后面提出了對象,通過將函數(shù)作為一個對象的方法來實現(xiàn),但是這種辦法會暴露所 有的所有的模塊成員,外部代碼可以修改內(nèi)部屬性的值。
- 現(xiàn)在最常用的是立即執(zhí)行函數(shù)的寫法,通過利用閉包來實現(xiàn)模塊私有作用域的建立,同時不會對全局作用域造成污染。
//IIFE(立即調(diào)用函數(shù)表達式)
//創(chuàng)建一個私有作用域,避免變量之間的沖突。然后,通過返回一個對象或函數(shù)來暴露模塊的公共部分
// 模塊A
var ModuleA = (function() {
var privateVar = "private";
function privateFunc() {
// ...
}
return {
publicVar: "public",
publicFunc: function() {
// ...
}
};
})();
- ES6 :使用 import 和 export 的形式來導(dǎo)入導(dǎo)出模塊。
- CommonJS : require 來引入模塊,通過 module.exports 定義模塊的輸出接口。
這種模塊加載方案是服務(wù)器端的解決方案,它是以同步的方式來引入模塊的,因為在服務(wù)端文件都存儲在本地磁盤,所以讀取非???,所以以同步的方式加載沒有問題。
但如果是在瀏覽器端,由于模塊的加載是使用網(wǎng)絡(luò)請求,因此使用異步加載的方式更加合適。
- AMD :Asynchronous Module Definition,這種方案采用異步加載的方式來加載模塊,模塊的加載不影響后面語句的執(zhí)行,所有依賴這個模塊的語句都定義在一個回調(diào)函數(shù)里,等到加載完成后再執(zhí)行回調(diào)函數(shù)。require.js 實現(xiàn)了 AMD 規(guī)范。
- ?CMD :Common Module Definition,這種方案和 AMD 方案都是為了解決異步模塊加載的問題,sea.js 實現(xiàn)了 CMD 規(guī)范。
AMD是預(yù)加載,CMD是懶加載。
AMD是提前執(zhí)行,CMD是延遲執(zhí)行。AMD在對應(yīng)的加載之前導(dǎo)入,CMD在用的時候?qū)?/strong>
???????require與import的區(qū)別和使用
require/import
// CommonJS 的寫法
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// ES6 的寫法
import { func1, func2 } from 'moduleA';
module.exports/export
// commonJS 的寫法
var React = require('react');
var Breadcrumbs = React.createClass({
render() {
return <nav />;
}
});
module.exports = Breadcrumbs;
// ES6 的寫法
import React from 'react';
class Breadcrumbs extends React.Component {
render() {
return <nav />;
}
};
export default Breadcrumbs;
- 規(guī)范:require是CommonJS,AMD規(guī)范的模塊化語法,import是ECMAScript 6規(guī)范的模塊化語法,如果要兼容瀏覽器的話必須轉(zhuǎn)化成es5的語法;CommonJS模塊默認(rèn)export的是一個對象,即使導(dǎo)出的是基礎(chǔ)數(shù)據(jù)類型。
- 本質(zhì):require是賦值過程,其實require 的結(jié)果就是對象、數(shù)字、字符串、函數(shù)等,再把require的結(jié)果賦值給某個變量,引入復(fù)雜數(shù)據(jù)類型時,數(shù)據(jù)淺拷貝該對象。。import是解構(gòu)過程。
- 加載:require是運行時加載,import是編譯時加載;
- 位置:require可以寫在代碼的任意位置,import只能寫在文件的最頂端且不可在條件語句或函數(shù)作用域中使用;
-
改變:require通過module.exports導(dǎo)出的值就不能再變,import通過export導(dǎo)出的值可以改變;
?
js的運行環(huán)境
腳本語言需要一個解析器才能運行,每一種解析器都是一個運行環(huán)境
JavaScript是腳本語言,在不同的位置有不一樣的解析器,
瀏覽器
寫入html的js語言,瀏覽器是它的解析器角色。
瀏覽器中的js的用途是操作DOM,瀏覽器就提供了document之類的內(nèi)置對象。
Node
Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環(huán)境,獨立于瀏覽器的運行環(huán)境
nodejs中的js的用途是操作磁盤文件或搭建http服務(wù)器,nodejs就相應(yīng)提供了fs,http等內(nèi)置對象。
特點
- 簡單:javascript,json進行編碼,
- 強大:非阻塞IO,可以適應(yīng)分塊傳輸數(shù)據(jù),較慢的網(wǎng)絡(luò)環(huán)境,尤其擅長高并發(fā)訪問,
- 輕量:node本身既是代碼,又是服務(wù)器,前后端使用統(tǒng)一語言;
- 可擴展體:輕松應(yīng)對多實例,多服務(wù)器架構(gòu),同時有海量的第三方應(yīng)用組件。
js包管理器
npm(Node Package Manager )
是nodeJS的一個程序包管理和分發(fā)的管理工具,npm完全用 JavaScript 寫成
允許用戶從NPM服務(wù)器下載安裝上傳包
安裝
npm 使用 node 寫的,同時也是 node 的包管理工具,
當(dāng)安裝了 node 就自動安裝了npm,
只是 npm 版本更新比 node 快,更新 npm 指令用:
yarn(實際開發(fā) 包管理)
yarn
由Facebook為解決npm的一些問題而創(chuàng)建的
優(yōu)勢
快速
- 本地緩存+并行下載?- Yarn并行下載,還可以直接從硬盤緩存中讀取包,因此可以顯著提高速度。npm串行下載
- 網(wǎng)絡(luò)連接問題處理?- 當(dāng)Yarn發(fā)現(xiàn)任何網(wǎng)絡(luò)連接問題時,它會自動重試請求,保存響應(yīng)并繼續(xù)構(gòu)建 - 這使得它更容易處理比npm更可靠且快速的環(huán)境。
穩(wěn)定性
- 確定性安裝?- Yarn能夠在包含區(qū)別式鎖文件(yarn.lock)的情況下進行精確的依賴項安裝,每次運行生成相同的代碼版本,與開發(fā)者上次運行相同。npm也有類似的功能,但是許多開發(fā)人員選擇使用Yarn鎖定其依賴關(guān)系以消除任何可能的不確定性。
- 強制命令?- 通過添加--force標(biāo)志,Yarn可以強制執(zhí)行某些操作。這可能看起來像是一種強制手段,但它實際上是保證操作按期望進行的一種方法。npm也有許多命令選項,但是Yarn的操作強迫執(zhí)行機制通常要好得多。
用法區(qū)別
-
安裝包
- Yarn: yarn add
- npm: npm install
-
移除包
- Yarn: yarn remove
- npm: npm uninstall
-
更新
- Yarn: yarn upgrade
- npm: npm update
npm install -g yarn
npx(Node Package Runner)單獨執(zhí)行包
npm install -g npx
nvm(Node Version Runner)版本切換
配置 .bash_profile 文件
-
通過命令 touch .bash_profile ,創(chuàng)建文件夾?.bash_profile;
-
通過命令 open .bash_profile,打開 .bash_profile 文件夾,把下面的內(nèi)容復(fù)制進去;
-
保存并關(guān)閉文件,然后輸入 source .bash_profile 執(zhí)行后重新啟動終端,輸入 nvm -v。檢查是否可以正常顯示版本號。
-
坑1:安裝 nvm 不需要單獨安裝 nodejs,如果裝過了一定要卸載,否則報錯;
-
坑2:裝完 nvm 手動配置.bash_profile 文件,網(wǎng)上教程不適用,不用 cd .nvm 才會成功
項目規(guī)范
整個項目不再使用class組件,統(tǒng)一使用函數(shù)式組件,并且全面用Hooks;
所有的函數(shù)式組件,為了避免不必要的渲染,全部使用memo進行包裹;
組件內(nèi)部的狀態(tài),使用useState、業(yè)務(wù)數(shù)據(jù)全部放在redux中管理;
函數(shù)組件內(nèi)部邏輯代碼基本按照如下順序編寫代碼:
組件內(nèi)部state管理;
redux的hooks代碼;
其他hooks相關(guān)代碼(比如自定義hooks);
其他邏輯代碼;
返回JSX代碼;
redux代碼規(guī)范如下:
redux目前我們學(xué)習(xí)了兩種模式, 根據(jù)自己的情況選擇普通模式還是rtk模式
每個模塊有自己獨立的reducer或者slice,之后合并在一起;
redux中會存在共享的狀態(tài)、從服務(wù)器獲取到的數(shù)據(jù)狀態(tài);
網(wǎng)絡(luò)請求采用axios
對axios進行二次封裝;
所有的模塊請求會放到一個請求文件中單獨管理;
項目使用AntDesign或者MUI(Material UI)
其他規(guī)范在項目中根據(jù)實際情況決定和編寫
命令(創(chuàng)建運行)
npm run start 來運行啟動項目并打開頁面
npx create-react-app my-app //創(chuàng)建項目
cd my-app
npm start
安裝命令:
npx create-react-app 項目名稱 --template typescript ? ??
?
項目文件結(jié)構(gòu)
主要開發(fā)代碼在src目錄下。App.js為根組件,index.js為入口模塊,index.css為全局樣式文件。
package.json
配置jsconfig.json:這個文件在Vue通過腳手架創(chuàng)建項目時自動生成, React是沒有自動生成
package.json相當(dāng)于說明書,其重點字段:
{
"name": "react-ts-app",
"version": "0.1.0",
"private": true,//是否私有,設(shè)置為 true 時,npm 拒絕發(fā)布
"dependencies": {//生產(chǎn)環(huán)境下,項目運行所需依賴
"@ant-design/icons": "^4.8.0",
...
"@types/node": "^16.18.6",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"antd": "^5.0.4",
"axios": "^1.2.1",
"classnames": "^2.3.2",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.4.4",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"sass": "^1.56.1",
"typescript": "^4.9.3",
"web-vitals": "^2.1.4"
},
"scripts": {//執(zhí)行npm腳本命令簡寫,比如“start" : "react-scripts start",執(zhí)行npm start就是運行“react-scripts start"
"start": "SET PORT=8080 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
....
"devDependencies": {//開發(fā)環(huán)境下,項目所需依賴
"@types/lodash": "^4.14.191"
}
}
package-lock.json
用一句話來概括很簡單,就是鎖定安裝時的包的版本號,并且需要上傳到git,以保證其他人在npm install時大家的依賴能保證一致。
node_modules
是安裝node后用來存放用包管理工具下載安裝的包的文件夾。比如webpack、gulp、grunt這些工具。
git代碼管理
常用命令
git init 初始化git倉庫
git status 查看文件狀態(tài)
git add 文件列表 追蹤文件
git commit -m 提交信息 向倉庫中提交代碼
git log 查看提交記錄
分支
1.分支明細(xì)
(1)主分支(master):第一次向 git 倉庫中提交更新記錄時自動產(chǎn)生的一個分支。
(2)開發(fā)分支(develop):作為開發(fā)的分支,基于 master 分支創(chuàng)建。
(3)功能分支(feature):作為開發(fā)具體功能的分支,基于開發(fā)分支創(chuàng)建
2.分支命令
(1)git branch 查看分支
(2)git branch 分支名稱 創(chuàng)建分支
(3)git checkout 分支名稱 切換分支
(4)git merge 來源分支 合并分支 (備注:必須在master分支上才能合并develop分支)
(5)git branch -d 分支名稱 刪除分支(分支被合并后才允許刪除)(-D 強制刪除)
git多人協(xié)同merge沖突
是當(dāng)前修改是左箭頭方向,傳入的是右箭頭的方向,
中間用等于號分割,等號上邊是當(dāng)前修改(本地),下邊是傳入的修改(線上的代碼)。
兩人同時提交可能會出現(xiàn)沖突,解決辦法是手動修改沖突
暫時保存更改
存儲臨時改動:git stash(藏匿)
恢復(fù)改動:git stash pop
- 應(yīng)用場景:
對于多人并行開發(fā),維護同一倉庫工作場景,經(jīng)常會出現(xiàn)文件合并沖突的情況
- 作用:
能夠?qū)⑺形刺峤坏男薷模?strong>工作區(qū)和暫存區(qū))保存至堆棧中,用于后續(xù)恢復(fù)當(dāng)前工作目錄。
git add
只是把文件加到 git 版本控制里
性能優(yōu)化
壓縮js,css,js分包,優(yōu)化圖片(webp),開啟gzip(后端開啟),配置緩存(強制緩存協(xié)商緩存),使用cdn,
webpack分包,減少重繪回流
webpack打包管理
它將根據(jù)模塊的依賴關(guān)系進行靜態(tài)分析,然后將這些模塊(?js、css、less?)按照指定的規(guī)則生成對應(yīng)的靜態(tài)資源,減少了頁面的請求。Webpack是以公共JS的形式來書寫腳本的,方便舊項目進行代碼遷移。
原理
Webpack通過一個給定的主文件(如:index.js)開始找到項目的所有依賴文件,
使用loaders處理它們,plugin可以壓縮代碼和圖片,
把所有依賴打包成一個 或多個bundle.js文件(捆bundle)瀏覽器可識別的JavaScript文件。
Babel
JavaScript 編譯器
將es6、es7、es8等語法轉(zhuǎn)換成瀏覽器可識別的es5或es3語法,即瀏覽器兼容的語法,比如將箭頭函數(shù)轉(zhuǎn)換為普通函數(shù)
將jsx轉(zhuǎn)換成瀏覽器認(rèn)的js
loader
webpack只認(rèn)識JS和JSON,所以Loader相當(dāng)于翻譯官,將其他類型資源進行預(yù)處理,最終變?yōu)?strong>js代碼。
- less-loader:將less文件編譯成css文件(開發(fā)中,會使用less預(yù)處理器編寫css樣式,使開發(fā)效率提高)
- css-loader:將css文件變成commonjs模塊(模塊化的規(guī)范)加載到j(luò)s中,模塊內(nèi)容是樣式字符串
- style-loader:創(chuàng)建style標(biāo)簽,將js中的樣式資源插入標(biāo)簽內(nèi),并將標(biāo)簽添加到head中生效
- ts-loader:打包編譯Typescript文件
plugin
Plugin解決loader 無法實現(xiàn)的事情,比如打包優(yōu)化和代碼壓縮等。
- html-webpack-plugin 處理html資源,默認(rèn)會創(chuàng)建一個空的HTML,自動引入打包輸出的所有資源(js/css)
- mini-css-extract-plugin 打包過后的css在js文件里,該插件可以把css單獨抽出來
- clean-webpack-plugin 每次打包時候,CleanWebpackPlugin 插件就會自動把上一次打的包刪除
loader和plugin的區(qū)別
運行時機
1.loader運行在編譯階段
2.plugins 在整個周期都起作用
熱加載原理
瀏覽器熱更新:開發(fā)時能夠在瀏覽器頁面中實時看到我們代碼的變化產(chǎn)生效果的流程。
熱加載是通過內(nèi)置的 HotModuleReplacementPlugin 實現(xiàn)的
- 構(gòu)建 bundle 的時候,監(jiān)聽文件變化。
- 文件修改會觸發(fā) webpack 重新構(gòu)建,
- 服務(wù)器通過向瀏覽器發(fā)送更新消息,
- 瀏覽器通過 jsonp 拉取更新的模塊文件,
- jsonp 回調(diào)觸發(fā)模塊熱替換邏輯。
TS4 加分項
類型
never,any,unknown
never類型表示永不存在的值的類型,當(dāng)一個值不存在的時候就會被自動類型推斷成never類型。
在出問題的時候會被自動轉(zhuǎn)成never。
any類型表示任意類型,而unknown類型表示為未知類型,是any類型對應(yīng)的安全類型。
類型斷言as與非空斷言!
當(dāng) TypeScript 推斷出來類型并不滿足需求,需要手動指定一個類型,強制說明類型,讓TS編譯不報錯
let a: unknown = 'hello';
a = 123;
(a as []).map(()=>{}) // success
因為b可能是字符串也可能是undefined,所以b.length
的時候就會報錯,這樣我們可以采用非空斷言來告訴TS,這個b肯定不是undefined,所以b只能是字符串,那么b.length
就不會報錯了。
let b: string|undefined = undefined;
b!.length // success
函數(shù)類型和void
function foo(n: number, m?: string): number{
return 123;
}
foo(123, 'hello');
foo(123); // success
當(dāng)函數(shù)沒有return和return undefined的時候返回void類型。
let foo = function(){ // void
}let foo = function(): undefined{ // undefined 不能不寫return的
} // error
泛型
泛型是指在定義函數(shù)、接口、類時,未指定其參數(shù)類型,只有在運行時傳入才能確定。泛型簡單來說就是對類型進行傳參處理。
應(yīng)用
變量
?*類型注解
類型注解:把變量空間與類型空間結(jié)合在一起
type關(guān)鍵字+類型別名
let a: string = 'hello'
//也可以通過類型別名進行連接
type A = string
let a: A = 'hello'
數(shù)組
let arr: Array<number> = [1, 2, 3];
//自定義MyArray實現(xiàn)
type MyArray<T> = T[];
let arr2: MyArray<number> = [1, 2, 3];
函數(shù)
function foo(n: number, m?: string): number{
return 123;
}
foo(123, 'hello');
foo(123); // success
function foo<T>(n: T){
}
foo<string>('hello');
foo(123); // 泛型會自動類型推斷
類
class Foo {
//第一種寫法
//username: string = 'xiaoming';
//第二種寫法
// username: string;
// constructor(){
// this.username = 'xiaoming';
// }
//第三種寫法
username: string;
constructor(username: string){
this.username = username;
}
}
interface A {
username: string
age: number
showName(n: string): string
}
class Foo implements A {
username: string = 'xiaoming'
age: number = 20
gender: string = 'male'
showName = (n: string): string => {
return n
}
}
class Foo {
...
showAge = (n: number): number => {
return n;
}
}
class Foo<T> {
username!: T; //不給初始值可通過非空斷言
}
let f = new Foo<string>();
f.username = 'hello';
class Foo<T> {
username!: T
}
class Baz extends Foo<string> {}
let f = new Baz()
f.username = 'hello'
類型判斷
is
is
?讓 ts 分辨類型
function toUpperCase(x: unknown) {
if(isString(x)) {
x.toUpperCase(); // ?? x is still of type unknown
}
}
-
但是由于這個檢驗函數(shù)(isString)被包裹在 toUpperCase()函數(shù)中,ts 在判斷的時候還是拋出了錯誤提示
-
使用
is
,這里讓我們主動明確的告訴 ts ,在 isString() 這個函數(shù)的參數(shù)是一個 string。
// !?。?使用 is 來確認(rèn)參數(shù) s 是一個 string 類型
function isString(s): s is string {
return typeof s === 'string';
}
Narrowing down sets
function pipsAreValid(pips: number) {
// we check for every discrete value, as number can
// be something between 1 and 2 as well.
return pips === 1 || pips === 2 || pips === 3 ||
pips === 4 || pips === 5 || pips === 6;
}
function evalThrow(count: number) {
if (pipsAreValid(count)) {
// my types are lying ??
switch (count) {
case 1:
case 2:
case 3:
case 4:
case 5:
console.log('Not today');
break;
case 6:
console.log('Won!');
break;
case 7:
// TypeScript does not complain here, even though
// it's impossible for count to be 7
console.log('This does not work!');
break;
}
}
}
count
?是一個?number
?類型,輸入的參數(shù)是沒有問題的。
在我們校驗它的時候,count
不再是一個?number
?類型,而是變成了一個 1-6 number 的特殊類型。
ts 為了防止類型溢出,使用了聯(lián)合類型把原來?number
?類型變成 1-6的數(shù)字(縮小了范圍)
改變處
// 主動使用聯(lián)合類型確保我們的輸入是 1-6的數(shù)字
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
function pipsAreValid(pips: number): pips is Dice {
改變處
return pips === 1 || pips === 2 || pips === 3 ||
pips === 4 || pips === 5 || pips === 6;
}
function evalThrow(count: number) {
if (pipsAreValid(count)) {
// count is now of type Dice ??
switch (count) {
case 1:
case 2:
case 3:
case 4:
case 5:
console.log('Not today');
break;
case 6:
console.log('Won!');
break;
case 7:
// TypeScript errors here. 7 is not in the union type of
// Dice
console.log('This does not work!');
break;
}
}
}
樣式
Ant Design
Css、less、Sass?(SCSS)
less, sass, scss都是css預(yù)處理語言(也是對應(yīng)的文件后綴名)。
CSS 預(yù)處理器為 CSS 增加一些編程的特性,無需考慮瀏覽器的兼容性問題,
可以在 CSS 中使用變量、簡單的邏輯程序、函數(shù)(如變量$main-color)等等在編程語言中的一些基本特性,可以讓?CSS 更加簡潔、適應(yīng)性更強、可讀性更佳,更易于代碼的維護等諸多好處。
開發(fā)時用預(yù)處理語言,在打包上線時,用webpack再配合loader工具給轉(zhuǎn)成css給瀏覽器使用。
Sass
瀑布流
描述:頁面元素的寬度按照屏幕分辨率進行適配調(diào)整,但整體布局不變。主要特征是像瀑布一樣往下流,有規(guī)律的無限遍歷模塊。(阿里、字節(jié)考過)
css
給圖片添加樣式讓圖片等寬并同行顯示。
1、首先我們定義一個container容器來裝所有圖片,在這個容器中用box容器裝box-img容器再裝入每張圖片,這樣方便之后樣式的編寫。
2、使圖片同行顯示--給box容器使用float:left;屬性。
3、讓圖片等寬顯示--給box-img容器設(shè)置width:150px;,img標(biāo)簽設(shè)置width:100%;繼承父容器box-img高度的100%
<!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>waterFall</title>
<script src="./index.js"></script>
</head>
<style>
<!--清除瀏覽器自帶樣式-->
*{
margin: 0;
padding: 0;
}
<!--overflow: hidden觸發(fā)BFC-->
.container {
overflow: hidden;
position: relative;
}
<!--float: left同行顯示-->
.box{
float: left;
padding: 5px;
}
<!--圖片等寬-->
.box-img{
width: 150px;
padding: 5px;
border: 1px solid #484848;
box-shadow: 0 0 5px #484848;
}
<!--圖片占滿父容器-->
.box-img img{
width: 100%;
}
</style>
<body>
<div id="container">
<div class="box">
<div class="box-img">
<img src="./img/1.jpg" alt="">
</div>
</div>
/*.......后面接39個box,此處省略*/
</div>
</body>
</html>
js
1、首先用window.οnlοad=function(){}來實現(xiàn)頁面加載完畢后立即執(zhí)行的功能
調(diào)用imgLocation('container','box')函數(shù)來呈現(xiàn)最終效果,
傳入的實參是父容器'container',裝圖片的子容器'box'。
window.onload=function() {
imgLocation('container','box')
}
2、實現(xiàn)imgLocation()函數(shù)功能
1)首先我們得?獲取所有要擺放的圖片
,并將其存入一個數(shù)組
中
function imgLocation(parent,content){
//得到父容器
var cparent=document.getElementById(parent)
//cparent下的所有的第一層的子容器 box
var ccontent=getChildElement(cparent,content)//數(shù)組,40個div
}
//取到父容器中的某一層子容器
function getChildElement(parent,content){
var contentArr=[]
var allContent=parent.getElementsByTagName('*')//通過標(biāo)簽來選中得到一個數(shù)組
//遍歷allContent把其中類名為content的容器都存到contentArr數(shù)組中
for(var i=0;i<allContent.length;i++){
if(allContent[i].className==content){ //當(dāng)前這個容器的類名是否為content
contentArr.push(allContent[i])
}
}
return contentArr;
}
2)得到這個數(shù)組
后,找出從誰開始
是需要被擺放
位置的
首先獲取視窗的寬度和每張圖片的寬度,
將兩者相除并向下取整可得到第一行可以放置圖片的數(shù)量,
自然也就知道了我們需要操作的那張圖片的序號。
//從誰開始是需要被擺放位置的
var winWidth=document.documentElement.clientWidth;//視窗寬度
var imgWidth=ccontent[0].offsetWidth;//圖片寬度
var num=Math.floor(winWidth/imgWidth)//第一行能放幾張圖
3)得到需要被擺放
位置的圖片序號后,確定其擺放位置
定義一個存儲高度的數(shù)組,對前一行元素的高度進行遍歷并存入數(shù)組,
當(dāng)遍歷到需要被擺放位置的圖片時,
用Math.min()方法獲取前一行高度最矮的元素高度,并用indexOf()方法獲取到其下標(biāo)。
再對我們所操作的這個圖片容器的樣式調(diào)整:
position:absolute;絕對定位,
top值設(shè)置為前一行高度最矮的圖片高度minHeight,
left值設(shè)置為單張圖片寬度乘這張圖片的下標(biāo)minIndex。
最后,擺放好圖片后,還要更新擺放的那一列的高度
//操作num+1張圖
var BoxHeightArr=[]
for(var i=0;i<ccontent.length;i++){
//前num張只要計算高度
if(i<num){
BoxHeightArr[i]=ccontent[i].offsetHeight
}
else{
//我們要操作的box :ccontent[i]
var minHeight=Math.min.apply(null,BoxHeightArr)//apply:把最小值這個方法借給它用
var minIndex=BoxHeightArr.indexOf(minHeight)//返回數(shù)組下標(biāo)
ccontent[i].style.position='absolute'//style設(shè)置樣式
ccontent[i].style.top=minHeight+'px'
ccontent[i].style.left=imgWidth*minIndex+'px'
//更新最矮的那一列的高度
BoxHeightArr[minIndex]+=ccontent[i].offsetHeight
}
}
共性
問項目中有哪些難點,怎么解決的
代碼遇到?jīng)_突怎么辦
業(yè)務(wù)系統(tǒng)的搭建過程
復(fù)盤過程
拆分組件
復(fù)用和業(yè)務(wù)邏輯拆分
如何實現(xiàn)自適應(yīng)頁面
說到媒體查詢和多個樣式表
React如何實現(xiàn)動畫的(數(shù)字不斷變大的動畫)
最后是用庫實現(xiàn)的
*個性
介紹
打卡考勤項目
實現(xiàn)功能
后端接口
- Navicat創(chuàng)建數(shù)據(jù)庫和空表
- 加載MySQL等模塊
- 創(chuàng)建MySQL連接池(設(shè)置服務(wù)器地址host,服務(wù)器端口號port) 和 服務(wù)器對象server
- 3306是MySQL的默認(rèn)端口
- 默認(rèn)的服務(wù)端口就是8080。
- 跨源資源共享CORS
-
Origin
字段用來說名本次請求來自哪個源,服務(wù)器根據(jù)這個值,決定是否同意這次請求。如果
Origin
指定的源不在允許范圍之內(nèi),服務(wù)器就會返回一個正常的HTTP
回應(yīng),然后瀏覽器發(fā)現(xiàn)頭信息中沒有包含Access-Control-Allow-Origin
字段,就知道出錯啦,然后拋出錯誤
// 加載Express模塊
const express = require('express');
// 加載MySQL模塊
const mysql = require('mysql');
...
// 創(chuàng)建MySQL連接池
const pool = mysql.createPool({
host: '127.0.0.1', //MySQL服務(wù)器地址
port: 3306, //MySQL服務(wù)器端口號
user: 'root', //數(shù)據(jù)庫用戶的用戶名
password: '', //數(shù)據(jù)庫用戶密碼
database: 'reg_log', //數(shù)據(jù)庫名稱
connectionLimit: 20, //最大連接數(shù)
charset: 'utf8' //數(shù)據(jù)庫服務(wù)器的編碼方式
});
// 創(chuàng)建服務(wù)器對象
const server = express();
// 加載CORS模塊
const cors = require('cors');
// 使用CORS中間件
server.use(cors({
origin: ['http://localhost:8080', 'http://127.0.0.1:8080']
}));
登陸注冊
*0.0.0.0,localhost,127.0.0.1
網(wǎng)絡(luò)需求 | 數(shù)據(jù)傳輸 | 訪問 | 性質(zhì) | |
---|---|---|---|---|
localhost | 不聯(lián)網(wǎng) | 不使用網(wǎng)卡,不受防火墻和網(wǎng)卡限制 | 本機訪問 | 域名,默認(rèn)是指向?127.0.0.1
|
127.0.0.1 | 不聯(lián)網(wǎng) | 網(wǎng)卡傳輸,受防火墻和網(wǎng)卡限制 | 本機訪問 | 環(huán)回地址 |
本機IP | 聯(lián)網(wǎng) | 網(wǎng)卡傳輸 ,受防火墻和網(wǎng)卡限制 | 本機or外部訪問 | 本機對外放開訪問的 IP 地址 |
0.0.0.0
- 在服務(wù)器中:0.0.0.0表示本機上的任意ip地址,
- 在路由中:0.0.0.0表示的是默認(rèn)路由,即當(dāng)路由表中沒有找到完全匹配的路由的時候所對應(yīng)的路由。表示”任意IPV4主機”。
- 當(dāng)一臺主機還沒有被分配一個IP地址的時候,用于表示主機本身。
localhost
localhost是個域名,而不是一個ip地址??尚薷?。
用于指代 this computer 或者 this host,可以用它來獲取運行在本機上的網(wǎng)絡(luò)服務(wù)。
在大多數(shù)系統(tǒng)中,localhost被指向了 IPV4 的 127.0.0.1 和 IPV6 的 ::1,這就是把localhost與127.0.0.1等同的原因。
127.0.0.1
本機地址,主要用于測試
(127.x.x.x)是本機回送地址(Loopback Address),即主機IP堆棧內(nèi)部的IP地址,主要用于網(wǎng)絡(luò)軟件測試以及本地機進程間通信,無論什么程序,一旦使用回送地址發(fā)送數(shù)據(jù),協(xié)議軟件立即返回,不進行任何網(wǎng)絡(luò)傳輸。
示例都使用端口3000作為HTTP服務(wù)器的默認(rèn)監(jiān)聽端口。
3000 是整數(shù)。 0 ~ 1023 (常用端口)49152 ~ 65535 號端口是動態(tài)端口
//用戶注冊接口
server.post('/register', (req, res) => {
//console.log(md5('12345678'));
// 獲取用戶名和密碼信息
let username = req.body.username;
let password = req.body.password;
//以username為條件進行查找操作,以保證用戶名的唯一性
let sql = 'SELECT COUNT(id) AS count FROM reg_log WHERE username=?';
pool.query(sql, [username], (error, results) => {
if (error) throw error;
let count = results[0].count;
if (count == 0) {
// 將用戶的相關(guān)信息插入到數(shù)據(jù)表
sql = 'INSERT reg_log(username,password) VALUES(?,MD5(?))';
pool.query(sql, [username, password], (error, results) => {
if (error) throw error;
res.send({
message: 'ok',
code: 200
});
})
} else {
res.send({
message: 'user exists',
code: 201
});
}
});
});
// 用戶登錄接口
server.post('/login', (req, res) => {
//獲取用戶名和密碼信息
let username = req.body.username;
let password = req.body.password;
// SQL語句
let sql = 'SELECT id,username FROM reg_log WHERE username=? AND password=MD5(?)';
pool.query(sql, [username, password], (error, results) => {
if (error) throw error;
if (results.length == 0) { //登錄失敗
res.send({
message: 'login failed',
code: 201
});
} else { //登錄成功
res.send({
message: 'ok',
code: 200,
result: results[0]
});
}
});
// 指定服務(wù)器對象監(jiān)聽的端口號
server.listen(3000, () => {
console.log('server is running...');
})
注冊頁,使用token,能避免CSRF攻擊Cross-site request forgery。JSON Web Token(JWT)
?//注冊
checkForm() {
// 點擊注冊按鈕后調(diào)用此方法,驗證用戶名、密碼、二次密碼是否均正確,正確則發(fā)送axios請求
if (this.checkName() && this.checkPwd() && this.checkrePwd()) {
console.log(`驗證成功,執(zhí)行注冊業(yè)務(wù)......`);
// 發(fā)送注冊(post)請求
this.axios
.post("/register", `username=${this.name}&password=${this.pwd}`)
.then((result) => {
console.log(result);
if (result.data.code == 200) {
// 彈窗提示注冊成功
...
// 注冊成功后直接跳轉(zhuǎn)到登錄頁
this.$router.push("/login");
} else if (result.data.code == 201) {
...
}
});
}
//登陸
checkForm() {
// 點擊登錄按鈕后調(diào)用此方法,同時驗證用戶名和密碼
if (this.checkName() && this.checkPwd()) {
// 發(fā)送登錄(post)請求
this.axios
.post("/login", `username=${this.name}&password=${this.pwd}`)
.then((result) => {
console.log(result);
if (result.data.code == 200) {
// 彈窗提示登錄成功
this.$toast({
message: `歡迎您 ${this.name}`,
position: "bottom",
duration: 3000,
});
...
} else {
this.$toast({
message: "登錄失敗,請檢查您的用戶名和密碼",
position: "bottom",
duration: 3000,
});
}
});
}
分頁
currentPage(當(dāng)前頁碼)、total(總條數(shù))、pageSize(每頁展示的數(shù)據(jù)量)
把所有的數(shù)據(jù)請求回后,通過arr.slice(開始索引,結(jié)束索引)來進行截取每一頁的數(shù)據(jù);
假設(shè)當(dāng)前頁是currentPage = 1,pageSize = 5,那么應(yīng)該從(currentPage-1)*pageSize開始截取,到currentPage*pageSize結(jié)束
彈窗組件modal
.modal {
display: none; /* 默認(rèn)隱藏 */
position: fixed; /* 固定定位 */
z-index: 1; /* 設(shè)置在頂層 */
...
overflow: auto;
}
// 點擊按鈕打開彈窗
btn.onclick = function() {
modal.style.display = "block";
}
如何實現(xiàn)點擊彈窗外面區(qū)域,彈窗消失
事件委托,往上遍歷target的父元素如果有彈窗的id就不做反應(yīng),如果沒有就觸發(fā)消失文章來源:http://www.zghlxwxcb.cn/news/detail-425586.html
相關(guān)技術(shù)
主要目的是為了鞏固基礎(chǔ)知識,和適應(yīng)大型項目的需求文章來源地址http://www.zghlxwxcb.cn/news/detail-425586.html
- 框架,選擇了React,說說其不同....,Router,Redux基本使用
- 保持TS限定類型的習(xí)慣,減少報錯,說下區(qū)別和原因及其常用,
- 使用懶加載,組件庫按需加載,優(yōu)化性能,
- 使用ant-design做ui,學(xué)會利用API,省去設(shè)計樣式的時間,實現(xiàn)樣式和行為分離
- webpack打包
到了這里,關(guān)于2023年高頻前端面試項目考點(npm,git,webpack,TS4,sass,瀑布流,懶加載)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!