vuejs路由和組件系統

前端路由原理

  • createRouter

    * hash* window.addEventListener('hashChange')*	兩種實現路由切換的模式:UI組件(router-link,router-view),Api(push()方法)
    * history * HTML5新增的API ,可以通過不刷新頁面前提下,修改頁面路由-history.pushState() 
    
  • useRouter

  • router-link

  • router-view

手寫實現一個路由跳轉
/*** mini 版本 vue-router*/import { ref, provide, inject } from 'vue';
import RouterLink from './router-link.vue';
import RouterView from './router-view.vue'// 保證全局唯一性,可以用 Symbol 創建
const ROUTER_KEY = '__router__'// 
class Router {constructor(options) {// 記錄訪問歷史this.history = options.history;// 初始化傳入路由表this.routes = options.routes;// 當前激活的路由this.current = ref(this.history.url)// hashChange 事件觸發把當前激活路由的值記錄下來this.history.bindEvents(() => {this.current.value = window.location.hash.slice(1)})}push(to) {location.hash = '#' + to;window.history.pushState({}, '', to)}beforeEach(fn) {this.guards = fn;}// app 插件的注冊調用函數// provie/inject,pinia install(app) {app.provide(ROUTER_KEY, this)// 兼容 options APIapp.$router = this;// 注冊全局組件app.component('router-link', RouterLink)app.component('router-view', RouterView)}
}// 1. hash
// hashChange -> View 
function createWebHashHistory() {function bindEvents(fn) {window.addEventListener('hashchange', fn)}return {bindEvents,url: window.location.hash.slice(1) || '/'}
}// TODO
function createWebHistory() {}// 組合式 API,獲取當前 vue-router 的實例
// options API, this.$router 來獲取vue-router 的實例
function useRouter() {return inject(ROUTER_KEY)
}// 暴露一個創建對應類的實例的方法
function createRouter(options) {return new Router(options)
}export { createRouter, useRouter, createWebHashHistory }

router-link

<template><a :href="'#' + props.to"><slot /></a>
</template><script setup>// a -> href
// router-link to
import { defineProps } from 'vue';let props = defineProps({to: { type: String, required: true }
})</script><style lang="css" scoped></style>

router-view

<template><!-- 動態組件 --><component :is="comp"></component>
</template><script setup>import { computed } from 'vue'
import { useRouter } from './mini-router'// 獲取到了 Router 的實例
let router = useRouter();console.log('router 實例', router)const comp = computed(() => {// 根據注冊的路由表和當前激活的 route 匹配const route = router.routes.find(route => {// 百分百等于,靜態路由return route.path === router.current.value})// 路由守衛的激活const ret = route?.guardsreturn route.component;
})</script><style lang="scss" scoped></style>
特性原理解析
  • 路由匹配規則:靜態路由、動態路由、正則匹配

