VueRouter 前端路由
-
Vue路由Vue-Router是一个路由插件,能够轻松管理SPA项目中组件的切换,适合制作单页面组件切换的项目
-
Vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件的访问映射起来
-
vue-router3是专门为vue2开发的
-
安装
npm install vue-router@3 -
官网 https://router.vuejs.org/zh/
创建路由组件
在项目中定义一些组件,使用vue-router来控制它们的展示和切换
-
在主页上声明路由连接,这些连接在点击后会在主页的url后加/#/来访问设置的连接
-
设置一个占位符,router可以将选中的组件显示在这里
<template> <div id="app"> <!-- 声明路由连接,跳转时在路径后加# --> <router-link to="/discover">发现</router-link> <router-link to="/my">我的</router-link> <router-link to="/follow">关注</router-link> <!-- 声明路由占位符标签,当通过路径找到对应组件时,对应的组件渲染到占位符这里 --> <router-view></router-view> </div> </template> -
设置不同的组件,对应路由连接的组件
<template> <div> <h1>发现</h1> </div> </template> <template> <div> <h1>关注</h1> </div> </template> <template> <div> <h1>我的</h1> </div> </template> -
建立一个router文件夹,创建js文件来管理路由连接和组件的映射关系
- 导入vue和vue-router
- 导入路由连接需要的组件
- 设置Vue-Router为Vue的插件
- 创建一个VueRouter对象,其中设置routes列表,使用path和component表示路由连接和组件的映射
- 导出router,在main.js中导入
// 在另外的js文件中描述路由跳转,导入Vue和VueRouter import VueRouter from "vue-router"; import Vue from 'vue'; // 导入自定义的组件 import Discover from '../components/Discover.vue' import Follow from "../components/Follow.vue" import My from "../components/My.vue" //将VueRouter设置为Vue的插件 Vue.use(VueRouter) //创建vueRouter类 const router = new VueRouter({ // 设置路径对应的组件 routes: [ {path: '/discover', component: Discover}, {path: '/follow', component: Follow}, {path: '/my', component: My}, ] }) //导出router,需要在main.js中加载 export default router; -
在main.js中导入router
import Vue from 'vue' import App from './App.vue' // 导入router import router from './router' Vue.config.productionTip = false new Vue({ render: h => h(App), //设置对应的router router:router }).$mount('#app')
路由重定向
使得用户访问时,可以自动被重定向到其他页面
const router = new VueRouter({
routes: [
//将首页重定向到discover,vue-router4不配置重定向则中默认跳转到第一条路由连接
{path: '/', redirect: 'discover'},
{path: '/discover', component: Discover},
{path: '/follow', component: Follow},
{path: '/my', component: My},
]
})
嵌套路由
在一个被路由管理的组件中仍然可以写其他路由
<template>
<div>
<h1>发现</h1>
<!-- 设置子路由,名称可以每增加一层路由就带上一次路由的前缀 -->
<router-link to="/discover/toplist">排行榜</router-link>
<router-link to="/discover/playlist">歌单</router-link>
<hr>
<router-view></router-view>
</div>
</template>
在多层路径嵌套路由的情况下,通过在routes里的条目增加一个children来设置对应的路由,可以省略前缀
const router = new VueRouter({
routes: [
{path: '/', redirect: '/discover'},
// 使用children的方式,在path前缀的基础上导入子路由,注意没有斜杠
{path: '/discover', component: Discover,
children:[
{path: 'playlist', component: Playlist},
{path: 'toplist', component: Toplist},
]},
{path: '/follow', component: Follow},
{path: '/my', component: My},
//直接按全路径导入子路由,会覆盖上层的组件
// {path: '/discover/toplist', component: Toplist}
]
})
动态路由
动态路由是指,把路由地址中的某些可变部分定义为参数项,从而提高路由的复用性,可以使用冒号来定义一个参数项,这个参数项指的是路由路径中的一部分,并且可以通过route.params.名称 在跳转的组件中获取
<template>
<div>
<h1>我的</h1>
<router-link to="/my/1">歌曲1</router-link>
<router-link to="/my/2">歌曲2</router-link>
<router-view></router-view>
</div>
</template>
<template>
<!--通过route.param.名称 可以获取路由时动态设置路径位置的参数 -->
<h4>歌曲{{$route.params.id}} 播放中</h4>
</template>
const router = new VueRouter({
routes: [
{path: '/my', component: My, children:[
// 通过:来定义不同访问路径,但都跳转到一个组件,这个参数可以通过route.params.名称 在跳转到的组件中获取
{path: ':id', component:Product}
]},
]
})
另一种获取参数的方式是,在目标组件中定义一个参数,在路由映射时设置props = true,就会把参数传递
<template>
<p>{{id}}</p>
</template>
<script>
export default {
props:['id'],
}
</script>
const router = new VueRouter({
// 设置路径对应的组件
routes: [
{path: '/my', component: My, children:[
// 通过:来定义不同访问路径,但都跳转到一个组件,设置props为true使得参数直接被传递,但目标组件中也要设置对应的props有该名称的参数
{path: ':id', component:Product, props: true}
]},
]
})
导航守卫
可以用来控制路由的访问权限,拦截每一个路由规则,从而进行访问权限的判断
使用router.beforeEach可以使用一个全局前置守卫
router.beforeEach((to,from,next) =>{
if(to.path === '/main' && !isAuthenticated) {
next('/login')
}else{
next()
}
})
- to:正在请求访问的目标
- from:正处于且准备离开的路由
- 如果在守卫方法中声明了next形参,则必须调用next,否则所有路由都无法访问
- next():放行
- next(false): 强制停留在当前页面
- next(‘/login’): 强制跳转到一个路由页面
Vuex
-
大型应用有时需要跨越多个组件,只通过父子组件间传递会很困难,所以需要一个全局的状态管理器
-
Vuex是一个专门为vue开发的应用程序状态管理库,采用集中式存储管理用于的所有组件的状态,用Vuex就可以管理在各个组件中的数据
-
安装
npm install vuex@next
状态管理
- Vuex核心是一个store,当store中的数据发生变化时,与之绑定的视图也会被重新渲染
- store中的状态不允许直接修改,改变store中的状态的唯一途径就是显式提交(commit) mutation,这样可以简单的追踪状态的变化
- vuex中有5个重要的概念,State, Getter, Mutation, Action和Module
- Vue组件可以读state中的数据并渲染到视图
- 网络请求是通过DIspatch触发Actions,由Actions完成获取数据
- 当获取到数据后,Actions需要Commit到Mutaations,更新数据
- Mutation更新后,再去修改State中的数据
State
-
创建一个新的store示例,并把需要使用的数据传入state
const store = createStore({ state () { return { count : 0 } } }), mutations: { increment (state) { state.count++ } } -
在组件中,使用this.$store.state.名称访问数据,也可以使用mapState辅助函数将其映射
import {mapState} from 'vuex' export default { computed: mapState({ count: state => state.count, countAlias: 'count', countPlusLocalState(state) { return state.count + this.localcount } }) }
Mutation
-
在组件中,使用store.commit来提交mutation
methods: { increment(){ this.$store.commit('increment') } } -
也可以使用mapMutation辅助函数将其映射下来
Action
-
类似于Mutation,但Action不能直接修改状态,只能通过mutation修改,并且包含异步操作
const store = createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
Getter
-
Getter维护由State派生的一些状态,随着State的状态变化和变化
const store = createStore({ state: { todos: [ {id: 1, text: '...', done: true}, {id: 2, text: '...', done: false} ] }, getters: { doneTodos: (state) => { return state.todos.filter(todo => todo.done) } } }) -
在组件中可以直接使用this.$store.getters.名称,也可以使用mapgetters辅助函数映射
使用示例
-
在main.js中导入并use
import Vuex from 'vuex' Vue.use(Vuex) -
单独创建一个js文件,一般放在store文件夹下,并导出store
const store = new Vuex.Store({ state: { count: 1, }, }) // 导出创建的store export default store -
在main.js中注册这个store,使得其可以在所有文件中使用$store.state.名称 访问
new Vue({ router, //注册store store:store, render: h => h(App) }).$mount('#app') -
如果需要更新数据,应该在mutations中定义一个专属的方法,并且在对应组件的method方法中触发这个方法即可,使用this.$store.commit(方法名称)即可
const store = new Vuex.Store({ state: { count: 1, }, mutations: { increment (state) { state.count++ } } }) export default store<template> <div class="hello"> {{ this.$store.state.count }}<br> <button @click="add">+1</button> </div> </template> <script> export default { name: 'HelloWorld', props: { msg: String }, methods:{ add(){ // 可以这样做,但不推荐,应该在mutations中定义一个方法,再去触发mutation中的方法 // this.$store.state.count++ //这样就可以调用mutation对应的方法,使用vuex统一管理数据 this.$store.commit("increment") } } } </script> -
Vuex中有一个computed称为计算属性,可以基于数据进行操作,可以对数据进行监听;在其中设置一些函数,函数中使用vuex的数据,当vuex数据发生变化时,该方法被重新计算并和视图关联渲染;在需要渲染的地方直接使用该函数即可
<template> <div class="hello"> <!-- {{ this.$store.state.count }}<br> --> {{ count }} <button @click="add">+1</button> </div> </template> <script> export default { name: 'HelloWorld', computed: { count() { return this.$store.state.count } }, methods:{ add(){ this.$store.commit("increment") } } } </script>-
mapState辅助函数可以帮助我们将数据映射到computed中去
-
在组件中导入
import {mapState} from 'vuex' -
重写computed,使用computed:mapState({})的以下几种方式
export default { name: 'HelloWorld', props: { msg: String }, computed: mapState({ //最简单,直接让state中的属性可以被访问 // 'count', // 使用箭头函数来获取值 count: state => state.count, // 使用字符串来获取对应的值,和上面的效果相同,相当于别名 countAlias: 'count', //也可以是一个常规函数来处理数据 countPlusLocalState (state) { return state.count } }), methods:{ add(){ this.$store.commit("increment") } } }
-
-
-
Getter可以处理和过滤一些派生数据,如过滤待办事项中已完成和未完成的任务
const store = new Vuex.Store({ state: { count: 1, // 添加一些待办事项 todos:[ {id:1,text:"事件1",done:true}, {id:2,text:"事件2",done:false} ], }, mutations: { increment (state) { state.count++ } }, // 设置getters,在getters中写一些方法,使得这个方法返回的数据是被筛选和处理过的 getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } }) export default storeimport {mapState} from 'vuex' <template> <div class="hello"> <!-- {{ this.$store.state.count }}<br> --> {{ count }} <button @click="add">+1</button> <ul> <li v-for="todo in doneTodos" :key="todo.id">{{ todo.text }}</li> </ul> </div> </template> <script> import { mapGetters, mapState } from 'vuex'; export default { name: 'HelloWorld', props: { msg: String }, computed: { //因为要嵌套mapGetter,所以需要在computed后加一个括号,使用...展开mapState对象 ...mapState( ['count','todos' ]), ...mapGetters([ 'doneTodos' ]), }, methods:{ add(){ this.$store.commit("increment") } } } </script> -
mutation也可以进行映射,也可以携带参数payLoad载荷
methods:{ add(){ //在这里传入一个参数 this.$store.commit("increment",2) } } }-
在组件中提交mutation时,可以使用mapMutation把方法映射为组件自己的方法
methods:{ ...mapMutations([ //将this.$store.commit("increment")映射为this.increment() 'increment', ]), add(){ this.$store.commit("increment",2) } }
-
-
Action主要是做异步操作和提交Mutation,携带一个context参数,用来调用mutation中的方法,需要使用store.dispatch(mutation中的方法)进行触发
- 也可以使用MapAction来映射成自己的方法,和mapMutation的写法一致
Module
在应用复杂时,可以使用module来定义store,每个模块都可以有自己的state,mutation,action和getters
const moduleA = {
state:( => {}),
mutations:{},
actions:{},
getters{}
}
//合并store
const store = new Vuex.Store({
modules: {
//访问时加上某个模块的名称即可访问模块的store
a : modulesA,
}
})
//访问模块store
store.state.a
Mock.js
-
这是一款前端中用来拦截ajax请求再生成随机数据响应的工具,可以用来模拟服务器响应
-
非常方便,无侵入性,基本覆盖常用的接口数据类型
-
支持随机文本,数字,布尔值,日期,邮箱,链接,图片,颜色等
-
安装
npm install mockjs -
使用
//引入mockjs import Mock from 'mockjs' //使用mockjs模拟数据 Mock.mock('/user', { "count": 0, "data":{ "time": "@datetime", //生成随机日期 "score|1-800": 800, //随机生成1-800的数字 "username": "@cname" //随机生成名字 } })前端可以按照axios原本的方法发送请求,但是如果项目中使用了mock就会返回自己定义的返回值
Mock核心功能
Mock.mock(rurl?,rtype?,template|function(options))
-
rurl,表示需要拦截的url,可以使用正则
-
rtype,表示需要拦截的Ajax请求类型,如GET/POST
-
template,表示数据模板,可以是对象或者字符串
-
function,表示用于生成响应数据的函数
-
设置延时
Mock.setup({ timeout: '200-400' //设置延时响应的范围 })
使用演示
-
在main.js中导入mockjs,当真正使用后端时取消导入即可
//导入mock import './mock' -
新建一个文件夹,设置一个对应的js文件来设置mock
import Mock from 'mockjs' Mock.mock('/user/all',{ "count" : 2, "data" : { "username": "@cname", "createtime": "@datetime", "score|40-100": 1, // 生成一张图片,参数为尺寸、背景、文字颜色、格式、文字内容 "img":"@image('100x100','#ff0066','#ff6600','png','Yan')" } }) -
在业务代码中正常使用Axios发送请求即可,只要请求路径和mock设置的拦截路径一致,就会被mock拦截并返回数据模板
<template> <div id="app"> <!-- 显示随机生成的图片,把生成的图片赋值给自己的数据即可 --> <img alt="Vue logo" :src="img"> </div> </template> <script> import Axios from "axios" export default { name: 'App', data:function(){ return { "img":"" } }, mounted:function(){ // 正常发送axios请求,地址和mock拦截的地址一致 Axios.get("/user/all").then(response =>{ console.log(response) //注意此时,reponse的第一个data是自身的属性,第二个才是自定义的属性 this.img = response.data.data.img }) }, } </script>
Mock数据生成规则
mock的语法包括两层规范,数据模板和数据占位符
数据模板DTD
基本语法是,name为名称,rule为生成规则,value是对应的值
'name|rule' : value
生成规则
-
生成字符串
//重复字符串string生成数据,min是最小值,max是最大值, 'name|min-max': string //重复固定次数count的string生成数据 'name|count' -
生成数字
//每次生成一个自增的数字,number为初始值 'name|+1': number //生成一个min到max的数字,number只是用来确定类型 'name|min-max': number //按范围生成数组,通过dmin和dmax确定保留小数的位数,这是一个浮点数 'name|min-max.dmin-dmax' -
生成布尔类型
//生成布尔值,概率各为二分之一 'name|1':boolean //生成布尔值,值为value的概率为min/(min+max) 'name|min-max':value -
生成对象值
var obj = { a: 1, b: 2, } var data = Mock.mock({ 'name|1-3': obj, //从obj中找1-3个属性 'name|2':obj }) -
生成列表
'name|1': array //选取array中的一个元素返回 'name|+1' array //顺序选取array中的一个元素返回 'name|min-max':array //随机重复array后返回 'name|count':array //重复一定次数后返回
数据占位符
使用@符号来生成一些随机的数据,这些占位符会调用内部的Mock.Random类来生成一些随机的数据
"@datetime" //生成随机日期
"@natural(1,800)" //范围随机数
"@cname" //随机姓名
匹配携带数据的请求
如果请求中携带了参数,那么只写请求路径是不能被mock捕获的,所以需要使用一个正则来匹配请求
Mock.mock(RegExp('/user/all.*').{
})
766

被折叠的 条评论
为什么被折叠?



