vue-router的详解及简单原理实现 与vuex简单原理实现

1基础用法

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')

router/index.js
里面注释的部分 包含路由独享守卫 与路由全局守卫

import Vue from 'vue'
import Router from 'vue-router'
import List from '@/components/list.vue';
import About from '@/components/about.vue';
import Detail from '@/components/detail.vue';
import Login from '@/components/login.vue';
import HelloWorld from '@/components/HelloWorld.vue';
Vue.use(Router)
let router = new Router({
    mode:"history",
    base:process.env.BASE_URL,
    routes:[
        {
            path: '/',
            name: 'HelloWorld',
            component: HelloWorld,
            children:[{
              path: '',
               name: 'List',
               component: List,
            },
            {path:'/detail/:id',
            name:Detail,
            component:Detail
          }
           
          ]
          },
          {
            path: '/about',
            name: 'About',
            // beforeEnter:(to,from,next) => {//路由独享守卫
            //     //     //判断是否登陆
            //     if(!window.isLogin){//如果去about页  并且没登陆  那么就去登陆页
            //         next('/login?redirect='+to.path)
            //     }else{
            //         next()
            //     }
            // },
            component: About,
            },
            {
              path: '/login',
            name: 'Login',
            component: Login,
            }
    ]
})
//每次路由激活前都会执行回调函数
// router.beforeEach((to,form,next)=>{   //全局的守卫
//     //判断是否登陆
//     if(to.path ==='/about'&&!window.isLogin){//如果去about页  并且没登陆  那么就去登陆页
//         next('/login?redirect='+to.path)
//     }else{
//         next()
//     }
// })
export default router

about.vue
组件守卫

<template>.
  <div>
      about
  </div>
</template>

<script>
  export default {
    beforeRouteEnter(to,from,next){//组件守卫
    //判断是否登陆
    if(!window.isLogin){// 没登陆  那么就去登陆页
        next('/login?redirect='+to.path) //重定向
    }else{
        next()
    }
   }
  }
</script>

<style scoped>

</style>

login.vue

<template>
  <div>
      登陆
      <button @click="onload">登陆</button>
  </div>
</template>

<script>
  export default {
    methods: {
      onload() {
        window.isLogin = true
        let redirect = this.$route.query.redirect||'/'
        this.$router.push(redirect)
      }
    },
  }
</script>

<style scoped>

</style>

list.vue

<template>
  <div>
    <ul>
      <li v-for="item in data" :key="item.price">
        <router-link :to="`/detail/${item.id}`">
        <span>{{ item.name }}</span>
        <span>{{ item.price }}</span>
        <!-- 去掉默认行为和冒泡 -->
        <button @click.prevent.stop="addCar(item)">添加购物车</button>
        </router-link>
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    data() {
    return {
      data: [
        { name: "辣条", price: 10, id: 1 },
        { name: "糖果", price: 1, id: 2 }
      ]
    };
  },
  methods: {
      addCar(){
          
      }
  },
  }
</script>

<style scoped>

</style>

HelloWorld.vue

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    
  }
</script>

<style scoped>

</style>

app.vue

<template>
  <div id="app">
    <div>
    <router-link to="/about">ABOUT</router-link>
    <router-link to="/">HOME</router-link>
    <router-link to="/login">登录</router-link>
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

.
.
.

原理

app.vue

<!--
 * @Author: yang
 * @Date: 2020-08-03 09:47:09
 * @LastEditors: yang
 * @LastEditTime: 2020-08-10 14:28:35
 * @FilePath: \project\src\App.vue
-->
<template>
  <div id="app">
    <div>
    <router-link to="/about">ABOUT</router-link>
    <router-link to="/">HOME</router-link>
    <router-link to="/login" v-if="!isLogin">登录</router-link>
    <span v-else>{{getLogin}}</span>
    </div>
    <router-view/>
    <button @click="addCount">加一</button>
    {{count}}
  </div>
</template>

<script>
import {mapState,mapGetters} from 'vuex'
import store from './Ystore.js'
export default {
  name: 'App',
  computed: {
    ...mapState(['isLogin']),
    ...mapGetters(['getLogin']),
    count(){
      return store.state.count
    },
  },
  methods: {
    addCount(){
      store.commit('add')
    },
  
  },
  
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

login.vue

<!--
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-08 14:45:23
-->
<template>
  <div>
      登陆
    <h1>用户登录</h1>
      <button @click="onload">{{loadding?'登陆中':"登陆"}}</button>
  </div>
</template>

<script>
import {mapActions} from 'vuex'
  export default {
    data() {
      return {
        loadding: false
      }
    },
    methods: {
      ...mapActions(['requestLogin']),
      onload() {
        // window.isLogin = true
         // commit提交
        // this.$store.commit('login')
        // action dispatch
        this.loadding = true
        let that = this
        this.requestLogin({name:'tom'}).then((login)=>{
          console.log(that.$route.query.redirect)
          //  that.loadding = false
          console.log(that.loadding)
            let redirect = that.$route.query.redirect||'/'
            that.$router.push(redirect)
        })
        
      }
    },
  }
</script>

<style scoped>

</style>

home.vue

<template>
  <div>
      <router-view></router-view>
  </div>
</template>

<script>
  export default {
    
  }
</script>

<style scoped>

</style>

about.vue

<!--
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-08 14:45:01
-->
<template>
  <div>
      about
  </div>
</template>

<script>
  export default {
//     beforeRouteEnter(to,from,next){//组件守卫
//     //判断是否登陆
//     if(!window.isLogin){// 没登陆  那么就去登陆页
//         next('/login?redirect='+to.path) //重定向
//     }else{
//         next()
//     }
//    }
  }
</script>

<style scoped>

</style>

store.js

/*
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-08 18:07:01
 */
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
    state:{
        isLogin:false
    },
    mutations:{
        login(state){
            state.isLogin = true
        }
    },
    getters:{
        getLogin(state){
            return state.isLogin ? '欢迎回来':'游客'
        }
    },
    actions:{
        requestLogin(context,prop){
            //context函数的上下文  prop 传过来的参数
            console.log(context,prop)
            return new Promise((resolve)=>{
                setTimeout(()=>{
                    resolve(true)
                    context.commit('login')
                },1000)
                
            })
           
        }
    }
})

