【VUE3】保姆级基础讲解(四): vue-router,vuex

news2024/11/13 8:38:01

目录

后端路由的映射方案

 SPA:single page web application

url的hash

 vue-router

基础使用

 路由默认url

异步打包

动态路由匹配

notfound

嵌套路由

动态路由

添加路由

添加嵌套路由

 删除路由

路由导航守卫

全局前置守卫beforeEach

Vuex状态管理

状态管理概念

vuex基础使用

安装

 创建store对象

main.js调用 

组件使用store 

state状态映射到组件

options api  computed 属性方案

setup方案

直接解构(推荐)

getters

基础使用

getters函数同时调用getters

getters函数返回函数

getter函数映射到组件

Mutation

基本使用

映射使用

重要原则


后端路由的映射方案

浏览器向服务器通过url申请页面,然后服务器通过url映射到具体的html页面,再将html页面传递给服务器,这就是后端路由的映射方式,url 对应了一个具体的 html页面

 SPA:single page web application

之前的后端方案是一个 url 对应了一个具体的 html页面

而现在的许多网站的方式不是这样,拿网易云网站举例

在点击导航栏时,例如点击  我的音乐

页面的url会发生改变,但是导航栏是没有变化的,而只变化了下面的界面

这说明这种方式,url发生变化时不会渲染整个页面,而只更新一部分

即url与组件一一对应,这就是SPA模式

 其实也就是前端路由

url的hash

 vue-router

基础使用

1、创建路由

 先下载插件  npm i vue-router

一般会建立一个js文件,用来创建路由并保持映射关系(其实就是保存url和组件的对应关系)

//引入路由函数
import { createRouter,createWebHashHistory} from 'vue-router'

//引入组件
import page from '../components/page.vue'
import nav from '../components/navitem.vue'

//创建路由
const router = createRouter({
//确定映射模式:hash模式
    history:createWebHashHistory(),
//确定映射关系
    routes:[
        {path:'/page',component:page},
        {path:'/nav',component:nav}
    ]
})

//导出路由
export default router

每个对应关系是可以有独一无二的name属性的,以便后续使用

        {
            name: "nav",
            path: '/nav',
            component: nav
        },

2、让路由生效

在main.js中引入路由并运用

import { createApp } from 'vue'
import App from './App.vue'
//引用路由
import router from './router/index'

const app = createApp(App)

//运用路由
app.use(router)

app.mount('#app')

3、router-view占位

在APP.vue或者其他组件中使用 router-view占位,以告诉页面当我切换url时,组件渲染在什么地方

4、router-link进行路由的切换

其实就是类似于a元素,点击时就可以切换url,使用 to属性

<template>
<router-view></router-view>
<router-link to="/page" class="link">page</router-link>
<router-link to="/nav" class="link">nav</router-link>
</template>

router-link自带class:router-link-active

选中哪个router-link,哪个router-link就会加入这个class,且具有排他作用

  当然也可以自己定义按钮函数:点击按钮触发jump函数,跳转到page

  const route = useRouter()
  let jump = ()=>{
    route.push('/page')
  }

 路由默认url

在初始时可以设定默认的跳转url

const router = createRouter({
    history:createWebHashHistory(),
    routes:[
//默认
        {path:'/',redirect:'/page'},

        {path:'/page',component:page},
        {path:'/nav',component:nav}
    ]
})

异步打包

【VUE3】保姆级基础讲解(三)非父子组件通讯,$refs,动态组件,keep-alive,Composition API_独憩的博客-CSDN博客

const page = ()=>import(/* webpackChunkName: 'page' */'../components/page.vue')
const nav = ()=>import(/* webpackChunkName: 'nav' */'../components/navitem.vue')

这样在打包的时候就会单独创造js文件

注释是固定写法,既魔法注释,会告知打包时的js文件名称

动态路由匹配

对于用户或者商品数据,往往的url是  商品\商品编号  组成,例如  good\111

那么我们希望,即使url变成这个样子,也要渲染good组件,只是穿进去的id是111

用到了动态路由匹配

    routes:[
        {path:'/',redirect:'/page'},
        {path:'/page',component:page},
        {path:'/nav',component:nav},
        {path:'/good/:id',component:good}
    ]

那么就定义了  id  用来传导编号

在使用时直接

<router-link to="/good/111" class="link">good1</router-link>
<router-link to="/good/222" class="link">good2</router-link>

在url转换成 good\111或者good\222时也能匹配到 good 组件

