vuejs路由和组件系统

2024-05-24 18:52

本文主要是介绍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 打包

这篇关于vuejs路由和组件系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/999240

相关文章

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Ubuntu系统怎么安装Warp? 新一代AI 终端神器安装使用方法

《Ubuntu系统怎么安装Warp?新一代AI终端神器安装使用方法》Warp是一款使用Rust开发的现代化AI终端工具,该怎么再Ubuntu系统中安装使用呢?下面我们就来看看详细教程... Warp Terminal 是一款使用 Rust 开发的现代化「AI 终端」工具。最初它只支持 MACOS,但在 20

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

Debian如何查看系统版本? 7种轻松查看Debian版本信息的实用方法

《Debian如何查看系统版本?7种轻松查看Debian版本信息的实用方法》Debian是一个广泛使用的Linux发行版,用户有时需要查看其版本信息以进行系统管理、故障排除或兼容性检查,在Debia... 作为最受欢迎的 linux 发行版之一,Debian 的版本信息在日常使用和系统维护中起着至关重要的作

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资