    const router = new VueRouter({routes: [// 動態路徑參數 以冒號開頭{ path: '/user/:id', component: User }]})
    
  • 嵌套路由:

    const router = new VueRouter({routes: [{path: '/user/:id',component: User,children: [{// 當 /user/:id/profile 匹配成功,// UserProfile 會被渲染在 User 的 <router-view> 中path: 'profile',component: UserProfile},{// 當 /user/:id/posts 匹配成功// UserPosts 會被渲染在 User 的 <router-view> 中path: 'posts',component: UserPosts}]}]})
    
  • 路由守衛:
    在這里插入圖片描述

  • 路由元信息:路由表中配置meta字段

  • 滾動行為記錄:這個功能只在支持 history.pushState 的瀏覽器中可用。

const router = new VueRouter({routes: [...],scrollBehavior (to, from, savedPosition) {// return 期望滾動到哪個的位置}
})
  • 路由懶加載和異步組件
const Foo = () => import('./Foo.vue')
把組件按組分塊
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
  • 過渡動效
<transition><router-view></router-view>
</transition><!-- 使用動態的 transition name -->
<transition :name="transitionName"><router-view></router-view>
</transition>
內置組件
  • 異步組件 defineAsyncComponent 、 <component :is=“xxx” / >
import { defineAsyncComponent } from 'vue'
const AsyncHelloWorld = defineAsyncComponent({//es6 importloader:()=>import('xxx.vue'),loadingComponent:LoadingComp,delay:100,timeout:300,errorComponent:xxx
})

異步組件的實現

// 異步組件的實現
// options = object {
//  loader: () => Promoise(void)
// }
// options 
function defineAsyncComponent(options) {if (typeof options === 'function') {options = {loader: options,};}const { loader } = options;let InnerComp = null;// 記錄重試次數let retries = 0;// 封裝 load 函數用來加載異步組件function load() {return (loader()// 捕獲加載器的錯誤.catch((err) => {// 如果用戶指定了 onError 回調,則將控制權交給用戶if (options.onError) {// 返回一個新的 Promise 實例return new Promise((resolve, reject) => {// 重試方法const retry = () => {resolve(load());retries++;};// 失敗const fail = () => reject(err);// 作為 onError 回調函數的參數,讓用戶來決定下一步怎么做options.onError(retry, fail, retries);});} else {throw error;}}));};// 創建一個 vue 組件return {name: 'AsyncComponentWrapper',setup() {// 標識異步組件是否加載成功const loaded = ref(false);const error = shallowRef(null);const loading = ref(false);// timeout 默認不超時const timeout = ref(false);let loadingTimer = null;if (options.delay) { // 100ms loadingTimer = setTimeout(() => {loading.value = true;}, options.delay);} else {loading.value = true;}let timer = null// 用戶配置參數 timeoutif(options.timeout) {timer = setTimeout(() => {timeout.value = true;}, options.timeout);}onUmounted(() => clearTimeout(timer))// 調用 load 函數加載組件// import(), ES6load().then((c) => {InnerComp = c;loaded.value = true;}).catch((err) => {error.value = err;}).finally(() => {loading.value = false;clearTimeout(loadingTimer);});// 占位內容...const Placeholer = { type: Text, children: '' }if(loaded.vlaue) {// 異步組價加載成功,渲染 InnerComp,否則渲染渲染出錯組件return {type: InnerComp,}} else if(timeout.value && options.errorComponent) {// 超時,并且設置了 Error 組件return {type: options.errorComponent,}        } else if(error.value && options.errorComponent) {return {type: options.errorComponent,}}return Placeholer},};
}// load 函數接收一個 onError 回調函數
function load(onError) {// 請求接口,得到 Promise 實例const p = fetch(100);// 捕獲錯誤return p.catch((err) => {// 當錯誤發生時,返回一個新的 Promise 實例,并調用 onError 回調,// 同時將 retry 函數作為 onError 回調的參數return new Promise((resolve, reject) => {// retry 函數,用來執行重試的函數,執行該函數會重新調用 load 函數并發送請求const retry = () => resolve(load(onError));const fail = () => reject(err);onError(retry, fail);});});
}function fetch(ms) {return new Promise((resolve, reject) => {// 請求會在  秒后失敗setTimeout(() => {reject('err');}, ms);});
}
  • KeepAlive 組件
  • Teleport 組件
<Teleport to="body"><div v-if="open" class="modal"><p>Hello from the modal!</p><button @click="open = false">Close</button></div>
</Teleport>
  • Transition 組件
    < Transition> 會在一個元素或組件進入和離開 DOM 時應用動畫
<Transition name="fade">...
</Transition>
.fade-enter-active,
.fade-leave-active {transition: opacity 0.5s ease;
}.fade-enter-from,
.fade-leave-to {opacity: 0;
}
使用場景
  • keep-alive,多標簽頁交互,多 tab 切換
  • teleport,全局彈窗,dom 結構脫離組件樹渲染
  • transition,實現組件過渡動畫
  • defineAsyncComponent,聲明一個異步組件,實現性能優化和分 chunk 打包

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14327.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14327.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14327.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

每日一題(1)

在看一本08年出版的書的時候&#xff0c;看到了這樣一個問題&#xff0c;感覺答案很奇怪&#xff1a; public class demo_p22 {public static void main(String args[]){int sCook1,sFish2;//各技能標記character ch1new character();if(ch1.haveSkill(sCook))System.out.print…

仙樂健康科技股份有限公司「E立方仿生增效技術平臺」推出新品啦

在這個看臉的顏值經濟時代,很多女性將肌膚保養作為人生的“必修課”,從各種網上攻略到高端護膚品,再到美容院的專業護理,可以說是應有盡有。最近,仙樂健康科技股份有限公司「E立方仿生增效技術平臺」推出的新品——PQQ鹽膠原小分子肽樺樹汁飲品,就受到了頗多追求健康美人士的關…

svg中漸變色的應用

設置漸變色背景 在 SVG 中可以使用<linearGradient>或<radialGradient>元素來設置漸變背景色。以下是一個簡單的示例&#xff1a; <svg width"400" height"400"><defs><linearGradient id"myGradient"><stop…

Discord運營攻略 | 從0-1教你搭建用戶社區!

Discord&#xff0c;這個最初為游戲愛好者設計的通訊平臺&#xff0c;現在已經發展成為了一個多元化的社區聚集地&#xff0c;涵蓋了各種興趣和行業。如果你是一名社媒運營人員&#xff0c;正在考慮如何從零開始構建一個充滿活力的Discord用戶社區&#xff0c;那么你來對地方了…

【CSP CCF記錄】202012-2 期末預測之最佳閾值

題目 過程 思路 第一次沒用前綴和&#xff0c;暴力求解得50分。 采用前綴和方法。 1. 對原數組stu[i]進行排序。 2. 計算前綴和數組s[]&#xff0c;s[i]表示安全指數的y_i的前綴和&#xff0c;即安全指數小于等于y_i時的實際掛科情況&#xff0c;y_i之前有多少個未掛科&am…

無線領夾麥克風哪個品牌好?無線麥克風品牌排行榜前十名推薦

?在當今的數字化浪潮中&#xff0c;個人聲音的傳播和記錄變得尤為重要。無論是會議中心、教室講臺還是戶外探險&#xff0c;無線領夾麥克風以其卓越的便攜性和連接穩定性&#xff0c;成為了人們溝通和表達的首選工具。面對市場上琳瑯滿目的無線麥克風選擇&#xff0c;為了幫助…

Python筑基之旅-MySQL數據庫(三)

目錄 一、數據庫操作 1、創建 1-1、用mysql-connector-python庫 1-2、用PyMySQL庫 1-3、用PeeWee庫 1-4、用SQLAlchemy庫 2、刪除 2-1、用mysql-connector-python庫 2-2、用PyMySQL庫 2-3、用PeeWee庫 2-4、用SQLAlchemy庫 二、數據表操作 1、創建 1-1、用mysql-…

38. 外觀數列 - 力扣(LeetCode)

基礎知識要求&#xff1a; Java&#xff1a;方法、for循環、if eles語句、StringBuilder類 Python&#xff1a; 方法、for循環、if else語句、字符串拼接 題目&#xff1a; 「外觀數列」是一個數位字符串序列&#xff0c;由遞歸公式定義&#xff1a; countAndSay(1) "…

記錄Python低代碼開發框架zdppy_amcrud的開發過程

實現新增接口 基礎代碼 import env import mcrud import api import snowflakeenv.load(".env") db mcrud.new_env()table "user" columns ["name", "age"]async def add_user(req):data await api.req.get_json(req)values [d…

SkyEye對接CANoe:助力汽車軟件功能驗證

01.簡介 CANoe&#xff08;CAN open environment&#xff09;是德國Vector公司專為汽車總線設計而開發的一款通用開發環境&#xff0c;作為車載網絡和ECU開發、測試和分析的專業工具&#xff0c;支持從需求分析到系統實現的整個系統的開發過程。CANoe豐富的功能和配置選項被OE…

虛擬ECU:徹底改變汽車軟件開發與測試

汽車開發領域有著垂直性較強的一系列需求&#xff0c;其中最為矚目的需求之一就是對安全高效的軟件測試方法的需求。傳統的汽車開發偏向使用硬件原型與真實ECU進行軟件測試&#xff0c;但由于硬件設備往往在開發周期的中后階段才生產完成&#xff0c;給汽車開發帶來了成本與時間…

理解Solidity 中的 tx.origin 和 msg.sender

開發者需要了解在Solidity中tx.origin和msg.sender的區別。這兩個全局變量經常被混淆&#xff0c;盡管它們之間有著根本的不同。雖然乍一看它們可能相似&#xff0c;但在交易的上下文中&#xff0c;tx.origin和msg.sender代表不同的地址。在這篇博客文章中&#xff0c;我們將深…

spring boot 之 事務

內容是小老弟的一些整理和個人思考總結&#xff0c;知識的海洋那么大&#xff0c;有錯誤的話還請諸位大佬指點一下&#xff01; 事務是一個不可分割操作序列&#xff0c;也是數據庫并發控制的基本單位&#xff0c;其執行的結果必須使數據庫從一種一致性狀態變到另一種一致性狀…

電商內卷時代,視頻號小店憑借一己之力“脫穎而出”

大家好&#xff0c;我是電商笨笨熊 今年618各大電商平臺花樣百出&#xff1b; 某寶更是直接取消了“預售”&#xff0c;從5月就開始進入618預熱期&#xff1b; 不少玩家既開心又難過&#xff0c;市場如此內卷&#xff0c;618確實是個爆發期&#xff0c;但更多的需要不斷壓低…

Star CCM+分配零部件至區域后交界面丟失-更新找回

前言 在工程應用中&#xff0c;將零部件分配至區域后&#xff0c;一般常規的操作需要對交界面進行檢查。偶爾會發現交界面丟失。遇到此類問題&#xff0c;在沒有做其他操作前&#xff08;比如畫網格&#xff09;&#xff0c;可以選擇先刪除所有區域在重新分配至區域。若已經進…

基于SSM的大學生兼職管理系統

基于SSM的大學生兼職管理系統的設計與實現~ 開發語言&#xff1a;Java數據庫&#xff1a;MySQL技術&#xff1a;SpringSpringMVCMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系統展示 登錄界面 企業界面 前臺學生界面 管理員界面 摘要 隨著大學生兼職市場的日益繁…

K8s 高級調度

文章目錄 K8s 高級調度CronJobinitContainerTaint 和 Toleration污點&#xff08;Taint&#xff09;容忍&#xff08;Toleration&#xff09; AffinityNodeAffinityPodAnffinity 和 PodAntiAffinity 總結 K8s 高級調度 CronJob 在 k8s 中周期性運行計劃任務&#xff0c;與 li…

【vue echart】完成一個簡單echart圖表+自適應

實現效果&#xff1a; html&#xff1a; <divref"echartOne"id"echartOne"style"width: 100%; height: 100%" ></div> js: getEchartOne() {let chart this.$echarts.init(this.$refs.echartOne);chart.setOption({title: {text:…

linux 有名管道FIFO

無名管道應用的一個重大限制是它沒有名字&#xff0c;因此&#xff0c;只能用于具有親緣關系的進程間通信&#xff0c;在有名管道&#xff08;named pipe或FIFO&#xff09;提出后&#xff0c;該限制得到了克服。FIFO不同于管道之處在于它提供一個路徑名與之關聯&#xff0c;以…

云原生|為什么服務網格能夠輕松重塑微服務?一文講清楚!

目錄 一、概述 二、 設計 三、服務網格 四、總結 一、概述 容器化技術與容器編排推動了微服務架構應用的演進&#xff0c;于是應用的擴展與微服務的數量日益增加&#xff0c;新的問題隨之而來&#xff0c;監控服務的性能變得越來越困難&#xff0c;微服務與微服務之間相互通…