在good.vue中,如果想使用这个id:

<template>
    <h1>{{$route.params.id}}</h1>
</template>
<script setup>
    import { useRoute } from 'vue-router'
    const route = useRoute()
    console.log(route.params);
</script>
<style scoped>
</style>

在组件中  使用 $route.params.id

在js代码中,使用useRoute()获取路由

js代码中还可以使用 route.forward()或 route.back()跳转后一个和前一个界面 

如果想在切换 id时能持续获取params,需要用到onBeforeRouteUpdate

<template>
    <h1>{{$route.params.id}}</h1>
</template>
<script setup>
    import { useRoute , onBeforeRouteUpdate} from 'vue-router'
    const route = useRoute()
    onBeforeRouteUpdate((to,from)=>{
        console.log(to.params);
        console.log(from.params);
    })
    console.log(route.params);
</script>
<style scoped>
</style>

notfound

当传入的url是没经过匹配时,这时可以设定显示一个  notfound 组件

{path:'/:pathMatch(.*)',component:notfound}

嵌套路由

<template>
<h1>page</h1>
<router-view></router-view>
</template>

一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:

/page/profile                         /page/posts
+------------------+                  +-----------------+
| page             |                  | page            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

也就是说在 组件中再次使用 router-view占位

page.vue:

<template>
<h1>page</h1>
<router-view></router-view>
</template>

那么在配置routes时,应该加入children属性

        {path:'/page',
        component:page,
        children:[
            {
                path:'profile',
                component:()=>import('../components/profile.vue')
            }
        ]},

动态路由

添加路由

使用addRoute函数直接添加根路由

router.addRoute({
            name: "nav",
            path: '/nav',
            component: nav
})

添加嵌套路由

要将嵌套路由添加到现有的路由中,可以将路由的 name 作为第一个参数传递给 router.addRoute(),这将有效地添加路由,就像通过 children 添加的一样:

router.addRoute("page", {
    path: 'profile',
    component: () => import('../components/profile.vue')
}
)

通过这种方式给page路由添加了children

 删除路由

有几个不同的方法来删除现有的路由:

  • 通过添加一个名称冲突的路由。如果添加与现有途径名称相同的途径,会先删除路由,再添加路由:
    router.addRoute({ path: '/about', name: 'about', component: About })
    // 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的
    router.addRoute({ path: '/other', name: 'about', component: Other })
    
  • 通过调用 router.addRoute() 返回的回调:
    const removeRoute = router.addRoute(routeRecord)
    removeRoute() // 删除路由如果存在的话
    
    当路由没有名称时,这很有用。
  • 通过使用 router.removeRoute() 按名称删除路由:
    router.addRoute({ path: '/about', name: 'about', component: About })
    // 删除路由
    router.removeRoute('about')
    
    需要注意的是,如果你想使用这个功能,但又想避免名字的冲突,可以在路由中使用 Symbol 作为名字。

当路由被删除时,所有的别名和子路由也会被同时删除

路由导航守卫

在进行路由跳转时,可以进行回调函数,既 守卫

有一种使用场景是:在点击跳转时,先判断是否登陆,如果登陆了就跳转到对应的路由,如果没有登陆就跳转到登陆路由

全局前置守卫beforeEach

router.beforeEach((to, from) => {
    if(to.path !== "/login"){
        return "/login"
    }
  })

 其他守卫:导航守卫 | Vue Router

Vuex状态管理

状态管理概念

在一个项目中存在着很多状态,其实这个状态就是我们一直使用的变量,例如网易云音乐这个项目,播放状态(暂停or播放),现在播放的歌曲名称,播放到哪一句....都是其状态,对于这些数据的管理我们就称之为是状态管理。


在前面我们是如何管理自己的状态呢?
在Vue开发中,我们使用组件化的开发方式;

  • 而在组件中我们定义data或者在setup中返回使用的数据,这些数据我们称之为state;
  • 在模块template中我们可以使用这些数据,模块最终会被渲染成DOM,我们称之为View;
  • 在模块中我们会产生一些行为事件,处理这些行为事件时,有可能会修改state,这些行为事件我们称之为actions;
     

在之前的例子中,都是在组件中用变量直接控制的,但是这样存在弊端:

  1. 当项目组件十分庞大,状态很多,会使得组件十分臃肿,不好维护
  2. 虽然我们有props和emits等数据传递方法,但是当组件很多,且组件之间不是父子关系时,数据的传递会变得十分复杂

