关于VueRouter导入的全过程

Elita ·
更新时间:2024-09-20
· 1119 次阅读

目录

router

nanoid的使用

引入

使用

路由

1-1 安装依赖

1-2 引入

1-3 在main.js中使用

1-4 App.vue

全局过滤器

element-ui

全局组件

Vuc-cli中的视配

1-1 安装依赖

1-2 配置文件

1-3 main.js

1-4 public/index.html

1-5 在pc端视配

slot封装动画

项目初始化

1-1 .router-link-active

1-2 动态显示tabbar

1-3 跳转回前一个页面

1-4轮播

vant ui的按需导入

1-1 安装依赖

1-2 配置babel.config.js

1-3 配置main.js

嵌套路由

1-1 router.js

1-2 index.vue

异步路由​

页面跳转和生命周期

页面跳转

DOM和生命周期

缓存的进一步封装

axios

跨域

地址值的放置

Vuex

1、state

2、mutation

3、actions

keep-alive

路由守卫

Login_guard(Vue&koa)

一、登录页面

二、后台代码

三、配置cookie跨域访问

懒加载

1、图片懒加载

2、axios拦截器

3、上拉刷新

4、路由滚动记录当前滚动条位置问题​

Vue路由跳转的bug

router nanoid的使用

​ --生成随机id

引入 yarn add nanoid 使用 import {nanoid} from 'nanoid' var id = nanoid() 路由 1-1 安装依赖 yarn add vue-router 1-2 引入

router/index.js 

import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import Movie from '../pages/Movie/index.vue' import Music from '../pages/Music/index.vue' const routes = [ { path:"/music", component:Music }, { path:"/movie", component:Movie } ] const router = new VueRouter({ routes, mode:"history" }) export default router; 1-3 在main.js中使用 import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({   router,   render: h => h(App), }).$mount('#app') 1-4 App.vue <template>   <div>     <router-view></router-view>   </div> </template> 全局过滤器

在main.js中挂载在Vue原型上

Vue.filter("handleStr",function(val){   if(val.length > 3){     val = val.slice(0,3) + '...'   }   return val }) element-ui

安装依赖

yarn add element-ui

main.js

.... import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); ... 全局组件 import Loading from '../components/Loading.vue' Vue.component("Loading",Loading) Vuc-cli中的视配

只在手机端

lib-flexible 阿里 1-1 安装依赖 yarn add lib-flexible postcss-pxtorem@5.1.1 1-2 配置文件

新建postcss.config.js

module.exports = {   plugins: {     'postcss-pxtorem': {       rootValue: 75,       propList: ['*'],     },   }, }; 1-3 main.js

导入lib-flexible

import 'lib-flexible/flexible.js' 1-4 public/index.html

将此行注释,关闭视口

<meta name="viewport" content="width=device-width,initial-scale=1.0"> 1-5 在pc端视配 <template>   <div id="app">     ...   </div> </template> <script>     ... </script> <style> *{   margin: 0;   padding: 0; } #app{   width: 10rem;   margin: 0 auto;   background-color: red; } </style> slot封装动画 // #1 定义一个组件 <template>   <transition>     <slot name="fade"></slot>   </transition> </template> <script> export default { } </script> <style> .v-enter,.v-leave-to{   opacity: 0; } .v-enter-active,.v-leave-active{   transition: opacity 4s; } </style> // #2 使用 <template>   <div class="about">     <Fade>       <h1 slot="fade" v-show="isShow">This is an about page</h1>     </Fade>   </div> </template> <script> import Fade from '../components/Fade.vue' export default {   data() {     return {       isShow:true     }   },   components:{     Fade   } } </script> 项目初始化 1、rem 2、asssreset.css 1-1 .router-link-active

被选中的路由样式