router.js

/*
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-08 14:31:45
 */
import Vue from 'vue'
import Router from 'vue-router'
import List from '@/components/list.vue';
import About from '@/components/about.vue';
import Detail from '@/components/detail.vue';
import Login from '@/components/login.vue';
import HelloWorld from '@/components/HelloWorld.vue';
import store from './store.js'
Vue.use(Router)
let router = new Router({
    mode:"history",
    base:process.env.BASE_URL,
    routes:[
        {
            path: '/',
            name: 'HelloWorld',
            component: HelloWorld,
            children:[{
              path: '',
               name: 'List',
               component: List,
            },
            {path:'/detail/:id',
            name:Detail,
            component:Detail
          }
           
          ]
          },
          {
            path: '/about',
            name: 'About',
            // beforeEnter:(to,from,next) => {//路由独享守卫
            //     //     //判断是否登陆
            //     if(!window.isLogin){//如果去about页  并且没登陆  那么就去登陆页
            //         next('/login?redirect='+to.path)
            //     }else{
            //         next()
            //     }
            // },
            component: About,
            },
            {
              path: '/login',
            name: 'Login',
            component: Login,
            }
    ]
})
//每次路由激活前都会执行回调函数
router.beforeEach((to,form,next)=>{   //全局的守卫
    //判断是否登陆
    if(to.path ==='/about'&&!store.state.isLogin){//如果去about页  并且没登陆  那么就去登陆页
        next('/login?redirect='+to.path)
        
    }else{
        next()
    }
})
export default router

Yrouter.js

/*
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-09 16:24:02
 */
class VueRouter{
    constructor(Vue,options){
        this.$option = options
        this.routeMap = {}
        this.app = new Vue({
            data:{
                current:'#/'
            }
        })
        this.init()
        this.initCreateRouterMap(options)
        this.initComponent(Vue)
    }
    init(){
        window.addEventListener('load',this.onHashchange,false)
        window.addEventListener('hashchange',this.onHashchange,false)
    }
    getHash(){
        return window.location.hash.splice(1)||'/'
    }
    onHashchange(){
        this.app.current = this.getHash()
    }
    initCreateRouterMap(options){
        options.routers.forEach(item=>{
           this.routeMap[item.path] = item.component
        })
    }
    initComponent(Vue){
//         props可以使用实例中的变量赋值
// 全局组件可以获取用使用prop 的做操作 ,指定类型
        Vue.component('router-link',{
          prop:{
            to:String
          },
//           用来访问被 slot 分发的内容。每个具名 slot 有其相应的属性
// (例如:slot="foo" 中的内容将会在 vm.$slots.foo 中被找到)
// default 属性包括了所有没有被包含在具名 slot 中的节点。
          render:function(h){
            return h(
                "a",
                {attr:{href:this.to}},
                this.$slots.default
            )
          }
        })
        let _this = this
        Vue.component('route-view',{
            render(h){
                let component = _this.routeMap[_this.app.current]
                h(component)
            }
        })
    }
}

Ystore.js

/*
 * @Description: 
 * @Autor: wangDuJuan
 * @Date: 2020-08-09 15:24:40
 */
import Vue from 'vue'
class Ystore{
    constructor(options){
        this.state = options.state
        this.mutations = options.mutations
        this.actions = options.actions
        // 借助Vue本身的数据响应机制
        new Vue({
            data:{
                state:this.state
            }
        })
    }
    commit(type,payload){
        let mutation = this.mutations[type]
        mutation(this.state,payload)
    }
    dispatch(type,payLoad){
        let action = this.actions[type]
        // createClass  创建类的函数里面中es5的写法默认是绑定了bind方法,而es6中 新增加了class,绑定的方法需要绑定this,如果是箭头函数就不需要绑定this,用箭头的方式
        let atx= {
            state:this.state.bind(this),
            mutations:this.mutations,
            dispatch:this.dispatch.bind(this)
        }
        return action(atx,payLoad)
    }
}
export default new Ystore({
    state:{
        count:1
    },
    mutations:{
        add(state){
            state.count++
        }
    }
})

vue.config.js(mock数据)

/*
 * @Author: yang
 * @Date: 2020-08-07 11:36:56
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2020-08-08 19:03:45
 * @FilePath: \testproject\vue.config.js
 */
// node代码
module.exports = {
    publicPath:'/cart',
    lintOnSave: false,
    configureWebpack:{//webpack的配置项 webpack开发服务器
        devServer:{//mock数据  服务器的代理 都可以在这里配置
            before(app){ //在服务器启动之前的钩子函数,在这里可以对服务器的实例做一些提前的操作
                //app 是express的实例
                app.get('/goods',(req,res)=>{
                    res.json([{
                        id:1,text:'kk'
                    },{id:2,text:'lll'}
                ])
                })
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值