那么就需要创建一个状态库 store来管理这些状态:

  •  第一幅图表示所有的组件都可以和store内部的状态进行交互
  • 第二幅图表示,组件可以直接拿到数据state,但是如果想修改,必须走 actions---mutations---state流程,具体在下文阐述

vuex的基本元素为:state ,getters,mutation,actions,modules 

vuex基础使用

安装

npm i vuex

 创建store对象

与路由类似,一般会在src文件夹下创建store文件夹,下面创建一个index.js文件:

import {createStore} from  'vuex'
const store = createStore({
    state:()=>{
        return{
            counter:100
        }
    },
})
export default store

这里创建了一个store实例,然后定义了内部的state,采用的是函数式编程

使用createStore创建store对象,默认内部的状态是响应式的

main.js调用 

main.js中:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import store from './store/index'

const app = createApp(App)

app.use(router)
app.use(store)

app.mount('#app')

组件使用store 

然后在任何一个组件中就可以使用state的数据进行展示:

 <h1>{{$store.state.counter}}</h1>

在组件的js中获取数据方法:

  import {useStore} from 'vuex'
  const store = useStore()
  console.log(store.state);

 

state状态映射到组件

options api  computed 属性方案

当state里面的状态很多时,如果每个状态都采用  $store.state.xxx 的形式调用,会十分繁琐

那么我们希望将state状态整体映射到组件中

一般我们会使用  computed 属性,其属于options api

对于state:

import {createStore} from  'vuex'
const store = createStore({
    state:()=>{
        return{
            counter:100,
            name:'kobe',
            age:18
        }
    },

})
export default store

 在组件中可以引入mapState函数放置在computed属性中,这个函数前加 ... 表示其会返回多个函数,通过数组的形式将state中的状态映射进来,在模板中就可以直接使用了

<template>
  <h1>{{name}}</h1>
</template>
<script>
  import {mapState} from 'vuex'
    export default{
    computed:{
      ...mapState(['name','age','counte'])
    }
  }
</script>

setup方案

但是这个操作在setup里面写就很麻烦,一般不会这么用

  const store = useStore()
  const {name ,age,counter} =mapState(['name','age','counter'])
  const Cname = computed(name.bind({$store:store}))

从mapState中返回的是函数形式,要想使用必须放在computed属性中

但是在上述的方案中,其实底层调用store的逻辑还是    this.$store.state.xxx 

但是setup 中是不存在this的,所以要使用bind属性给其设置一个this指向

直接解构(推荐)

我们一般会使用setup编写逻辑,不希望还同时使用options api,所以上述方案都不太好

可以直接解构:

  import {toRefs} from 'vue'
  import {useStore} from 'vuex'

  const store = useStore()
  const{name,age,counter} = toRefs(store.state)

这样既映射成功,还保证了其响应式

getters

基础使用

类似于options api中的computed属性,当你想对state中的状态做一些操作时,可以使用getters

import {createStore} from  'vuex'
const store = createStore({
    state:()=>{
        return{
            counter:100,
        }
    },
    getters:{
        doubleCounter(state){
            return state.counter*2
        }
    }

})
export default store

使用方法和state类似 

<h1>{{$store.getters.doubleCounter}}</h1>

getters函数同时调用getters

getters中的函数可以相互调用

import {createStore} from  'vuex'
const store = createStore({
    state:()=>{
        return{
            counter:100,
            name:'lee',
        }
    },
    getters:{
        doubleCounter(state){
            return state.counter*2
        },
//相互调用
        message(state,getters){
            return `${state.name} need ${getters.doubleCounter} yuan`
        },
    }

})
export default store

getters函数返回函数

getters中的函数可以返回函数,在调用时可以传参:

import {createStore} from  'vuex'
const store = createStore({
    state:()=>{
        return{
            friends:[
                {name:"111",age:12},
                {name:"112",age:13},
                {name:"113",age:14},
            ]
        }
    },
    getters:{
        findfriend(state){
            return function(name){
                return state.friends.find(item=>item.name == name)
            }
        }
    }
})
export default store

 findfriend函数返回了一个函数,形参是name,这个函数又通过传入的name找到对应的friend信息返回

调用时:

  <h1>{{$store.getters.findfriend(112)}}</h1>

 

getter函数映射到组件

跟state方法的方案类似,也会有三个方案,也会有mapGetters函数,这里不再赘述,只写一下最推荐的直接解构方案

  const{findfriend} = toRefs(store.getters)

Mutation