.router-link-active{     color: #ff2d51;   } 1-2 动态显示tabbar

​ – 在路由配置中增加一条meta属性

const routes = [   {     path: '/films',     name: 'Films',     component:Films,     meta:{       isNav:true     }   },   {     path: '/article',     name: 'Article',     component:Article,     meta:{       isNav:true     }   },   {     path: '/center',     name: 'Center',     component:Center,     meta:{       isNav:true     }   },   {     path:"/movie/:id",     name:'MovieDetail',     component:MovieDetail   } ]

通过v-if动态显示

<tab-bar v-if="this.$route.meta.isNav"></tab-bar> 1-3 跳转回前一个页面 this.$router.back() 1-4轮播 yarn add vue-preview import VuePreview from 'vue-preview' Vue.use(VuePreview) vant ui的按需导入 1-1 安装依赖 yarn add vant babel-plugin-import 1-2 配置babel.config.js module.exports = {   presets: [     '@vue/cli-plugin-babel/preset'   ],   plugins: [     ["import", {       "libraryName": "vant",       "libraryDirectory": "es",       "style": true     }]   ] } 1-3 配置main.js import {Button} from 'vant' Vue.use(Button)

router-view实现动画

<template>   <div>     <div class="cover" v-if="isShow"></div>     <transition        @before-enter="handleBeforeEnter"       @enter="handleEnter"     >       <slot></slot>     </transition>   </div> </template> <script> /*  .v-enter              @before-enter .v-ernter-active      @enter .v-enter-to           @after-enter */   export default {     data() {       return {         isShow:false       }     },     methods:{       handleBeforeEnter(){         this.isShow = true       },       handleEnter(){         setTimeout(() => {           this.isShow = false         }, 200);       }     }   } </script> <style>   .v-enter-active{     animation: animate 2s linear;   }   @keyframes animate {     0%{       opacity: 0;       transform: translateY(0px);     }     50%{       opacity: .5;       transform: translateY(20px);     }     100%{       opacity: 1;       transform: translateY(0px);     }   }   .cover{     width: 100%;     height: 100%;     background-color: #fff;     position: fixed;     z-index: 10;   } </style> 嵌套路由 1-1 router.js  {     path: '/films',     name: 'Films',     component:Films,     meta:{       isNav:true     },     children:[       {         path:"nowPlaying",         component:NowPlaying       }     ]   }, 1-2 index.vue

需要加入router-view

<template>     ...     <div class="container">         <!-- 装载父路由下的子路由的对应 -->         <router-view></router-view>     </div> </template> 异步路由​

--又称路由懒加载

{     path: '/about',     name: 'About',     // 异步路由     component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') },

怎么减少首屏渲染时间

1、使用异步路由 

页面跳转和生命周期

​ --面试常客

页面跳转

1-1 A页面初次加载

beforeCreate(){     console.log('beforeCreate'); }, created(){     console.log('created'); }, beforeMount(){     console.log('beforeMount'); }, mounted(){     console.log('mounted'); },

1-2 A->B

从A页面跳转到B页面

A页面触发以下生命周期

beforeDestroy(){     console.log('beforeDestroy'); }, destroyed(){     console.log('destroyed'); }

1-3 B–>A

从B页面回到A页面

A页面触发以下生命周期

beforeCreate(){     console.log('beforeCreate'); }, created(){     console.log('created'); }, beforeMount(){     console.log('beforeMount'); }, mounted(){     console.log('mounted'); },

upDate

beforeUpdate , beforeUpdate执行需要满足以下两个条件

1、data中的数据更新的时候

2、模板中要使用data中的数据

destroyed

# A页面 --> b页面

b页面执行以下生命周期:

1.beforeCreate        B

2.created            B

3.beforeMount        B

4.beforeDestroy        A

5.destroyed            A

6.mounted            B

DOM和生命周期

只能在mounted生命周期中获取DOM

缓存的进一步封装

localStorage.setItem() 函数会将对象或者数组全部转换成字符串的形式

所以可以对缓存进行判断,使用 JSON.stringify 和 JSON.parse 分别处理数据

const setLocalStorage = (key , value) => {   if(value instanceof Array || value instanceof Object){     value = JSON.stringify(value)   }   localStorage.setItem(key , value) } const getLocalStorage = (key) =>{   var val = localStorage.getItem(key)   var reg = /^[[{].*[\]}]/   if(reg.test(val)){     val = JSON.parse(val)   }   return val } axios 跨域

安装依赖

yarn add axios-jsonp

axios格式

import axios from 'axios' import jsonpAdapter from 'axios-jsonp' axios({     url:"",     adapter: jsonpAdapter, }).then(     res => console.log(res) )

腾讯地图api需要在最后加上 &output=jsonp

https://apis.map.qq.com/ws/location/v1/ip?key=L6UBZ-JSLCU-FRAVA-4DBQG-V5WC5-2RBJ4&output=jsonp 地址值的放置 http://47.108.197.28:3000/top/playlist?limit=1&offset=1

在小程序中

wx.request({ })

axios中

import axios from 'axios' axios({     url:"http://47.108.197.28:3000/top/playlist",     method:"get",     params:{     limit:1     } }).then(res=>{     console.log(res) }) Vuex import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({   state: {   },   mutations: {   },   actions: {   },   modules: {   } }) 1、state

​ --state中存放的是数据

state: {     num:10 } this.$store.state 2、mutation

​ --mutation中的函数第一个默认参数是state

​ --连接方式 commit

mutations: {     add(state){         console.log(state);         state.num++;     } }, this.$store.commit('add') 3、actions

​ --actions中的函数第一个默认值是上下文

​ --连接方式 dispatch

actions: {     addNum(ctx){         console.log(ctx);         ctx.commit("add")     } }, this.$store.dispatch('a') keep-alive

使用keep-alive之后,路由切换的时候,生命周期函数不会重复的触发

组件不会被销毁,而是被缓存起来。当加载到对应的路由页面,缓存的组件会被加载

路由组件的两个生命周期函数

/* 路由组件被激活时触发。 */ activated(){     console.log('activated') } /* 路由组件失活时触发。 */ deactivated(){     console.log('deactivated') } 路由守卫

全局路由守卫

router.beforeEach((to , from ,next)=>{   console.log(to);    // 要跳转的路由   console.log(from);  // 起点路由   next(); }) Login_guard(Vue&koa) 一、登录页面 <template>   <div>     <el-form       :model="ruleForm"       status-icon       :rules="rules"       ref="ruleForm"       label-width="100px"       class="demo-ruleForm"     >     <!-- props为了规则校验 rules -->     <el-form-item label="用户名" prop="username">         <el-input  type="text" v-model.number="ruleForm.username"></el-input>       </el-form-item>       <el-form-item label="密码" prop="pass">         <el-input           type="password"           v-model="ruleForm.pass"           autocomplete="off"         ></el-input>       </el-form-item>       <el-form-item label="确认密码" prop="checkPass">         <el-input           type="password"           v-model="ruleForm.checkPass"           autocomplete="off"         ></el-input>       </el-form-item>       <el-form-item>         <el-button type="primary" @click="submitForm('ruleForm')"           >提交</el-button         >         <el-button @click="resetForm('ruleForm')">重置</el-button>       </el-form-item>     </el-form>   </div> </template> <script> export default {   // beforeRouteEnter () {   //   /* 在局部守卫中获取不到this */   //   console.log(1);   // },   data() {     var checkUsername = (rule, value, callback) => {       if (!value) {         return callback(new Error("用户名不能为空"));       }else{         callback();       }     };     var validatePass = (rule, value, callback) => {       if (value === "") {         callback(new Error("请输入密码"));       } else {         if (this.ruleForm.checkPass !== "") {           this.$refs.ruleForm.validateField("checkPass");         }         callback();       }     };     var validatePass2 = (rule, value, callback) => {       if (value === "") {         callback(new Error("请再次输入密码"));       } else if (value !== this.ruleForm.pass) {         callback(new Error("两次输入密码不一致!"));       } else {         callback();       }     };     return {       ruleForm: {         pass: "",         checkPass: "",         username: "",       },       rules: {         pass: [{ validator: validatePass, trigger: "blur" }],         checkPass: [{ validator: validatePass2, trigger: "blur" }],         username: [{ validator: checkUsername, trigger: "blur" }],       },     };   },   methods: {     submitForm(formName) {       this.$refs[formName].validate((valid) => {         if (valid) {           // alert("submit!");           // console.log(this.ruleForm);           // console.log(username,pass);           /* 发送http请求 */           this.loginHttp()         } else {           console.log("error submit!!");           return false;         }       });     },     resetForm(formName) {       this.$refs[formName].resetFields();     },     loginHttp(){       var {username , pass} = this.ruleForm       this.$http({         method: 'post',         url:'http://localhost:8000/login',         data:{           username,           pass         }       }).then(res=>{         console.log(res.data);         if(res.data.code == 200){           this.$message({             message:res.data.msg,             type:"success",             duration:1000           })           this.$router.push('/home')         }else{           this.$message({             message:res.data.msg,             type:"warning",             duration:1000           })         }       })     }   } }; </script> 二、后台代码 const koa = require("koa"); const app =  new koa(); const koaBody = require("koa-body"); const router = require("koa-router")(); const cors = require("koa2-cors");     /* username=cheng  pass=123456 */     console.log(ctx.request.body);     var {username , pass } = ctx.request.body     if(username == "cheng" && pass == "123456"){       ctx.cookies.set("loginAuth",true,{         /* httpOnly:false   设置前端可读 */         httpOnly:false       })       ctx.body = {         code:200,         msg:"登录成功"       }     }else{       ctx.body = {         code:400,         msg:"登录失败,用户名或密码错误"       }     } }) /* 后端配置cookie可以实现跨域访问 */ app.use(cors({   origin:ctx =>{     return ctx.headers.origin   },   credentials:true })); app.use(koaBody()); app.use(router.routes()); app.listen(8000); 三、配置cookie跨域访问

3-1 配置后端cookie可以访问

/* 后端配置cookie可以实现跨域访问 */ app.use(cors({   origin:ctx =>{     return ctx.headers.origin   },   credentials:true }));

3-2 配置前端跨域访问cookie

import axios from 'axios' /* 设置前端跨域访问cookie */ axios.defaults.withCredentials = true axios.defaults.crossDomain = true

3-3 vue上获取cookie

安装依赖

yarn add vue-cookie

配置main.js

import VueCookie from 'vue-cookie' Vue.use(VueCookie)

在页面中获取cookie

mounted() {     console.log(this.$cookie.get('loginAuth')); }

3-4 路由守卫

​ --没有登录的情况下,不能进入其它页面

​ --已经登录的情况下,直接进入首页

var vm = new Vue(); router.beforeEach((to,from,next)=>{   console.log(vm.$cookie.get('loginAuth'));   var isLogin = vm.$cookie.get('loginAuth')   if(to.path == "/login"){     /* 1、登录页面,如果cookie显示登录了直接进入home页面,如果没有登录,正产执行login页的逻辑 */     if(isLogin){       router.push('/home')     }else{       next()     }   }else{     /* 2、在其他页面,如果登录正常显示,没有登录则停留在login页面 */     if(isLogin){       next()     }else{       router.push('/login')     }   } }) 懒加载 1、图片懒加载

安装依赖

yarn add vue-lazyload

在main.js中进行配置

import VueLazyLoad from 'vue-lazyload' Vue.use(VueLazyLoad,{   preLoad:1.3,   loading:require('@/assets/loading.gif') })

使用(将:src替换成v-lazy)

<template>   <div class="home">     <div  v-for="item of playlists" :key="item.id">       <img  class="item" v-lazy="item.coverImgUrl" alt="">       <p>{{item.name}}</p>     </div>   </div> </template> 2、axios拦截器

​ --实现loading的加载效果

在vuex中定义一条isShowLoading     -->    设置加载条是否显示

export default new Vuex.Store({   state: {     isSowLoading:true   }, })

main.js

// 配置 请求拦截 和 响应拦截 // 添加请求拦截器 axios.interceptors.request.use(function (config) {   // 在发送请求之前做些什么   store.state.isSowLoading = true   return config; }); // 添加响应拦截器 axios.interceptors.response.use(function (response) {   // 2xx 范围内的状态码都会触发该函数。   // 对响应数据做点什么   store.state.isSowLoading = false   return response; });

App.vue设置loading

<template>   <div id="app">     <Loading v-if="this.$store.state.isShowLoading"/>     <router-view/>   </div> </template> 3、上拉刷新

vant-ui 中整合了小程序中的 onBottom 和 onLoad

<template>   <div class="home">     <van-list       class="home"       v-model="loading"       :finished="finished"       finished-text="没有更多了"       @load="onLoad"     >       <van-cell @click="handleClick(item.id)" v-for="item of playlists" :key="item.id">         <img class="item" v-lazy="item.coverImgUrl" alt="">         <p>{{item.name}}</p>       </van-cell>     </van-list>   </div> </template> <script> export default {   name: 'Home',   data() {     return {       playlists:[],       loading:false,       finished:false     }   },   mounted() {   },   methods: {     onLoad(){       setTimeout(()=>{         var offset = this.playlists.length         console.log(1);         this.axios.get(`http://47.108.197.28:3000/top/playlist?offset=${offset}&limit=20`).then(res =>{           var playlists = this.playlists.concat(res.data.playlists)           this.playlists = playlists           this.loading = false         })       },500)     },     handleClick(id){       this.$router.push(`detail?id=${id}`)     }   }, } </script> <style scoped>   .item{     width: 150px;     height: 150px;   }   .home{     display: flex;     justify-content: space-between;     flex-wrap: wrap;   }   .van-cell{     width: 150px;   }   .home >>> .van-list__loading{     position: fixed;     bottom: 0;     left: 50%;     transform:translateX(-50%);   } </style> 4、路由滚动记录当前滚动条位置问题​

在路由设置中,重置滚动条的x,y

const router = new VueRouter({   ...   scrollBehavior (to , from , savedPosition) {     if( to.path == "/detail"){       return {x:0,y:0}    // 让页面出于顶部     }else{       return savedPosition    // 让页面出于记录点     }   } }) Vue路由跳转的bug

项目中遇到如下报错内容:

Uncaught (in promise) Error: Redirected when going from “/XXX” to “/XXX” via a navigation guard.

原因:vue-路由版本更新产生的问题,导致路由跳转失败抛出该错误,但并不影响程序功能

在main.js中改变push原型

import Router from 'vue-router' const originalPush = Router.prototype.push Router.prototype.push = function push(location, onResolve, onReject) {   if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)   return originalPush.call(this, location).catch(err => err) }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持软件开发网。



需要 登录 后方可回复, 如果你还没有账号请 注册新账号