Vue八股笔记自用2

86 阅读5分钟

路由

Vue-router的懒加载如何实现

  1. 箭头函数+import动态加载
const List = () => import('@/components/list.vue')
const router = new VueRouter({
  routes: [
    { path: '/list', component: List }
  ]
})
  1. 箭头函数+require动态加载
const router = new Router({
  routes: [
   {
     path: '/list',
     component: resolve => require(['@/components/list'], resolve)
   }
  ]
})
  1. 方案三:使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
// r就是resolve
const List = r => require.ensure([], () => r(require('@/components/list')), 'list');
// 路由也是正常的写法  这种是官方推荐的写的 按模块划分懒加载 
const router = new Router({
  routes: [
  {
    path: '/list',
    component: List,
    name: 'list'
  }
 ]
}))

如何获取页面的hash变化

  1. 监听$route的变化
  2. window.location.hash读取#值

$route$router的区别

  • $route是路由信息对象,包括path, params, hash, query, fullPath, matched, name等参数。
  • $router是路由实例对象,包括了路由的跳转方法,钩子函数等

hash和history

  • hash模式实际上是通过window.addEventListener('hashchange')监听hash值的变化,从而让vue-router渲染对应的组件
  • history模式是利用history..pushState()这个状态,通过状态变化通知router呈现的组件。

如何定义动态路由,如何获取传过来的动态参数。

  1. params方式
  • 配置路由格式/router/:id
  • 传递的方式:在path后面跟上对应的值
//在APP.vue中
<router-link :to="'/user/'+userId" replace>用户</router-link>    

//在index.js
{
   path: '/user/:userid',
   component: User,
},
// 方法1:
<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link

// 方法2:
this.$router.push({name:'users',params:{uname:wade}})

// 方法3:
this.$router.push('/user/' + wade)
  1. query方式
  • 在对象中使用query的key作为传输方式
  • 传递后形成的路径:/route?key=value
//方式1:直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>

// 方式2:写成按钮以点击事件形式
<button @click='profileClick'>我的</button>    

profileClick(){
  this.$router.push({
    path: "/profile",
    query: {
        name: "kobi",
        age: "28",
        height: 198
    }
  });
}

vue-router路由钩子

  1. 全局路由钩子 Vue-router全局有三个路由钩子;
  • router.beforeEach 全局前置守卫,进入路由之前
  • router.beforeResolve 全局解析守卫 在beforeRouteEnter调用之后调用
  • router.afterEach 全局后置钩子 进入路由之后
    具体使用:
  • beforeEach(判断是否登录,没登陆就跳到登录页)
router.beforeEach((to, from, next) => {  
    let ifInfo = Vue.prototype.$common.getSession('userData');  // 判断是否登录的存储信息
    if (!ifInfo) { 
        // sessionStorage里没有储存user信息    
        if (to.path == '/') { 
            //如果是登录页面路径,就直接next()      
            next();    
        } else { 
            //不然就跳转到登录      
            Message.warning("请重新登录!");     
            window.location.href = Vue.prototype.$loginUrl;    
        }  
    } else {    
        return next();  
    }
})
  • afterEach (跳转之后滚动条返回顶部)
router.afterEach((to, from) => {
    window.scrollTo(0, 0)
})
  1. 单个路由独享钩子 beforeEnter如果不想全局配置守卫的话,可以为某些路由单独配置守卫,有三个参数:to, from, next
export default [    
    {        
        path: '/',        
        name: 'login',        
        component: login,        
        beforeEnter: (to, from, next) => {          
            console.log('即将进入登录页面')          
            next()        
        }    
    }
]
  1. 组件内钩子 beforeRouteUpdate, beforeRouteEnter, beforeRouteLeave 这三个钩子都有参数:to, from, next
  • beforeRouteEnter: 进入组件前触发
  • beforeRouteUpdate: 当前地址改变并且该组件被复用时触发,举例来说,带有动态参数的路径foo/:id, 在/foo/1和/foo/2之间跳转时,由于会渲染同样的foa组件,这个钩子在这种情况下就会被调用
  • beforeRouteLeave:离开组件被调用
  1. 触发钩子的完整顺序
  • beforeRouteLeave:路由组件的组件离开路由前钩子,可以取消路由离开
  • beforeEach:路由全局前置首位i,可用于登录验证、全局路由loading等
  • beforeEnter:路由独享守卫
  • beforeRouteEnter:路由组件的组件进入路由前钩子
  • beforeResolve: 路由全局解析守卫
  • afterEach: 路由全局后置钩子
  • beforeCreate -> created -> beforeMount -> deactivated ->mounted -> activated
  • 执行beforeRouteEnter回调函数next

vue-router跳转和Location.href的区别

  • location.href跳转刷新页面 而vue-router跳转不会
  • router.push(/url)跳转,使用了diff算法,实现了按需加载,减少了dom的损耗

params 和 query 区别

query刷新不丢失而params刷新丢失

Vuex

  • Vuex中的状态存储是响应式的,当Vue组件从store读取状态时,若store中的状态发生变化,那么相应的组件也会更新
  • 改变store中的状态的唯一途径就是显式的提交(commit)mutation。这样可以方便地跟踪每一个状态的变化。