更改VUEX中状态的唯一方法是提交mutation(其实也能直接修改,但是vuex认为不规范)

基本使用

首先在store中定义mutation方法:

    mutations:{
        increment(state){
            state.counter++
        },
        changename(state){
            state.name = 'kobe'
        }
    }

在组件中使用,必须要使用.commit方法:

<template>
  <button @click="changeName">跳转到page</button>
  <h1>{{$store.state.name}}</h1>
</template>
<script>
  export default {
    methods: {
      changeName() {
        this.$store.commit('changename')
      }
    }
  }
</script>

当然也可以传入参数:

    mutations:{
        changename(state,newname){
            state.name = newname
        }
    }
<script>
  export default {
    methods: {
      changeName() {
        this.$store.commit('changename','lalla')
      }
    }
  }
</script>

映射使用

mutations也可以映射使用

同样使用  mapMutations 函数

<template>
  <button @click="changename('kobe')">跳转到page</button>
  <h1>{{$store.state.name}}</h1>
</template>
<script>
  import { useStore, mapMutations } from 'vuex'
  export default {
    methods: {
      ...mapMutations(['changename'])
    }
  }
</script>

重要原则

也就是说在mutations中不要进行异步操作,例如网络请求,如果要网络请求数据,需要用到actions

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/135159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互联网电商模式的迅速发展,消费返利模式你知道吗?

互联网电商模式的迅速发展&#xff0c;消费返利模式在市面上一直以来的引流能力相信大家都是有目共睹的&#xff0c;只不过因为近两到三年来的返利模式相关负面新闻太多&#xff0c;导致到了大众对于这种模式的一种不信任心理&#xff0c;但不可否认的是目前还是有很多消费者在…

Prompt-NLP新范式

作者&#xff1a;子苏 来源&#xff1a;投稿 编辑&#xff1a;学姐 Prompt综述论文&#xff1a;Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural Language Processing 论文作者知乎-近代自然语言处理技术发展的“第四范式” NLP技术发展…

【回答问题】ChatGPT上线了!推荐40个以上比较好的目标检测模型

推荐40个以上比较好的目标检测模型? 目标检测是指在图像中找到并标识出特定目标的计算机视觉任务。近年来&#xff0c;机器学习技术的发展使得目标检测取得了长足进步。目前有许多优秀的目标检测模型&#xff0c;下面是推荐的40个以上的比较好的目标检测模型&#xff1a; R-…

事务到底是隔离的还是不隔离的?

我在第 3 篇文章和你讲事务隔离级别的时候提到过,如果是可重复读隔离级别,事务 T 启动的时候会创建一个视图 read-view,之后事务 T 执行期间,即使有其他事务修改了数据,事务 T 看到的仍然跟在启动时看到的一样。也就是说,一个在可重复读隔离级别下执行的事务,好像与世无…

尚医通-医院列表接口-等级接口-功能测试(二十二)

目录&#xff1a; &#xff08;1&#xff09;医院列表接口-医院等级接口 &#xff08;2&#xff09;医院列表接口-远程调用 &#xff08;3&#xff09;医院列表接口-功能测试 &#xff08;1&#xff09;医院列表接口-医院等级接口 由于我们的医院等级、省市区地址都是取的数据…

BGP在数据中心的应用1——数据中心网络介绍

注&#xff1a; 本文根据《BGP in the Datacenter》整理&#xff0c;有兴趣和英文阅读能力的朋友可以直接看原文&#xff1a;https://www.oreilly.com/library/view/bgp-in-the/9781491983416/ 引子 在传统的大型数据中心&#xff0c;网络通常是三层结构。Cisco称之为&#x…

js函数之call和apply

一、含义 function test() {console.log(----) }//执行 test(); test.call() 结果一致&#xff0c;调用test()默认会调用call&#xff0c;二者效果一致&#xff0c;call省略掉了。 二、改变this指向 call还有一个很重要的功能是改变this的指向。 function Car(brand, color)…

[Java]泛型

文章目录&#x1f97d; 泛型简介&#x1f30a; 泛型的概念&#x1f30a; 使用泛型的原因&#x1f30a; 小结&#x1f30a; 类型推断&#x1f97d; 自定义泛型&#x1f30a; 自定义泛型类&#x1f30a; 自定义泛型类/泛型接口注意点&#x1f30a; 自定义泛型方法&#x1f97d; 泛…

2022HW11

