從vue-router看前端路由的兩種實(shí)現(xiàn)
隨著前端應(yīng)用的業(yè)務(wù)功能越來(lái)越復(fù)雜、用戶(hù)對(duì)于使用體驗(yàn)的要求越來(lái)越高,單頁(yè)應(yīng)用(SPA)成為前端應(yīng)用的主流形式。大型單頁(yè)應(yīng)用最顯著特點(diǎn)之一就是采用前端路由系統(tǒng),通過(guò)改變URL,在不重新請(qǐng)求頁(yè)面的情況下,更新頁(yè)面視圖。
“更新視圖但不重新請(qǐng)求頁(yè)面”是前端路由原理的核心之一,目前在瀏覽器環(huán)境中這一功能的實(shí)現(xiàn)主要有兩種方式:
- 利用URL中的hash(“#”)
- 利用History interface在 HTML5中新增的方法
vue-router是Vue.js框架的路由插件,下面我們從它的源碼入手,邊看代碼邊看原理,由淺入深觀摩vue-router是如何通過(guò)這兩種方式實(shí)現(xiàn)前端路由的。
模式參數(shù)
在vue-router中是通過(guò)mode這一參數(shù)控制路由的實(shí)現(xiàn)模式的:
const router = new VueRouter({ mode: 'history', routes: [...] })
創(chuàng)建VueRouter的實(shí)例對(duì)象時(shí),mode以構(gòu)造函數(shù)參數(shù)的形式傳入。帶著問(wèn)題閱讀源碼,我們就可以從VueRouter類(lèi)的定義入手。一般插件對(duì)外暴露的類(lèi)都是定義在源碼src根目錄下的index.js文件中,打開(kāi)該文件,可以看到VueRouter類(lèi)的定義,摘錄與mode參數(shù)有關(guān)的部分如下:
export default class VueRouter { mode: string; // 傳入的字符串參數(shù),指示history類(lèi)別 history: HashHistory | HTML5History | AbstractHistory; // 實(shí)際起作用的對(duì)象屬性,必須是以上三個(gè)類(lèi)的枚舉 fallback: boolean; // 如瀏覽器不支持,'history'模式需回滾為'hash'模式 constructor (options: RouterOptions = {}) { let mode = options.mode || 'hash' // 默認(rèn)為'hash'模式 this.fallback = mode === 'history' && !supportsPushState // 通過(guò)supportsPushState判斷瀏覽器是否支持'history'模式 if (this.fallback) { mode = 'hash' } if (!inBrowser) { mode = 'abstract' // 不在瀏覽器環(huán)境下運(yùn)行需強(qiáng)制為'abstract'模式 } this.mode = mode // 根據(jù)mode確定history實(shí)際的類(lèi)并實(shí)例化 switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${mode}`) } } } init (app: any /* Vue component instance */) { const history = this.history // 根據(jù)history的類(lèi)別執(zhí)行相應(yīng)的初始化操作和監(jiān)聽(tīng) if (history instanceof HTML5History) { history.transitionTo(history.getCurrentLocation()) } else if (history instanceof HashHistory) { const setupHashListener = () => { history.setupListeners() } history.transitionTo( history.getCurrentLocation(), setupHashListener, setupHashListener ) } history.listen(route => { this.apps.forEach((app) => { app._route = route }) }) } // VueRouter類(lèi)暴露的以下方法實(shí)際是調(diào)用具體history對(duì)象的方法 push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.push(location, onComplete, onAbort) } replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.replace(location, onComplete, onAbort) } }
可以看出:
作為參數(shù)傳入的字符串屬性mode只是一個(gè)標(biāo)記,用來(lái)指示實(shí)際起作用的對(duì)象屬性history的實(shí)現(xiàn)類(lèi),兩者對(duì)應(yīng)關(guān)系如下:
mode | history | hash | abstract |
---|---|---|---|
history | HTML5History | HashHistory | AbstractHistory |
在初始化對(duì)應(yīng)的history之前,會(huì)對(duì)mode做一些校驗(yàn):若瀏覽器不支持HTML5History方式(通過(guò)supportsPushState變量判斷),則mode強(qiáng)制設(shè)為'hash';若不是在瀏覽器環(huán)境下運(yùn)行,則mode強(qiáng)制設(shè)為'abstract'
VueRouter類(lèi)中的onReady(), push()等方法只是一個(gè)代理,實(shí)際是調(diào)用的具體history對(duì)象的對(duì)應(yīng)方法,在init()方法中初始化時(shí),也是根據(jù)history對(duì)象具體的類(lèi)別執(zhí)行不同操作
在瀏覽器環(huán)境下的兩種方式,分別就是在HTML5History,HashHistory兩個(gè)類(lèi)中實(shí)現(xiàn)的。他們都定義在src/history文件夾下,繼承自同目錄下base.js文件中定義的History類(lèi)。History中定義的是公用和基礎(chǔ)的方法,直接看會(huì)一頭霧水,我們先從HTML5History,HashHistory兩個(gè)類(lèi)中看著親切的push(), replace()方法的說(shuō)起。
HashHistory
看源碼前先回顧一下原理:
hash(“#”)符號(hào)的本來(lái)作用是加在URL中指示網(wǎng)頁(yè)中的位置:
#符號(hào)本身以及它后面的字符稱(chēng)之為hash,可通過(guò)window.location.hash屬性讀取。它具有如下特點(diǎn):
- hash雖然出現(xiàn)在URL中,但不會(huì)被包括在HTTP請(qǐng)求中。它是用來(lái)指導(dǎo)瀏覽器動(dòng)作的,對(duì)服務(wù)器端完全無(wú)用,因此,改變hash不會(huì)重新加載頁(yè)面
- 可以為hash的改變添加監(jiān)聽(tīng)事件:
window.addEventListener("hashchange", funcRef, false)
每一次改變hash(window.location.hash),都會(huì)在瀏覽器的訪(fǎng)問(wèn)歷史中增加一個(gè)記錄
利用hash的以上特點(diǎn),就可以來(lái)實(shí)現(xiàn)前端路由“更新視圖但不重新請(qǐng)求頁(yè)面”的功能了。
HashHistory.push()
我們來(lái)看HashHistory中的push()方法:
push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { pushHash(route.fullPath) onComplete && onComplete(route) }, onAbort) } function pushHash (path) { window.location.hash = path }
transitionTo()方法是父類(lèi)中定義的是用來(lái)處理路由變化中的基礎(chǔ)邏輯的,push()方法最主要的是對(duì)window的hash進(jìn)行了直接賦值:
window.location.hash = route.fullPath
hash的改變會(huì)自動(dòng)添加到瀏覽器的訪(fǎng)問(wèn)歷史記錄中。
那么視圖的更新是怎么實(shí)現(xiàn)的呢,我們來(lái)看父類(lèi)History中transitionTo()方法的這么一段:
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) ... }) } updateRoute (route: Route) { this.cb && this.cb(route) } listen (cb: Function) { this.cb = cb }
可以看到,當(dāng)路由變化時(shí),調(diào)用了History中的this.cb方法,而this.cb方法是通過(guò)History.listen(cb)進(jìn)行設(shè)置的?;氐絍ueRouter類(lèi)定義中,找到了在init()方法中對(duì)其進(jìn)行了設(shè)置:
init (app: any /* Vue component instance */) { this.apps.push(app) history.listen(route => { this.apps.forEach((app) => { app._route = route }) }) }
根據(jù)注釋?zhuān)琣pp為Vue組件實(shí)例,但我們知道Vue作為漸進(jìn)式的前端框架,本身的組件定義中應(yīng)該是沒(méi)有有關(guān)路由內(nèi)置屬性_route,如果組件中要有這個(gè)屬性,應(yīng)該是在插件加載的地方,即VueRouter的install()方法中混合入Vue對(duì)象的,查看install.js源碼,有如下一段:
export function install (Vue) { Vue.mixin({ beforeCreate () { if (isDef(this.$options.router)) { this._router = this.$options.router this._router.init(this) Vue.util.defineReactive(this, '_route', this._router.history.current) } registerInstance(this, this) }, }) }
通過(guò)Vue.mixin()方法,全局注冊(cè)一個(gè)混合,影響注冊(cè)之后所有創(chuàng)建的每個(gè) Vue 實(shí)例,該混合在beforeCreate鉤子中通過(guò)Vue.util.defineReactive()定義了響應(yīng)式的_route屬性。所謂響應(yīng)式屬性,即當(dāng)_route值改變時(shí),會(huì)自動(dòng)調(diào)用Vue實(shí)例的render()方法,更新視圖。
總結(jié)一下,從設(shè)置路由改變到視圖更新的流程如下:
$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()
HashHistory.replace()
replace()方法與push()方法不同之處在于,它并不是將新路由添加到瀏覽器訪(fǎng)問(wèn)歷史的棧頂,而是替換掉當(dāng)前的路由:
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { replaceHash(route.fullPath) onComplete && onComplete(route) }, onAbort) } function replaceHash (path) { const i = window.location.href.indexOf('#') window.location.replace( window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path ) }
可以看出,它與push()的實(shí)現(xiàn)結(jié)構(gòu)上基本相似,不同點(diǎn)在于它不是直接對(duì)window.location.hash進(jìn)行賦值,而是調(diào)用window.location.replace方法將路由進(jìn)行替換。
監(jiān)聽(tīng)地址欄
以上討論的VueRouter.push()和VueRouter.replace()是可以在vue組件的邏輯代碼中直接調(diào)用的,除此之外在瀏覽器中,用戶(hù)還可以直接在瀏覽器地址欄中輸入改變路由,因此VueRouter還需要能監(jiān)聽(tīng)瀏覽器地址欄中路由的變化,并具有與通過(guò)代碼調(diào)用相同的響應(yīng)行為。在HashHistory中這一功能通過(guò)setupListeners實(shí)現(xiàn):
setupListeners () { window.addEventListener('hashchange', () => { if (!ensureSlash()) { return } this.transitionTo(getHash(), route => { replaceHash(route.fullPath) }) }) }
該方法設(shè)置監(jiān)聽(tīng)了瀏覽器事件hashchange,調(diào)用的函數(shù)為replaceHash,即在瀏覽器地址欄中直接輸入路由相當(dāng)于代碼調(diào)用了replace()方法
HTML5History
History interface是瀏覽器歷史記錄棧提供的接口,通過(guò)back(), forward(), go()等方法,我們可以讀取瀏覽器歷史記錄棧的信息,進(jìn)行各種跳轉(zhuǎn)操作。
從HTML5開(kāi)始,History interface提供了兩個(gè)新的方法:pushState(), replaceState()使得我們可以對(duì)瀏覽器歷史記錄棧進(jìn)行修改:
window.history.pushState(stateObject, title, URL) window.history.replaceState(stateObject, title, URL)
- stateObject: 當(dāng)瀏覽器跳轉(zhuǎn)到新的狀態(tài)時(shí),將觸發(fā)popState事件,該事件將攜帶這個(gè)stateObject參數(shù)的副本
- title: 所添加記錄的標(biāo)題
- URL: 所添加記錄的URL
這兩個(gè)方法有個(gè)共同的特點(diǎn):當(dāng)調(diào)用他們修改瀏覽器歷史記錄棧后,雖然當(dāng)前URL改變了,但瀏覽器不會(huì)立即發(fā)送請(qǐng)求該URL(the browser won't attempt to load this URL after a call to pushState()),這就為單頁(yè)應(yīng)用前端路由“更新視圖但不重新請(qǐng)求頁(yè)面”提供了基礎(chǔ)。
我們來(lái)看vue-router中的源碼:
push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) } replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { replaceState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) } // src/util/push-state.js export function pushState (url?: string, replace?: boolean) { saveScrollPosition() // try...catch the pushState call to get around Safari // DOM Exception 18 where it limits to 100 pushState calls const history = window.history try { if (replace) { history.replaceState({ key: _key }, '', url) } else { _key = genKey() history.pushState({ key: _key }, '', url) } } catch (e) { window.location[replace ? 'replace' : 'assign'](url) } } export function replaceState (url?: string) { pushState(url, true) }
代碼結(jié)構(gòu)以及更新視圖的邏輯與hash模式基本類(lèi)似,只不過(guò)將對(duì)window.location.hash直接進(jìn)行賦值window.location.replace()改為了調(diào)用history.pushState()和history.replaceState()方法。
在HTML5History中添加對(duì)修改瀏覽器地址欄URL的監(jiān)聽(tīng)是直接在構(gòu)造函數(shù)中執(zhí)行的:
constructor (router: Router, base: ?string) { window.addEventListener('popstate', e => { const current = this.current this.transitionTo(getLocation(this.base), route => { if (expectScroll) { handleScroll(router, route, current, true) } }) }) }
當(dāng)然了HTML5History用到了HTML5的新特特性,是需要特定瀏覽器版本的支持的,前文已經(jīng)知道,瀏覽器是否支持是通過(guò)變量supportsPushState來(lái)檢查的:
// src/util/push-state.js export const supportsPushState = inBrowser && (function () { const ua = window.navigator.userAgent if ( (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) && ua.indexOf('Mobile Safari') !== -1 && ua.indexOf('Chrome') === -1 && ua.indexOf('Windows Phone') === -1 ) { return false } return window.history && 'pushState' in window.history })()
以上就是hash模式與history模式源碼的導(dǎo)讀,這兩種模式都是通過(guò)瀏覽器接口實(shí)現(xiàn)的,除此之外vue-router還為非瀏覽器環(huán)境準(zhǔn)備了一個(gè)abstract模式,其原理為用一個(gè)數(shù)組stack模擬出瀏覽器歷史記錄棧的功能。當(dāng)然,以上只是一些核心邏輯,為保證系統(tǒng)的魯棒性,源碼中還有大量的輔助邏輯,也很值得學(xué)習(xí)。此外在vue-router中還有路由匹配、router-view視圖組件等重要部分
兩種模式比較
在一般的需求場(chǎng)景中,hash模式與history模式是差不多的,但幾乎所有的文章都推薦使用history模式,理由竟然是:"#" 符號(hào)太丑...0_0 "
如果不想要很丑的 hash,我們可以用路由的 history 模式 ——官方文檔
當(dāng)然,嚴(yán)謹(jǐn)?shù)奈覀兛隙ú粦?yīng)該用顏值評(píng)價(jià)技術(shù)的好壞。根據(jù)MDN的介紹,調(diào)用history.pushState()相比于直接修改hash主要有以下優(yōu)勢(shì):
- pushState設(shè)置的新URL可以是與當(dāng)前URL同源的任意URL;而hash只可修改#后面的部分,故只可設(shè)置與當(dāng)前同文檔的URL
- pushState設(shè)置的新URL可以與當(dāng)前URL一模一樣,這樣也會(huì)把記錄添加到棧中;而hash設(shè)置的新值必須與原來(lái)不一樣才會(huì)觸發(fā)記錄添加到棧中
- pushState通過(guò)stateObject可以添加任意類(lèi)型的數(shù)據(jù)到記錄中;而hash只可添加短字符串
- pushState可額外設(shè)置title屬性供后續(xù)使用
history模式的一個(gè)問(wèn)題
我們知道對(duì)于單頁(yè)應(yīng)用來(lái)講,理想的使用場(chǎng)景是僅在進(jìn)入應(yīng)用時(shí)加載index.html,后續(xù)在的網(wǎng)絡(luò)操作通過(guò)Ajax完成,不會(huì)根據(jù)URL重新請(qǐng)求頁(yè)面,但是難免遇到特殊情況,比如用戶(hù)直接在地址欄中輸入并回車(chē),瀏覽器重啟重新加載應(yīng)用等。
hash模式僅改變hash部分的內(nèi)容,而hash部分是不會(huì)包含在HTTP請(qǐng)求中的:
http://oursite.com/#/user/id // 如重新請(qǐng)求只會(huì)發(fā)送http://oursite.com/
故在hash模式下遇到根據(jù)URL請(qǐng)求頁(yè)面的情況不會(huì)有問(wèn)題。
而history模式則會(huì)將URL修改得就和正常請(qǐng)求后端的URL一樣
http://oursite.com/user/id
在此情況下重新向后端發(fā)送請(qǐng)求,如后端沒(méi)有配置對(duì)應(yīng)/user/id的路由處理,則會(huì)返回404錯(cuò)誤。官方推薦的解決辦法是在服務(wù)端增加一個(gè)覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態(tài)資源,則應(yīng)該返回同一個(gè) index.html 頁(yè)面,這個(gè)頁(yè)面就是你 app 依賴(lài)的頁(yè)面。同時(shí)這么做以后,服務(wù)器就不再返回 404 錯(cuò)誤頁(yè)面,因?yàn)閷?duì)于所有路徑都會(huì)返回 index.html 文件。為了避免這種情況,在 Vue 應(yīng)用里面覆蓋所有的路由情況,然后在給出一個(gè) 404 頁(yè)面。或者,如果是用 Node.js 作后臺(tái),可以使用服務(wù)端的路由來(lái)匹配 URL,當(dāng)沒(méi)有匹配到路由的時(shí)候返回 404,從而實(shí)現(xiàn) fallback。
直接加載應(yīng)用文件
Tip: built files are meant to be served over an HTTP server.
Opening index.html over file:// won't work.
Vue項(xiàng)目通過(guò)vue-cli的webpack打包完成后,命令行會(huì)有這么一段提示。通常情況,無(wú)論是開(kāi)發(fā)還是線(xiàn)上,前端項(xiàng)目都是通過(guò)服務(wù)器訪(fǎng)問(wèn),不存在 "Opening index.html over file://" ,但程序員都知道,需求和場(chǎng)景永遠(yuǎn)是千奇百怪的,只有你想不到的,沒(méi)有產(chǎn)品經(jīng)理想不到的。
本文寫(xiě)作的初衷就是遇到了這樣一個(gè)問(wèn)題:需要快速開(kāi)發(fā)一個(gè)移動(dòng)端的展示項(xiàng)目,決定采用WebView加載Vue單頁(yè)應(yīng)用的形式,但沒(méi)有后端服務(wù)器提供,所以所有資源需從本地文件系統(tǒng)加載:
// AndroidAppWrapper public class MainActivity extends AppCompatActivity { private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); webView = new WebView(this); webView.getSettings().setJavaScriptEnabled(true); webView.loadUrl("file:///android_asset/index.html"); setContentView(webView); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); return true; } return false; } }
此情此景看來(lái)是必須 "Opening index.html over file://" 了,為此,我首先要進(jìn)行了一些設(shè)置
- 在項(xiàng)目config.js文件中將assetsPublicPath字段的值改為相對(duì)路徑 './'
- 調(diào)整生成的static文件夾中圖片等靜態(tài)資源的位置與代碼中的引用地址一致
這是比較明顯的需要改動(dòng)之處,但改完后依舊無(wú)法順利加載,經(jīng)過(guò)反復(fù)排查發(fā)現(xiàn),項(xiàng)目在開(kāi)發(fā)時(shí),router設(shè)置為了history模式(為了美觀...0_0"),當(dāng)改為hash模式后就可正常加載了。
為什么會(huì)出現(xiàn)這種情況呢?我分析原因可能如下:
當(dāng)從文件系統(tǒng)中直接加載index.html時(shí),URL為:
file:///android_asset/index.html
而首頁(yè)視圖需匹配的路徑為path: '/' :
export default new Router({ mode: 'history', routes: [ { path: '/', name: 'index', component: IndexView } ] })
我們先來(lái)看history模式,在HTML5History中:
ensureURL (push?: boolean) { if (getLocation(this.base) !== this.current.fullPath) { const current = cleanPath(this.base + this.current.fullPath) push ? pushState(current) : replaceState(current) } } export function getLocation (base: string): string { let path = window.location.pathname if (base && path.indexOf(base) === 0) { path = path.slice(base.length) } return (path || '/') + window.location.search + window.location.hash }
邏輯只會(huì)確保存在URL,path是通過(guò)剪切的方式直接從window.location.pathname獲取到的,它的結(jié)尾是index.html,因此匹配不到 '/' ,故 "Opening index.html over file:// won't work" 。
再看hash模式,在HashHistory中:
export class HashHistory extends History { constructor (router: Router, base: ?string, fallback: boolean) { ... ensureSlash() } // this is delayed until the app mounts // to avoid the hashchange listener being fired too early setupListeners () { window.addEventListener('hashchange', () => { if (!ensureSlash()) { return } ... }) } getCurrentLocation () { return getHash() } } function ensureSlash (): boolean { const path = getHash() if (path.charAt(0) === '/') { return true } replaceHash('/' + path) return false } export function getHash (): string { const href = window.location.href const index = href.indexOf('#') return index === -1 ? '' : href.slice(index + 1) }
我們看到在代碼邏輯中,多次出現(xiàn)一個(gè)函數(shù)ensureSlash(),當(dāng)#符號(hào)后緊跟著的是'/',則返回true,否則強(qiáng)行插入這個(gè)'/',故我們可以看到,即使是從文件系統(tǒng)打開(kāi)index.html,URL依舊會(huì)變?yōu)橐韵滦问剑?/p>
file:///C:/Users/dist/index.html#/
getHash()方法返回的path為 '/' ,可與首頁(yè)視圖的路由匹配。
故要想從文件系統(tǒng)直接加載Vue單頁(yè)應(yīng)用而不借助后端服務(wù)器,除了打包后的一些路徑設(shè)置外,還需確保vue-router使用的是hash模式。
以上就是從vue-router看前端路由的兩種實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于vue前端路由的兩種實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- vue-router中的hash和history兩種模式的區(qū)別
- Vue-router 中hash模式和history模式的區(qū)別
- vue+axios 前端實(shí)現(xiàn)登錄攔截的兩種方式(路由攔截、http攔截)
- vue-router 前端路由之路由傳值的方式詳解
- vue路由守衛(wèi),限制前端頁(yè)面訪(fǎng)問(wèn)權(quán)限的例子
- Vue-router中hash模式與history模式的區(qū)別詳解
- Vue Element前端應(yīng)用開(kāi)發(fā)之動(dòng)態(tài)菜單和路由的關(guān)聯(lián)處理
- vue-router中hash模式與history模式的區(qū)別
- Vue3純前端實(shí)現(xiàn)Vue路由權(quán)限的方法詳解
- Vue?前端路由工作原理hash與history的區(qū)別
相關(guān)文章
vue屬性props默認(rèn)類(lèi)型的寫(xiě)法介紹
這篇文章主要介紹了vue屬性props默認(rèn)類(lèi)型的寫(xiě)法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04Vue 路由返回恢復(fù)頁(yè)面狀態(tài)的操作方法
在使用 Vue 開(kāi)發(fā)前端的時(shí)候遇到一個(gè)場(chǎng)景在首頁(yè)進(jìn)行一些數(shù)據(jù)搜索,點(diǎn)擊搜索結(jié)果進(jìn)入詳情頁(yè)面,瀏覽詳情頁(yè)后返回主頁(yè),所以需要在返回后恢復(fù)跳轉(zhuǎn)前的頁(yè)面參數(shù)狀態(tài),今天通過(guò)本文給大家分享Vue 路由頁(yè)面狀態(tài)返回的操作方法,一起看看吧2021-07-07Vue.js實(shí)戰(zhàn)之利用vue-router實(shí)現(xiàn)跳轉(zhuǎn)頁(yè)面
對(duì)于單頁(yè)應(yīng)用,官方提供了vue-router進(jìn)行路由跳轉(zhuǎn)的處理,這篇文章主要給大家介紹了Vue.js實(shí)戰(zhàn)之利用vue-router實(shí)現(xiàn)跳轉(zhuǎn)頁(yè)面的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-04-04Vue如何調(diào)用接口請(qǐng)求頭增加參數(shù)
這篇文章主要介紹了Vue如何調(diào)用接口請(qǐng)求頭增加參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01vue iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了vue iview多張圖片大圖預(yù)覽、縮放翻轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07淺談vue 組件中的setInterval方法和window的不同
這篇文章主要介紹了淺談vue 組件中的setInterval方法和window的不同,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07Vue3+Element?Plus實(shí)現(xiàn)動(dòng)態(tài)標(biāo)簽頁(yè)以及右鍵菜單功能
這篇文章主要給大家介紹了關(guān)于Vue3+Element?Plus實(shí)現(xiàn)動(dòng)態(tài)標(biāo)簽頁(yè)以及右鍵菜單功能的相關(guān)資料,Vue?3和Element?Plus提供了一種簡(jiǎn)單的方法來(lái)實(shí)現(xiàn)側(cè)邊菜單欄與標(biāo)簽頁(yè)之間的聯(lián)動(dòng),文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09