image.png

  • Vue Components时vue组件,组件会触发(dispatch)一些事件或动作,也就是图中的actions;
  • 在vuex中,actions会把组件发来的动作提交(commit)到Mutations中
  • 然后mutations就去改变(mutate) state里的数据
  • state中的数据被改变后,就会重新render到vue components中,组件展示更新后的数据。
  • actions负责处理Vue components接收到的所有交互行为。包含同步异步操作,向后台请求api的操作就在这个模块中进行,该模块支持action的链式触发。
  • getters类似于组件中的computed,可以对state的数据进行一些处理,且也是响应式的。

vuex的简单应用

登陆前,state里的userInfo为空,登陆后存入
下面就是在created中调用函数,而函数向actions dispatch了一个动作,这个动作是为了在actions中请求api。


<template>
    <div>{{realName}}</div>
</template>



export default{
    computed(){
    //第三步
    realName:this.$store.getters.realName
},


created(){ 
    //第一步
    this.reqUserInfo()
},
methods:{
    reqUserInfo(){
       //第二步使用action不想之前state、getters一样直接点调用,而是用dispatch关键字来派发action
        this.$store.dispatch('getUserInfo')
    }
}
    
}

下面是actions里的操作

 async getUserInfo(context){
      //1.从接口里异步获取数据
      const res = await axios.get('/接口url')
      
      //2.将获取到的数据,通过commit提交一个mutation,去更改state里面的userInfo
      context.commit( SET_USER_INFO,{userInfo:res.userData})
   },

然后在mutations中更改state里的userInfo即可

SET_USER_INFO(state, payload) {
    state.userInfo = payload.userInfo
}

更改之后getters也会基于改变后的数据进行处理

realName:(state)=>{ return state.userInfo.userName+'' },

辅助函数(mapGetters, mapMutations, mapState, mapActions)

mapState

computed: {   
  value(){
   return this.val++
  },
  ...mapState(['likes','friends','token','userInfo'])

}

// 等价于
userInfo(){
  return this.$store.state.userInfo
},

token(){
  return this.$store.state.token
},

 friends(){
  return this.$store.state.friends
},

likes(){
 return this.$store.state.likes
},

mapMutations

methods:{
 ...mapMutations(['addAge'])
}

// 相当于
methods:{
 addAge(payLoad){
 
  this.$store.commit('addAge',payLoad)
 }
}

//传参

<button @click="AddAge({number:1})">增加一岁</button>

mapGetters

computed: {  
 valued(){
   return this.value++
 },
 ...mapGetters(['realName','myMoney'])
}

mapActions

methods:{
    ...mapActions(['getUserInfo','getToken'])
}

//相当于

methods:{
    getUserInfo(){
        return this.$store.dispatch(‘getUserInfo’)
    },
    getToken(){
        return this.$store.dispatch(‘getToken’)
    },
}

Vuex module

我们将Vuex中的store分成大大小小的对象,这个对象就叫做module模块,每个module也都有state, actions, mutations, getters。
建立一个moduleA和一个moduleB

export default {
    state: {
        text: 'moduleA'
    },
    getters: {},
    mutations: {},
    actions: {}
}
export default {
    state: {
        text: 'moduleB'
    },
    getters: {},
    mutations: {},
    actions: {}
}

在store的主文件index.js中,我们这样引入两个module

import moduleA from './module/moduleA';
import moduleB from './module/moduleB';

export default new Vuex.Store({
    modules: {
        moduleA, moduleB,
    },
    // ...
}

注册了moduleA和moduleB,我们就可以在组件使用了

// ...
computed: {
    ...mapState({
        name1: state => state.moduleA.text,
        name2: state => state.moduleB.text
    }),
},
// ...

由此我们可以看出,对于不同module,他的state是独立的,那mutations,getters,actions也是如此吗?
其实并不是,mutations,actions,getters是默认注册在全局命名空间的,也就是说一个module的改变会引起所有module的变化,具体看下面的例子
moduleA中的mutations修改state里的text

mutations: {
    setText(state) {
        state.text = 'A'
    }
},

在组件里获取,会发现moduleA和moduleB里的text都被更改了

<script>
    import {mapState, mapMutations} from 'vuex';
    export default {
        computed: {
            ...mapState({
                name: state => (state.moduleA.text + '和' + state.moduleB.text)
            }),
        },
        methods: {
            ...mapMutations(['setText']),
            modifyNameAction() {
                this.setText();
            }
        },
    }
</script>

actionsgetters也是同理
暂时没遇到这样的场景,不做总结 放个学习的链接,遇到了再翻看Vuex白话教程第六讲:Vuex的管理员Module(实战篇) - 简书 (jianshu.com)

vuex和localstorage

  1. 持久化 vuex的数据存放在内存中,页面刷新数据就会丢失,而localstorage存放在硬盘内,刷新页面不会丢失。
  2. 响应式 vuex的数据是经过响应式处理的,而localstorage没有。
  3. 应用场景 vuex主要是为了数据的集中管理,用于组件传值,而localstorage一般用于跨页面传输(同域名)。个人认为只有不变的数据且不更换数据源情况下才用localstorage,比如token