<listing id="z3xzv"><menuitem id="z3xzv"><meter id="z3xzv"></meter></menuitem></listing>
<address id="z3xzv"></address>
<noframes id="z3xzv"><address id="z3xzv"><listing id="z3xzv"></listing></address>

    <address id="z3xzv"><address id="z3xzv"><listing id="z3xzv"></listing></address></address><form id="z3xzv"><listing id="z3xzv"><meter id="z3xzv"></meter></listing></form><form id="z3xzv"></form><form id="z3xzv"><listing id="z3xzv"><meter id="z3xzv"></meter></listing></form>
    <noframes id="z3xzv">

    <form id="z3xzv"></form>
    溫馨提示×

    Vue.js?前端路由和異步組件是什么

    發布時間:2022-09-13 17:06:17 來源:億速云 閱讀:80 作者:栢白 欄目:開發技術

    今天小編給大家分享的是Vue.js 前端路由和異步組件是什么,相信很多人都不太了解,為了讓大家更加了解,所以給大家總結了以下內容,一起往下看吧。一定會有所收獲的哦。

    目錄
    • 文章目標

      • P6

      • P6+ ~ P7

    • 一、背景

      • 二、前端路由特性

        • 三、面試?。?!

          • 四、Hash 原理及實現

            • 1、特性

            • 2、如何更改 hash

            • 3、手動實現一個基于 hash 的路由

          • 五、History 原理及實現

            • 1、HTML5 History 常用的 API

            • 2、pushState/replaceState 的參數

            • 3、History 的特性

            • 4、面試?。?!

            • 5、手動實現一個基于 History 的路由

          • 六、Vue-Router

            • 1、router 使用

            • 2、動態路由匹配

            • 3、響應路由參數的變化

            • 4、捕獲所有路由或 404 Not found 路由

            • 5、導航守衛

            • 6、完整的導航解析流程

            • 7、導航守衛執行順序(面試?。。。?/p>

            • 8、滾動行為(面試?。。。?/p>

            • 9、路由懶加載

          文章目標

          P6

          • 針對 react/vue 能夠根據業務需求口噴 router 的關鍵配置,包括但不限于:路由的匹配規則、路由守衛、路由分層等;

          • 能夠描述清楚 history 的主要模式,知道 history 和 router 的邊界;

          P6+ ~ P7

          • 在沒有路由的情況下,也可以根據也無需求,實現一個簡單的路由;

          • 讀過 router 底層的源碼,不要求每行都讀,可以口噴關鍵代碼即可;

          一、背景

          遠古時期,當時前后端還是不分離的,路由全部都是由服務端控制的,前端代碼和服務端代碼過度融合在一起。

          客戶端 --> 前端發起 http 請求 --> 服務端 --> url 路徑去匹配不同的路由 --> 返回不同的數據。

          這種方式的缺點和優點都非常明顯:

          • 優點:因為直接返回一個 html,渲染了頁面結構。SEO 的效果非常好,首屏時間特別快;

            • 在瀏覽器輸入一個 url 開始到頁面任意元素加載出來/渲染出來 --> 首屏時間;

          • 缺點:前端代碼和服務端代碼過度融合在一起,開發協同非常的亂。服務器壓力大,因為把構建 html 的工作放在的服務端;

          后來 ...隨之 ajax 的流行,異步數據請求可以在瀏覽器不刷新的情況下進行。

          后來 ...出現了更高級的體驗 &mdash;&mdash; 單頁應用。

          •  --> HTML 文件

          • 單頁 --> 單個 HTML 文件

          在單頁應用中,不僅在頁面中的交互是不刷新頁面的,就連頁面跳轉也都是不刷新頁面的。

          單頁應用的特點:

          • 頁面中的交互是不刷新的頁面的,比如點擊按鈕,比如點擊出現一個彈窗;

          • 多個頁面間的交互,不需要刷新頁面(a/b/c,a-> b -> c);加載過的公共資源,無需再重復加載;

          而支持起單頁應用這種特性的,就是 前端路由。

          二、前端路由特性

          前端路由的需求是什么?

          • 根據不同的 url 渲染不同內容;

          • 不刷新頁面;

          也就是可以在改變 url 的前提下,保證頁面不刷新。

          三、面試?。?!

          Hash 路由和 History 路由的區別?

          • hash 有 #,history 沒有 #;

          • hash 的 # 部分內容不會給服務端,主要一般是用于錨點, history 的所有內容都會給服務端;

          • hash 路由是不支持 SSR 的,history 路由是可以的;

          • hash 通過 hashchange 監聽變化,history 通過 popstate 監聽變化;

          四、Hash 原理及實現

          1、特性

          hash 的出現滿足了這個需求,他有以下幾種特征:

          • url 中帶有一個 # 符號,但是 # 只是瀏覽器端/客戶端的狀態,不會傳遞給服務端;

            • 客戶端路由地址 www.baidu.com/#/user --> 通過 http 請求 --> 服務端接收到的 www.baidu.com/

            • 客戶端路由地址 www.baidu.com/#/list/detail/1 --> 通過 http 請求 --> 服務端接收到的 www.baidu.com/

          • hash 值的更改,不會導致頁面的刷新;

          location.hash = '#aaa';
          location.hash = '#bbb';
          // 從 #aaa 到 #bbb,頁面是不會刷新的
          • 不同 url 會渲染不同的頁面;

          • hash 值的更改,會在瀏覽器的訪問歷史中添加一條記錄,所以我們才可以通過瀏覽器的返回、前進按鈕來控制 hash 的切換;

          • hash 值的更改,會觸發 hashchange 事件;

          location.hash = '#aaa';
          location.hash = '#bbb';
          
          window.addEventLisenter('hashchange', () => {});

          2、如何更改 hash

          我們同樣有兩種方式來控制 hash 的變化:

          • location.hash 的方式:

          location.hash = '#aaa';
          location.hash = '#bbb';
          • html 標簽的方式:

          <a href="#user" rel="external nofollow" > 點擊跳轉到 user </a>
          
          <!-- 等同于下面的寫法 -->
          location.hash = '#user';

          3、手動實現一個基于 hash 的路由

          • ./index.html

          <!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>Document</title>
              <link rel="stylesheet" href="./index.css" rel="external nofollow"  />
            </head>
            <body>
              <div class="container">
                <a href="#gray" rel="external nofollow" >灰色</a>
                <a href="#green" rel="external nofollow" >綠色</a>
                <a href="#" rel="external nofollow" >白色</a>
                <button onclick="window.history.go(-1)">返回</button>
              </div>
          
              <script type="text/javascript" src="index.js"></script>
            </body>
          </html>
          • ./index.css

          .container {
            width: 100%;
            height: 60px;
            display: flex;
            justify-content: space-around;
            align-items: center;
          
            font-size: 18px;
            font-weight: bold;
          
            background: black;
            color: white;
          }
          
          a:link,
          a:hover,
          a:active,
          a:visited {
            text-decoration: none;
            color: white;
          }
          • ./index.js

          /* 
            期望看到的效果:點擊三個不同的 a 標簽,頁面的背景顏色會隨之變化
          */
          class BaseRouter {
            constructor() {
              this.routes = {}; // 存儲 path 以及 callback 的對應關系
              this.refresh = this.refresh.bind(this); // 如果不 bind 的話,refresh 方法中的 this 指向 window
              // 處理頁面 hash 變化,可能存在問題:頁面首次進來可能是 index.html,并不會觸發 hashchange 方法
              window.addEventListener('hashchange', this.refresh);
          
              // 處理頁面首次加載
              window.addEventListener('load', this.refresh);
            }
          
            /**
             * route
             * @param {*} path 路由路徑
             * @param {*} callback 回調函數
             */
            route(path, callback) {
              console.log('========= route 方法 ========== ', path);
              // 向 this.routes 存儲 path 以及 callback 的對應關系
              this.routes[path] = callback || function () {};
            }
          
            refresh() {
              // 刷新頁面
              const path = `/${location.hash.slice(1) || ''}`;
              console.log('========= refresh 方法 ========== ', path);
              this.routes[path]();
            }
          }
          
          const body = document.querySelector('body');
          function changeBgColor(color) {
            body.style.backgroundColor = color;
          }
          
          const Router = new BaseRouter();
          
          Router.route('/', () => changeBgColor('white'));
          Router.route('/green', () => changeBgColor('green'));
          Router.route('/gray', () => changeBgColor('gray'));

          五、History 原理及實現

          hash 有個 # 符號,不美觀,服務端無法接受到 hash 路徑和參數。

          歷史的車輪無情攆過 hash,到了 HTML5 時代,推出了 History API。

          1、HTML5 History 常用的 API

          window.history.back(); // 后退
          
          window.history.forward(); // 前進
          
          window.history.go(-3); // 接收 number 參數,后退 N 個頁面
          
          window.history.pushState(null, null, path);
          
          window.history.replaceState(null, null, path);

          其中最主要的兩個 API 是 pushState 和 replaceState,這兩個 API 都可以在不刷新頁面的情況下,操作瀏覽器歷史記錄。

          不同的是,pushState 會增加歷史記錄,replaceState 會直接替換當前歷史記錄。

          2、pushState/replaceState 的參數

          • pushState:頁面的瀏覽記錄里添加一個歷史記錄;

          • replaceState:替換當前歷史記錄;

          他們的參數是?樣的,三個參數分別是:

          • state:是一個對象,是一個與指定網址相關的對象,當 popstate 事件觸發的時候,該對象會傳入回調函數;

          • title:新頁面的標題,瀏覽器支持不一,建議直接使用 null;

          • url:頁面的新地址;

          3、History 的特性

          History API 有以下幾個特性:

          • 沒有 #;

          • history.pushState() 或 history.replaceState() 不會觸發 popstate 事件,這時我們需要手動觸發頁面渲染;

          • 可以使用 history.popstate 事件來監聽 url 的變化;

          • 只有用戶點擊瀏覽器 倒退按鈕 和 前進按鈕,或者使用 JavaScript 調用 back、forward、go 方法時才會觸發 popstate;

          4、面試?。?!

          • pushState 時,會觸發 popstate 嗎?

            • pushState/replaceState 并不會觸發 popstate 事件,這時我們需要手動觸發頁面的重新渲染;

          • 我們可以使用 popstate 來監聽 url 的變化;

          • popstate 到底什么時候才能觸發:

            • 點擊瀏覽器后退按鈕;

            • 點擊瀏覽器前進按鈕;

            • js 調用 back 方法;

            • js 調用 forward 方法;

            • js 調用 go 方法;

          5、手動實現一個基于 History 的路由

          • ./index.html

          • ./index.css

          .container {
            width: 100%;
            height: 60px;
            display: flex;
            justify-content: space-around;
            align-items: center;
          
            font-size: 18px;
            font-weight: bold;
          
            background: black;
            color: white;
          }
          
          a:link,
          a:hover,
          a:active,
          a:visited {
            text-decoration: none;
            color: white;
          }
          • ./index.js

          class BaseRouter {
            constructor() {
              this.routes = {};
          
              // location.href; => hash 的方式
              console.log('location.pathname ======== ', location.pathname); // http://127.0.0.1:8080/green ==> /green
              this.init(location.pathname);
              this._bindPopState();
            }
          
            init(path) {
              // pushState/replaceState 不會觸發頁面的渲染,需要我們手動觸發
              window.history.replaceState({ path }, null, path);
              const cb = this.routes[path];
              if (cb) {
                cb();
              }
            }
          
            route(path, callback) {
              this.routes[path] = callback || function () {};
            }
          
            // ! 跳轉并執行對應的 callback
            go(path) {
              // pushState/replaceState 不會觸發頁面的渲染,需要我們手動觸發
              window.history.pushState({ path }, null, path);
              const cb = this.routes[path];
              if (cb) {
                cb();
              }
            }
            // ! 演示一下 popstate 事件觸發后,會發生什么
            _bindPopState() {
              window.addEventListener('popstate', e => {
                /* 
                  觸發條件:
                    1、點擊瀏覽器前進按鈕
                    2、點擊瀏覽器后退按鈕
                    3、js 調用 forward 方法
                    4、js 調用 back 方法
                    5、js 調用 go 方法
                */
                console.log('popstate 觸發了');
                const path = e.state && e.state.path;
                console.log('path >>> ', path);
                this.routes[path] && this.routes[path]();
              });
            }
          }
          const Router = new BaseRouter();
          const body = document.querySelector('body');
          const container = document.querySelector('.container');
          
          function changeBgColor(color) {
            body.style.backgroundColor = color;
          }
          Router.route('/', () => changeBgColor('white'));
          Router.route('/gray', () => changeBgColor('gray'));
          Router.route('/green', () => changeBgColor('green'));
          
          container.addEventListener('click', e => {
            if (e.target.tagName === 'A') {
              e.preventDefault();
              console.log(e.target.getAttribute('href')); // /gray  /green 等等
              Router.go(e.target.getAttribute('href'));
            }
          });

          六、Vue-Router

          1、router 使用

          使用 Vue.js,我們已經可以通過組合組件來組成應用程序,當你要把 Vue Router 添加進來,我們需要做的是,將組件(components)映射到路由(routes),然后告訴 Vue Router 在哪里渲染它們。

          舉個例子:

          <!-- 路由匹配到的組件將渲染在這里 -->
          <div id="app">
            <router-view></router-view>
          </div>
          // 如果使用模塊化機制編程,導入 Vue 和 VueRouter,要調用 Vue.use(VueRouter)
          
          // 1、定義(路由)組件
          // 可以從其他文件 import 進來
          const Foo = { template: '<div>foo</div>' };
          const Bar = { template: '<div>bar</div>' };
          
          // 2、定義路由
          //每個路由應該映射一個組件,其中 component 可以是通過 Vue.extend() 創建的組件構造器,或者只是一個組件配置對象
          const routes = [
            { path: '/foo', component: Foo },
            { path: '/bar', component: Bar },
          ];
          
          // 3、創建 router 實例,然后傳 routes 配置
          const router = new VueRouter({
            routes,
          });
          
          // 4、創建和掛載根實例
          // 記得要通過 router 配置參數注入路由,從而讓整個應用都有路由功能
          const app = new Vue({
            router,
          }).$mount('#app');

          2、動態路由匹配

          我們經常需要把某種模式匹配到的所有路由,全部映射到同個組件,比如用戶信息組件,不同用戶使用同一個組件。

          可以通過 $route.params.id 或者參數。

          const router = new VueRouter({
            routes: [
              // 動態路徑參數,以冒號開頭
              { path: '/user/:id', component: User },
            ],
          });
          
          const User = {
            template: '<div>User: {{ $route.params.id }}</div>',
          };

          3、響應路由參數的變化

          復用組件時,想對 路由參數 的變化作出響應的話,可以使用 watch 或者 beforeRouteUpdate

          舉個例子:

          const User = {
            template: '...',
            watch: {
              $route(to, from) {
                // 對路由變化作出響應...
              },
            },
          };
          
          const User = {
            template: '...',
            beforeRouteUpdate(to, from, next) {
              // 對路由變化作出響應...
              // don't forget to call next()
            },
          };

          4、捕獲所有路由或 404 Not found 路由

          當時用通配符路由時,請確保路由的順序是正確的,也就是說含有通配符的路由應該在 最后。

          舉個例子:

          5、導航守衛

          vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種方式植入路由導航過程中:

          • 全局的

            • 全局前置守衛:router.beforeEach

            • 全局解析守衛:router.beforeResolve

            • 全局后置鉤子:router.afterEach

          • 單個路由獨享的

            • 路由獨享守衛:beforeEnter

          • 組件級的

            • beforeRouteEnter

            • beforeRouteUpdate

            • beforeRouteLeave

          6、完整的導航解析流程

          • 導航被觸發;

          • 在失活的組件里調用離開守衛(前一個組件的 beforeRouteLeave);

          • 調用全局的 beforeEach 守衛;

          • 在重用的組件里調用 beforeRouteUpdate 守衛;

          • 在路由配置里調用 beforeEnter;

          • 解析異步路由組件;

          • 在被激活的組件里調用 beforeRouterEnter;

          • 調用全局的 beforeResolve 守衛;

          • 導航被確認;

          • 調用全局的 afterEach 鉤子;

          • 觸發 DOM 更新;

          • 用創建好的實例調用 beforeRouterEnter 守衛中傳給 next 的回調函數;

          舉個例子:

          // 全局
          const router = new VueRouter({
            mode: 'history',
            base: process.env.BASE_URL,
            routes,
          });
          
          // 全局的導航守衛
          router.beforeEach((to, from, next) => {
            console.log(`Router.beforeEach => from=${from.path}, to=${to.path}`);
            // 可以設置頁面的 title
            document.title = to.meta.title || '默認標題';
            // 執行下一個路由導航
            next();
          });
          
          router.afterEach((to, from) => {
            console.log(`Router.afterEach => from=${from.path}, to=${to.path}`);
          });
          
          // 路由獨享
          const router = new VueRouter({
            routes: [
              {
                path: '/foo',
                component: Foo,
                beforeEnter: (to, from, next) => {
                  // 配置數組里針對單個路由的導航守衛
                  console.log(`TestComponent route config beforeEnter => from=${from.path}, to=${to.path}`);
                  next();
                },
              },
            ],
          });
          
          // 組件
          const Foo = {
            template: `...`,
            beforeRouteEnter(to, from, next) {
              // 在渲染該組件的對應路由被 comfirm 前調用
              // 不!能!獲取組件實例 this,因為當守衛執行前,組件實例還沒被調用
            },
            beforeRouteUpdate(to, from, next) {
              // 在當前路由改變,但是該組件被復用時調用
              // 舉個例子來說,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候
              // 由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用
              // 可以訪問組件實例 this
            },
            beforeRouteLeave(to, from, next) {
              // 導航離開該組件的對應路由時調用
              // 可以訪問組件實例 this
            },
          };

          next 必須調用:

          • next():進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed(確認的)。

          • next(false):中斷當前的導航。如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到 from 路由對應的地址。

          • next("/") 或者 next({ path: "/" }):跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航??梢韵?nbsp;next 傳遞任意位置對象,且允許設置諸如 replace: true、name: "home" 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。

          • next(error):如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 注冊過的回調。

          7、導航守衛執行順序(面試?。。。?/h4>
          • 【組件】前一個組件的 beforeRouteLeave

          • 【全局】的 router.beforeEach

            • 【組件】如果是路由參數變化,觸發 beforeRouteUpdate

          • 【配置文件】里,下一個的 beforeEnter

          • 【組件】內部聲明的 beforeRouteEnter

          • 【全局】的 router.afterEach

          8、滾動行為(面試?。。。?/h4>

          vue-router 里面,怎么記住前一個頁面的滾動條的位置???

          使用前端路由,當切換到新路由時,想要頁面滾動到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣。

          Vue-router 能做到,而且更好,它讓你可以自定義路由切換時頁面如何滾動。

          【注意】:這個功能只在支持 history.pushState 的瀏覽器中可用。

          scrollBehavior 生效的條件:

          • 瀏覽器支持 history API;

          • 頁面間的交互是通過 go,forward,back 或者 瀏覽器的前進/返回按鈕;

          window.history.back(); // 后退
          window.history.forward(); // 前進
          window.history.go(-3); // 接收 number 參數,后退 N 個頁面

          舉個例子

          // 1. 記?。菏謩狱c擊瀏覽器返回或者前進按鈕,記住滾動條的位置,基于 history API 的,其中包括:go、back、forward、手動點擊瀏覽器返回或者前進按鈕
          // 2. 沒記?。簉outer-link,并沒有記住滾動條的位置
          
          const router = new VueRouter({
            mode: 'history',
            base: process.env.BASE_URL,
            routes,
            scrollBehavior: (to, from, savedPosition) => {
              console.log(savedPosition); // 已保存的位置信息
              return savedPosition;
            },
          });

          9、路由懶加載

          當打包構建應用時,JavaScript 包會變得非常大,影響頁面加載。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。

          舉個例子:

          const Foo = () => import(/* webpackChunkName: "foo" */ './Foo.vue');
          
          const router = new VueRouter({
            routes: [{ path: '/foo', component: Foo }],
          });

          關于Vue.js 前端路由和異步組件是什么就分享到這里了,希望以上內容可以對大家有一定的參考價值,可以學以致用。如果喜歡本篇文章,不妨把它分享出去讓更多的人看到。

          推薦閱讀:Vue動態組件和異步組件是什么

          免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

          主題地圖

          日本亚洲一区二区
          <listing id="z3xzv"><menuitem id="z3xzv"><meter id="z3xzv"></meter></menuitem></listing>
          <address id="z3xzv"></address>
          <noframes id="z3xzv"><address id="z3xzv"><listing id="z3xzv"></listing></address>

            <address id="z3xzv"><address id="z3xzv"><listing id="z3xzv"></listing></address></address><form id="z3xzv"><listing id="z3xzv"><meter id="z3xzv"></meter></listing></form><form id="z3xzv"></form><form id="z3xzv"><listing id="z3xzv"><meter id="z3xzv"></meter></listing></form>
            <noframes id="z3xzv">

            <form id="z3xzv"></form>