??此賬號為華為云開發者社區官方運營賬號,提供全面深入的云計算前景分析、豐富的技術干貨、程序樣例,分享華為云前沿資訊動態
本文分享自華為云社區《學習VueRouter,HTML5 History 模式,因為history模式刷新頁面會出現404》,作者: DevFeng 。
vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,于是當 URL 改變時,頁面不會重新加載。
如果不想要很丑的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。
const router = new VueRouter({
mode: 'history',
routes: [...]
})
當你使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!
不過這種模式要玩好,還需要后臺配置支持。因為我們的應用是個單頁客戶端應用,如果后臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。
所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。
注意:下列示例假設你在根目錄服務這個應用。如果想部署到一個子目錄,你需要使用 VueCLI 的
publicPath 選項 (opens new window)和相關的 router base property (opens new window)。你還需要把下列示例中的根目錄調整成為子目錄 (例如用 RewriteBase /name-of-your-subfolder/ 替換掉 RewriteBase/)。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
除了 mod_rewrite,你也可以使用 FallbackResource (opens new window)。
location / {
try_files $uri $uri/ /index.html;
}
const http = require('http')
const fs = require('fs')
const httpPort = 80
http.createServer((req, res) => {
fs.readFile('index.html', 'utf-8', (err, content) => {
if (err) {
console.log('We cannot open "index.html" file.')
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})
對于Node.js/Express,請考慮使用 connect-history-api-fallback 中間件 (opens new window)。
1. 安裝 IIS UrlRewrite(opens new window)
2. 在你的網站根目錄中創建一個 web.config 文件,內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
rewrite {
regexp .*
to {path} /
}
在你的 firebase.json 中加入:
{
"hosting": {
"public": "dist",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
給個警告,因為這么做以后,你的服務器就不再返回 404 錯誤頁面,因為對于所有路徑都會返回
index.html 文件。為了避免這種情況,你應該在 Vue 應用里面覆蓋所有的路由情況,然后再給出一個 404 頁面。
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
或者,如果你使用 Node.js 服務器,你可以用服務端路由匹配到來的 URL,并在沒有匹配到路由的時候返回 404,以實現回退。
點擊關注,第一時間了解華為云新鮮技術~華為云博客_大數據博客_AI博客_云計算博客_開發者中心-華為云
、良生- input type=file與文件上傳
本文所說的input type=file指的是type類型是file的input元素,最簡HTML代碼如下:
<input type=file>
但是,為了習慣,我們多寫成:
<input type="file">
在HTML5出現之前(XHTML),我們的閉合規則則有些出入:
<input type="file" />
顧名思義,選擇文件,并上傳文件。
在萬惡的舊時代,HTML5還沒有出現之前,原生的file input表單元素只能讓我們一次上傳一張圖片。無法滿足一次上傳多圖的交互需求,所以,很多場景,就被swfupload.js給取代了,有點逐漸淡出人們視野的感覺。
然,技術發展,日新月異,三十年河東,三十年河西。隨著原生HTML5表單對多圖(multiple屬性)、上傳前預覽,二進制上傳等支持越來越廣泛,原生的file input表單元素又迎來了新的升級,flash為背景的swfupload.js注定要落寞。
但是,對于PC項目,IE8-IE9瀏覽器還是不能忽略的。所以,現在,很流行的一種處理方式,就是HTML5 file上傳和flash swfupload上傳一起整合的模式,優先使用原生HTML5上傳,不支持的,使用flash上傳。我之前有篇關于HTML5上傳的文章,每天訪問量很高的:“基于HTML5的可預覽多圖片Ajax上傳”,大家有興趣可以看看。
如果想使用瀏覽器原生特性實現文件上傳(如圖片)效果,父級的form元素有個東西不能丟,就是:
enctype="multipart/form-data"
enctype屬性規定在發送到服務器之前應該如何對表單數據進行編碼,默認的編碼是:”application/x-www-form-urlencoded“。對于普通數據是挺適用的,但是,對于文件,科科,就不能亂編碼了,該什么就是什么,只能使用multipart/form-data作為enctype屬性值。
無論是舊時代的單圖上傳,還是HTML5中的多圖上傳,均是如此。
文件,尤其圖片,上場前能夠預覽,是很棒的交互體驗。不走服務器,不耗費流量,多棒!
理想雖好,實現起來……
在HTML5還沒出現的舊時代,只有低版本的IE瀏覽器貌似有方法,使用私有的濾鏡,超越安全的限制(其實是利用了不好的東西),實現圖片直接預覽;但是呢,那個時候,Chrome, FireFox沒有這一出,于是,想要使用原生file input實現圖片的上傳前預覽,兼容性坎很難跨過去。
但是,后來,HTML5來了,我們出現了轉機,IE10+以及其他現代瀏覽器,可以讓我們直接讀取圖片的數據,然后在頁面上呈現,實現了上傳前預覽;加上之前老IE的濾鏡策略,貌似,可行。但是呢但是,老的IE瀏覽器只能最多一次選擇一個文件,因此,只有單圖上傳的時候,大家可以考慮考慮。
傳統的form提交,是要改變頁面流的,也就是刷新后跳轉。好的體驗應該是走Ajax交互的。HTML5里面支持二進制formData數據提交,因此,可以從容Ajax提交上傳的文件數據;那老舊的IE瀏覽器怎么辦?
一般方法如下:
<form action="" method="post" enctype="multipart/form-data" target="uploadIframe">< <iframe id="uploadIframe"></iframe>
var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document; var response = doc.body && doc.body.innerHTML;
OK, 當然,你也可以不用像上面這么麻煩,直接使用jquery.form.js. 原理呢,就是上面這樣,但是,不需要這么麻煩。
原生的file input不收待見的另外一個原因是:長的丑還不好控制。
舉個例子,下圖這個“選擇文件”這幾個文字,我們就不好對file控件動刀子實現自定義:
file input框
怎么辦呢?
有一種方法是這樣的: 讓file類型的元素透明度0,覆蓋在我們好看的按鈕上。然后我們去點擊好看的按鈕,實際上點擊是是file元素。
然而,此方法有一些不足:
更好的方法是,使用label元素與file控件關聯,好處在于:
<label class="ui_button ui_button_primary" for="xFile">上傳文件</label> <form><input type="file" id="xFile" style="position:absolute;clip:rect(0 0 0 0);"></form>
效果如下(真實實時效果):
input file類型控件有一個屬性,名為
accept
, 可能有些小伙伴不太了解。可以用來指定瀏覽器接受的文件類型,也就是的那個我們打開系統的選擇文件彈框的時候,默認界面中呈現的文件類型。例如:
accept="image/jpeg"
,則界面中只有jpg圖片,如下截圖,同時,窗體右下方是“自定義文件”按鈕:
自定義文件
實際開發的時候,很少只允許傳jpg圖片,應該都是只能傳圖片類型,此時,可以使用:
accept="image/*"
于是乎,“自定義文件”按鈕變成了語義更明確的“圖片文件”:
圖片文件
accept屬性值其實是MIME類型, 例如下面幾個可能常用的:
accept="application/pdf" accept="audio/x-mpeg" accept="text/html" .accept="video/x-mpeg2"
然后,多個屬性值使用逗號分隔,例如:
<input accept="audio/*,video/*,image/*">
現代瀏覽器直接value = "", 有些IE瀏覽器貌似不行,好像使用file.outerHTML = file.outerHTML,我自己沒測試。
不過我覺得比較麻煩,還要判斷瀏覽器什么的。像本文的Ajax單圖上傳,直接form.reset()就可以了。
以上~
本文為原創文章,會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
下面試題不分先后順序
八股文不想寫了自己百度吧...
Hash模式
1、定義
hash 模式是一種把前端路由的路徑用井號 # 拼接在真實 url 后面的模式。當井號 # 后面的路徑發生變化時,瀏覽器并不會重新發起請求,而是會觸發 onhashchange 事件。
2、網頁url組成部分
(1)了解幾個url的屬性
屬性 | 含義 |
location.protocal | 協議 |
location.hostname | 主機名 |
location.host | 主機 |
location.port | 端口號 |
location.patchname | 訪問頁面 |
location.search | 搜索內容 |
location.hash | 哈希值 |
(2)演示
下面用一個網址來演示以上屬性:
History模式
hash的特點
1、定義
history API 是 H5 提供的新特性,允許開發者直接更改前端路由,即更新瀏覽器 URL 地址而不重新發起請求。
2、與hash的區別
我們用一個例子來演示, hash 與 history 在瀏覽器下刷新時的區別。具體如下:
正常頁面瀏覽
改造H5 history模式
3、history的API
下面闡述幾種 HTML5 新增的 history API 。具體如下表:
API | 定義 |
history.pushState(data, title [, url]) | pushState主要用于往歷史記錄堆棧頂部添加一條記錄。各參數解析如下:①data會在onpopstate事件觸發時作為參數傳遞過去;②title為頁面標題,當前所有瀏覽器都會忽略此參數;③url為頁面地址,可選,缺少時表示為當前頁地址 |
history.replaceState(data, title [, url]) | 更改當前的歷史記錄,參數同上; 上面的pushState是添加,這個更改 |
history.state | 用于存儲以上方法的data數據,不同瀏覽器的讀寫權限不一樣 |
window.onpopstate | 響應pushState或者replaceState的調用 |
4、history的特點
對于 history 來說,主要有以下特點:
5、存在問題
對于 history 來說,確實解決了不少 hash 存在的問題,但是也帶來了新的問題。
具體如下:
6、兩者選擇
下面我們再來介紹下在實際的項目中,如何對這兩者進行選擇。具體如下:
淺拷貝與深拷貝
借助ConardLi大佬以下兩張圖片,幫我們更好的理解兩者的含義:
總而言之,淺拷貝只復制指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存。但深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。
var person = new Person()
console.log(person.constructor === Person) // true
當獲取person.constructor時,其實person中并沒有constructor屬性,當不能讀取到constructor屬性時,會從person的原型,也就是Person.prototype中讀取時,正好原型中有該屬性,所以 person.constructor === Person.prototype.constructor
其次是__proto__,絕大部分瀏覽器都支持這個非標準的方法訪問原型,然而它并不存在于Person.prototype中。
實際上,它是來自與Object.prototype,與其說是一個屬性,不如說是一個getter/setter,當使用obj.__proto__時,可以理解成返回了Object.getPrototypeOf(obj) 。
總結:
如果沒有參數,就直接寫一個空括號即可
如果只有一個參數,可以省去參數括號
如果有多個參數,用逗號分割
如果函數體的返回值只有一句,可以省略大括號
如果函數體不需要返回值,且只有一句話,可以給這個語句前面加一個void關鍵字。
最常用的就是調用一個函數:
let fn = () => void doesNotReturn()
箭頭函數不會創建自己的this,所以它沒有自己的this,它只會在自己作用域的上一層繼承this。所以箭頭函數中的this的指向在它在定義時一家確定了,之后不會改變。
戳右邊鏈接:https://segmentfault.com/a/1190000016278115
當一個內部函數被調用,就會形成閉包,閉包就是能夠讀取其他函數內部變量的函數。
閉包作用:
局部變量無法共享和長久的保存,而全局變量可能造成變量污染,所以我們希望有一種機制既可以長久的保存變量又不會造成全局污染。
Promise 是異步編程的一種解決方案:從語法上講,promise是一個對象,從它可以獲取異步操作的消息;從本意上講,它是承諾,承諾它過一段時間會給你一個結果。promise有三種狀態: pending(等待態),fulfiled(成功態),rejected(失敗態) ;狀態一旦改變,就不會再變。創造promise實例后,它會立即執行。
foreach()方法會針對每一個元素執行提供得函數,該方法沒有返回值,是否會改變原數組取決與數組元素的類型是基本類型還是引用類型
map()方法不會改變原數組的值,返回一個新數組,新數組中的值為原數組調用函數處理之后的值
localStorage:以鍵值對的方式存儲 儲存時間沒有限制 永久生效 除非自己刪除記錄
sessionStorage:當頁面關閉后被清理與其他相比不能同源窗口共享 是會話級別的存儲方式
cookies數據不能超過4k 同時因為每次http請求都會攜帶cookie 所有cookie只適合保存很小的數據 如會話標識
有五種,分別是 State、 Getter、Mutation 、Action、 Module
Loader:直譯為"加載器"。Webpack將一切文件視為模塊,但是webpack原生是只能解析js文件,如果想將其他文件也打包的話,就會用到`loader`。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
Plugin:直譯為"插件"。Plugin可以擴展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
太多了,自己整理吧-.-
區別:
computed 計算屬性:依賴其它屬性值,并且computed的值有緩存,只有它依賴的屬性值發生改變,下一次獲取computed的值時才會重新計算computed的值。
watch 偵聽器:更多的是觀察的作用,無緩存性,類似與某些數據的監聽回調,每當監聽的數據變化時都會執行回調進行后續操作
運用場景:
當需要進行數值計算,并且依賴與其它數據時,應該使用computed,因為可以利用computed的緩存屬性,避免每次獲取值時都要重新計算。
當需要在數據變化時執行異步或開銷較大的操作時,應該使用watch,使用watch選項允許執行異步操作(訪問一個API),限制執行該操作的頻率,并在得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。
Vue 實例有?個完整的?命周期,也就是從開始創建、初始化數據、編譯模版、掛載Dom -> 渲染、更新 -> 渲染、卸載等?系列過程,稱這是Vue的?命周期。
//利用絕對定位,先將元素的左上角通過 top:50%和 left:50%定位到頁面的中心,然后再通過 translate 來調整元素的中心點到頁面的中心。該方法需要考慮瀏覽器兼容問題。
//利用絕對定位,設置四個方向的值都為 0,并將 margin 設置為 auto,由于寬高固定,因此對應方向實現平分,可以實現水平和垂直方向上的居中。該方法適用于盒子有寬高的情況:
//利用絕對定位,先將元素的左上角通過 top:50%和 left:50%定位到頁面的中心,然后再通過 margin 負值來調整元素的中心點到頁面的中心。該方法適用于盒子寬高已知的情況
//使用 flex 布局,通過 align-items:center 和 justify-content:center 設置容器的垂直和水平方向上為居中對齊,然后它的子元素也可以實現垂直和水平的居中。該方法要**考慮兼容的問題**,該方法在移動端用的較多:
//另外,如果父元素設置了flex布局,只需要給子元素加上`margin:auto;`就可以實現垂直居中布局
戳右邊鏈接:https://blog.csdn.net/qq_29438877/article/details/103998284
JavaScript中的對象是引用類型的數據,當多個實例引用同一個對象時,只要一個實例對這個對象進行操作,其他實例中的數據也會發生變化。而在Vue中,我們更多的是想要復用組件,那就需要每個組件都有自己的數據,這樣組件之間才不會相互干擾。所以組件的數據不能寫成對象的形式,而是要寫成函數的形式。數據以函數返回值的形式定義,這樣當我們每次復用組件的時候,就會返回一個新的data,也就是說每個組件都有自己的私有數據空間,它們各自維護自己的數據,不會干擾其他組件的正常運行。
1.如果obj里面有時間對象,則JSON.stringify后再JSON.parse的結果,時間將只是字符串的形式,而不是對象的形式
2.如果obj里有RegExp(正則表達式的縮寫)、Error對象,則序列化的結果將只得到空對象
3、如果obj里有函數,undefined,則序列化的結果會把函數或 undefined丟失
4、如果obj里有NaN、Infinity和-Infinity,則序列化的結果會變成null
5、JSON.stringify()只能序列化對象的可枚舉的自有屬性,例如 如果obj中的對象是有構造函數生成的, 則使用JSON.parse(JSON.stringify(obj))深拷貝后,會丟棄對象的constructor
6、如果對象中存在循環引用的情況也無法正確實現深拷貝
總結:for...in循環主要是為了遍歷對象而生,不適用遍歷數組; for....of循環可以用來遍歷數組、類數組對象、字符串、Set、Map以及Generator對象
1. 語法上的區別:
函數式組件是一個純函數,它是需要接受props參數并且返回一個React元素就可以了。類組件是需要繼承React.Component的,而且class組件需要創建render并且返回React元素,語法上來講更復雜。
2. 調用方式
函數式組件可以直接調用,返回一個新的React元素;類組件在調用時是需要創建一個實例的,然后通過調用實例里的render方法來返回一個React元素。
3. 狀態管理
函數式組件沒有狀態管理,類組件有狀態管理。
4. 使用場景
類組件沒有具體的要求。函數式組件一般是用在大型項目中來分割大組件(函數式組件不用創建實例,所有更高效),一般情況下能用函數式組件就不用類組件,提升效率。
答案戳這里:zhuanlan.zhihu.com/p/35801438
初次登錄的時候,前端調后調的登錄接口,發送用戶名和密碼,后端收到請求,驗證用戶名和密碼,驗證成功,就給前端返回一個token,和一個用戶信息的值,前端拿到token,將token儲存到Vuex中,然后從Vuex中把token的值存入瀏覽器Cookies中。
把用戶信息存到Vuex然后再存儲到LocalStroage中,然后跳轉到下一個頁面,根據后端接口的要求,只要不登錄就不能訪問的頁面需要在前端每次跳轉頁面師判斷Cookies中是否有token,沒有就跳轉到登錄頁,有就跳轉到相應的頁面,我們應該再每次發送post/get請求的時候應該加入token,常用方法再項目utils/service.js中添加全局攔截器,將token的值放入請求頭中 后端判斷請求頭中有無token,有token,就拿到token并驗證token是否過期,在這里過期會返回無效的token然后有個跳回登錄頁面重新登錄并且清除本地用戶的信息
答案戳這里:https://blog.csdn.net/weixin_40599109/article/details/113728974
vue中購物車邏輯的實現
js中購物車邏輯的實現
**展示購物車中的商品******
**完成購物車中商品的購買******
備注1:購物車中商品存儲的數據除了“商品id”、“商品數量”之外,根據產品要求還可以有其他的信息,例如完整的商品詳情(這樣就不用掉服務器接口獲得詳情了)、購物車商品的過期時間,超過時間的購物車商品在下次打開網站或者購物車頁面時被清除。
備注2:購物車商品除了存儲在localStorage中,根據產品的需求不同,也可以存儲在sessionStorage、cookie、session中,或者直接向服務器接口發起請求存儲在服務器上。何種情況使用哪種方式存儲、有啥區別請自己分析。
<!-- 狀態碼:由3位數字組成,第一個數字定義了響應的類別 -->
<!-- 1xx:指示消息,表示請求已接收,繼續處理 -->
<!-- 2xx:成功,表示請求已被成功接收,處理 -->
<!-- 200 OK:客戶端請求成功
204 No Content:無內容。服務器成功處理,但未返回內容。一般用在只是客戶端向服務器發送信息,而服務器不用向客戶端返回什么信息的情況。不會刷新頁面。
206 Partial Content:服務器已經完成了部分GET請求(客戶端進行了范圍請求)。響應報文中包含Content-Range指定范圍的實體內容 -->
<!-- 3xx 重定向 -->
<!-- 301 Moved Permanently:永久重定向,表示請求的資源已經永久的搬到了其他位置。
302 Found:臨時重定向,表示請求的資源臨時搬到了其他位置
303 See Other:臨時重定向,應使用GET定向獲取請求資源。303功能與302一樣,區別只是303明確客戶端應該使用GET訪問
307 Temporary Redirect:臨時重定向,和302有著相同含義。POST不會變成GET
304 Not Modified:表示客戶端發送附帶條件的請求(GET方法請求報文中的IF…)時,條件不滿足。返回304時,不包含任何響應主體。雖然304被劃分在3XX,但和重定向一毛錢關系都沒有 -->
<!-- 4xx:客戶端錯誤 -->
<!-- 400 Bad Request:客戶端請求有語法錯誤,服務器無法理解。
401 Unauthorized:請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用。
403 Forbidden:服務器收到請求,但是拒絕提供服務
404 Not Found:請求資源不存在。比如,輸入了錯誤的url
415 Unsupported media type:不支持的媒體類型 -->
<!-- 5xx:服務器端錯誤,服務器未能實現合法的請求。 -->
<!-- 500 Internal Server Error:服務器發生不可預期的錯誤。
503 Server Unavailable:服務器當前不能處理客戶端的請求,一段時間后可能恢復正常, -->
我是cv的各位自取吧-。-
原文鏈接:https://juejin.cn/post/7073869980411887652
*請認真填寫需求信息,我們會在24小時內與您取得聯系。