文章目录任务描述-域自适应二、代码三、实验1、Simple Baseline2、Medium Baseline3、Strong Baseline任务描述-域自适应 ●想象一下&#xff0c;你想做与3D环境相关的任务&#xff0c;然后发现 ○3D图像很难标记&#xff0c;因此也很昂贵。 ○模拟图像&#xff08;如GTA-5上的…

shell-流程控制之循环

1.for创建20用户用户前缀由用户输入用户初始密码由用户输入 例如&#xff1a;test01,test10 [rootcotenos day06]# vim useradd.sh #!/bin/bash read -p "请输入用户前缀&#xff1a;" user read -p "请输入初始密码&#xff1a;" pass for ((i1;i<…

重新成长再出发

文章大纲突然的转型&#xff0c;逼自己一把也能重新成长为什么脱口秀突然火了起来&#xff1f;上天是给了你一个重新成长的机会&#xff01;2022 一些成长的点滴突然的转型&#xff0c;逼自己一把也能重新成长 年初的时候&#xff0c;航旅纵横给我弹窗问我很久没有坐飞机了怎么…

微三云陈志坤:盘点帮助企业转型到线上的模式

今/天小编给大家介绍一下泰山众筹模式系统&#xff0c;想搭建系统平台的联系微三云陈志坤。 泰山众筹模式已经走了4个多年头&#xff0c;目前仍在运行。 第一部分&#xff1a;泰山众筹模式介绍 一、无泡沫——安全长久 所有的互联网金融项目的死穴就是泡沫无法消除&#xf…

对于此版本,windows installer和即点即用的Office不能并行运行,因此只能安装一种类型(安装Visio破解版时的报错)

阅读前请看一下&#xff1a;我是一个热衷于记录的人&#xff0c;每次写博客会反复研读&#xff0c;尽量不断提升博客质量。文章设置为仅粉丝可见&#xff0c;是因为写博客确实花了不少精力。不用担心你关注我而我却不关注你&#xff0c;因为我是个诚信互关的人&#xff01;&…

gem5 arm架构 fullsystem spec2017 benchmark 仿真

gem5 system emulation 模式&#xff0c;内部实现了对system call的模拟&#xff0c;使用了一段时间后&#xff0c;有一些发现: 如果使用spec2017 X86编译&#xff0c;那么会存在对intel比较新的指令不支持的问题&#xff1b;后来使用gcc march K6 m32来解决&#xff0c;即使用…

FPGA知识汇集-FPGA配置模式和配置设计

所有现代FPGA的配置分为两类:基于SRAM的和基于非易失性的。其中&#xff0c;前者使用外部存储器来配置FPGA内的SRAM;后者只配置一次。 Lattice和Actel的FPGA使用称为反熔丝的非易失性配置技术&#xff0c;其主要优点是系统设计更加简单、不需要外部存储器和配置控制器、功耗低…

Kotlin之泛型的高级特性

Kotlin泛型中的基本用法和Java中的泛型用法是大致相同的&#xff0c;因此也比较好理解。然而实际上&#xff0c;Kotlin在泛型方面还提供了不少特有的功能&#xff0c;接下来将进行介绍。 一、对泛型进行实化 泛型实化这个功能对于绝大多数Java程序员来讲是非常陌生的&#xf…

对云台、IMU、鲁棒性和硬件时间同步的理解

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> slam是一门集硬件和软件的多科学技术&#xff0c;涉及到很多技术术语、概念以及数学公式等等。下面我将结合网上资料以及个人理解进行介绍。 什么叫云台…

navicat导入sql数据库文件的简单操作步骤

目录 前言必读 一、概念 二、操作步骤 &#xff08;一&#xff09;新建连接 &#xff08;二&#xff09;新建数据库 &#xff08;三&#xff09;数据库导入sql文件 前言必读 读者手册&#xff08;必读&#xff09;_云边的快乐猫的博客-CSDN博客 一、概念 在很多项目当…

LeetCode 309. 最佳买卖股票时机含冷冻期

309. 最佳买卖股票时机含冷冻期 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 卖出股票后&#x…

第二个岳云鹏,跨年晚会含泪主持,成为一道最靓丽的风景

中国人自古讲究&#xff1a;百善孝入先&#xff0c;尤其是对于娱乐圈的明星来说&#xff0c;孝心和爱心更是他们成功的根本。 在这方面&#xff0c;德云社的小岳岳走在了前列&#xff0c;他用自己的孝心和爱心感动了粉丝&#xff0c;也收获了无数的鲜花和掌声。小岳岳的爱心体现…