vue router and vuex

vue router and vuex

Before learning, we can install a plug-in first, which is a browser plug-in. The function of this plug-in is to allow us to better observe the changes of data and status. It is a link to github. If you can’t get online
insert image description here
scientifically If so, you can also download and install the
plug-in
from the above link. I won’t talk
about the installation. For the installation of router and vuex, you can install it when creating a project, or you can add plug-ins later. The more brainless way is to start cmd , start the ui management of vue

vue ui

insert image description here
Then search and install.
After the installation is complete, there will be these two folders.
insert image description here
Let’s take a look at these two files
router/index.js first.

import Vue from 'vue'
import VueRouter from 'vue-router'  //1、引用了VueRouter这个库,就是咱们在创建项目的时候选择了VueRouter即可
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter) //2、引入了VueRouter这个官方插件

const routes = [
  {
    
    
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]
//3、new VueRouter,创建了一个VueRouter的实例
const router = new VueRouter({
    
    
  routes
})
//4、导出这个实例,供项目使用
export default router

Look at store/index.js again

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//和router/index.js是类似的
export default new Vuex.Store({
    
    
  state: {
    
    
  },
  getters: {
    
    
  },
  mutations: {
    
    
  },
  actions: {
    
    
  },
  modules: {
    
    
  }
})

So, where are the created router and vuex instances used?
The answer is main.js in the root directory

insert image description here
At this time, the entire Vue project has the function of router vuex

router

basic use

Next, let's explain the basic functions of the router.

import Vue from 'vue'
import VueRouter from 'vue-router'  
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter) 
const routes = [
  {
    
    
    // 3、path就是你跳转的路径
    path: '/',
    //4、这个name参数,是在比如说你的path很长的时候,例如 '/xxxx/eeee/cccc/vvv/vvv/ggg',可以通过name的value,也就是home来替代path,就比较方便跳转
    name: 'home',
    //5、这个地址对应的显示的组件是哪个,就由这个参数来决定,这个路径是通过import HomeView from '../views/HomeView.vue' import的方式来引用的
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    //6、这个是通过异步的方式,里面还有一个webpack的魔法注释,是为了让webpack打包的时候可以让多个组件统一打包
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]
const router = new VueRouter({
    
    
  //1、history,看起来更好看,IE10及以上支持,一下需要单独处理
  //mode设置为空.默认是hash模式的,或者设置成 mode: 'hash'  也可以,这种模式的优点在于兼容性更好
  mode: 'history',
  //2、这个routes就是上面const routes定义的变量,里面存放的是真正的路由信息
  routes
})
export default router

For the first point
history mode
insert image description here
hash or default mode
insert image description here

For the third and fourth points, including where these components are defined, let's take a look
insert image description here

<template>
  <div id="app">
    <nav>
      <!-- 1、这是一个链接的标签,外面显示的名字时Home,点击后,就根据router/index.js设置的路由跳转到了Home这个组件 -->
      <router-link to="/">Home</router-link> |
      <!-- 2、相应的,这个就是跳转到了AboutView这个组件 -->
      <router-link to="/about">About</router-link> |
      <!-- 3、还记得router/index.js的第三点和第四点,我们可以通过下面这种方式来替换上面的跳转方式,通过 :to来绑定,{
    
    name: 'about'}的name,就是表示我要用name的方式来跳转,后面的about就是router/index.js的第4点的name的value -->
      <router-link :to="{name: 'about'}">About2</router-link>
    </nav>
    <!-- 4、那上面这两个跳转的了对应的组件页面,展示在哪里呢,就是展示router-view标签的位置,也就是App这个组件,在这里留了一块地方,供子组件使用 
    它没有展示在上面,而是展示在了跳转链接的下面,就是在这里定义的-->
    <router-view/>
  </div>
</template>

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

nav {
    
    
  padding: 30px;
}

nav a {
    
    
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
    
    
  color: #42b983;
}
</style>

insert image description here
Next we can write a page ourselves
insert image description here

<template>
    <h3>一级组件:视频信息</h3>
</template>
<script>
export default {
    
    
    name: 'VideoView'
}
</script>
<style>

</style>

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'  
import HomeView from '../views/HomeView.vue'
// 1、引入我们新写的页面
import VideoView from '../views/VideoView.vue'

Vue.use(VueRouter) 
const routes = [
  {
    
    
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  // 2、配置好跳转信息
  {
    
    
    path:'/video',
    name:'video',
    component: VideoView
  }
]
const router = new VueRouter({
    
    
  mode: 'history',
  routes
})
export default router

app.vue

<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <!-- 1、配置好跳转链接 -->
      <router-link :to="{name: 'video'}">Video</router-link>
    </nav>
    <router-view/>
  </div>
</template>

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

nav {
    
    
  padding: 30px;
}

nav a {
    
    
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
    
    
  color: #42b983;
}
</style>

insert image description here

dynamic routing

The above are basic uses, let’s talk about dynamic routing.
For example, we created the video component above, then we may have the first video, the second video and the third video

  {
    
    
    path:'/video/323',
    name:'video',
    component: VideoView
  }

Just like above, the content of the component is the same, but the id of the video to be processed is different, similar to the product id

We first modify router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'  
import HomeView from '../views/HomeView.vue'
import VideoView from '../views/VideoView.vue'

Vue.use(VueRouter) 
const routes = [
  {
    
    
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    
    
    // 1、当后面有:的时候,就代表是动态的,就是动态路由
    path:'/video/:id',
    name:'video',
    component: VideoView,
    // 2、当动态路由设置好之后,如果你想要在组件内部访问到这个id的话,就需要配置如下内容
    props: true
  }
]
const router = new VueRouter({
    
    
  mode: 'history',
  routes
})
export default router

Then modify the corresponding component VideoView.vue

<template>
    <div>
        <h3>一级组件:视频信息</h3>
        <!-- 2、这里只是为了方便展示而已,在这里打印出来 -->
        <p>视频id为:{
    
    {
    
     id }}</p>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoView',
    // 1、在组件中通过props来承接链接中传进来的id这个值
    props:['id']
}
</script>
<style>

</style>

Finally modify the parent component to pass dynamic information

<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <!-- 1、如果通过path的方式来传递值的话,就直接在路径中拼好 -->
      <router-link to="/video/321">VideoPath</router-link> |
      <!-- 2、通过:to的方式绑定的话, 需要通过params这个参数来传递值-->
      <router-link :to="{name: 'video',params:{id:28}}">VideoBind</router-link>
    </nav>
    <router-view/>
  </div>
</template>

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

nav {
    
    
  padding: 30px;
}

nav a {
    
    
  font-weight: bold;
  color: #2c3e50;
}

nav a.router-link-exact-active {
    
    
  color: #42b983;
}
</style>

insert image description here
insert image description here

nested routes

For example, for the video id of 28, I still need to do some analysis on this video, such as the like information, and the secondary function, which is human speaking. For example, the
path
of the video is 'video/30'
and the path of the like information is
For the path of '/video/30/info', 'video/30', this section is the foundation, and info jumps on the basis of the foundation

Let's modify router/index.js first

import Vue from 'vue'
import VueRouter from 'vue-router'  
import HomeView from '../views/HomeView.vue'
import VideoView from '../views/VideoView.vue'
// 3、我们在这里也先引入,然后根据这个信息去写对应的component
import VideoInfo1 from '../views/video/VideoInfo1.vue'
import VideoInfo2 from '../views/video/VideoInfo2.vue'

Vue.use(VueRouter) 
const routes = [
  {
    
    
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    
    
    path:'/video/:id',
    name:'video',
    component: VideoView,
    props: true,
    // 1、通过children关键字来处理嵌套路由,你看这个结构,是不是和一般的路由是一样的,所以很好理解,只不过这里的children是一个list,方便配置多个嵌套路由
    children:[
      // 2、在这里我只是先随便配置上,现在对应的component还没有,稍后写,我们先放两个
      {
    
    path:'info1',
       name: 'video-info1',
       component:VideoInfo1
      },
      {
    
    path:'info2',
      name: 'video-info2',
      component:VideoInfo2
     },
    ]
  }
]
const router = new VueRouter({
    
    
  mode: 'history',
  routes
})
export default router

Next write the corresponding components
insert image description here

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1'
}
</script>
<style>

</style>
<template>
    <div>
        <h3>二级组件:互动情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo2'
}
</script>
<style>

</style>

After writing, where do we put it, of course, on the component of the parent route corresponding to the child route, that is
insert image description here

<template>
    <div>
        <h3>一级组件:视频信息</h3>
        <p>视频id为:{
    
    {
    
     id }}</p>
        <!-- 1、在这里配置好跳转的地方,这个params可以不传,毕竟咱们也没用,但是如果要传值的话,正常情况下是应该传的,要不你怎么知道是哪个视频的点赞呢,对不对,使用的方式就和动态路由一致 -->
        <router-link :to="{name: 'video-info1',params:{id:28}}">点赞</router-link> |
        <router-link :to="{name: 'video-info2',params:{id:28}}">互动</router-link>
        <!-- 2、我们的子组件总要有展示的地方对不对,就需要router-view来确定位置 -->
        <router-view/>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoView',
    props:['id']
}
</script>
<style>

</style>

The effect is as follows
insert image description here
insert image description here

How programmatic navigation is handled

What we just realized is to jump by manual clicking, so if your login information has expired, and you click this interactive link again, it should jump to the login page for you to log in, that is, take the initiative to jump change

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    // 1、created()涉及到了生命周期的内容,可以去看看,大致就是当组件创建完毕以后会执行的一个声明周期钩子
    created(){
    
    
        // 2、如果你要使用router的功能,可以通过this.$router访问到router实例,通过push去跳转到对应的地方,比如说我们就是跳转到了about页面,至于setTimeout,其实就是为了三秒后再跳转,要不直接跳转到的不就看不到过程了么
        setTimeout(()=>{
    
    
            this.$router.push({
    
    name:'about'})
        },3000)
    }
}
</script>
<style>

</style>

As a result, I won’t make animations.
The following picture is the first click.
insert image description here
After 3 seconds, it will automatically jump.
insert image description here
What should I do when we jump?

Let's first look at how the data is passed

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    created(){
    
    
        setTimeout(()=>{
    
    
            // 1、我们这次修改为跳转到video-info2,然后通过query的方式来传递信息,也就是3秒后会跳转到video-info2,并做一些数据传递
            this.$router.push({
    
    name:'video-info2',query:{
    
    someData:'video-info1传递的信息'}})
        },3000)
    }
}
</script>
<style>

</style>

Next, look at the data reception

<template>
    <div>
        <h3>二级组件:互动情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo2',
    created(){
    
    
        // 1、如果你要操作路由的话,那就是router,但是如果你要看路由相关的数据,例如地址呀,响应的参数呀,通过route来操作,就是在这里接收数据的
        // 但是需要注意的是,只有通过info1跳转过来的时候加了,其他的位置是没有加的
        console.log(this.$route.query)
    }
}
</script>
<style>

</style>

insert image description here
insert image description here

navigation guard

import Vue from 'vue'
import VueRouter from 'vue-router'  
import HomeView from '../views/HomeView.vue'
import VideoView from '../views/VideoView.vue'
import VideoInfo1 from '../views/video/VideoInfo1.vue'
import VideoInfo2 from '../views/video/VideoInfo2.vue'

Vue.use(VueRouter) 
const routes = [
  {
    
    
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    
    
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    
    
    path:'/video/:id',
    name:'video',
    component: VideoView,
    props: true,
    children:[
      {
    
    path:'info1',
       name: 'video-info1',
       component:VideoInfo1
      },
      {
    
    path:'info2',
      name: 'video-info2',
      component:VideoInfo2
     },
    ]
  }
]
const router = new VueRouter({
    
    
  mode: 'history',
  routes
})

// 比如说我要在每次路由跳转的时候都做一些操作,比如说加一个进度条啊什么的,那么就需要这个导航守卫,导航守卫有三个参数,to,from,next,to代表去哪里,from代表来自哪里,next,如果你不加next就不会跳转页面,也就什么都不渲染
router.beforeEach((to,from,next)=>{
    
    
    console.log('路由触发了')
    next()
})
export default router

The result is that every time a route is redirected, a guard will be sent out
insert image description here

vuex

It is a unified data storage method, providing a total of five functions

data storage

store/index.js file

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//和router/index.js是类似的
export default new Vuex.Store({
    
    
  // state,存储数据的地方,全局数据,其他任意组件的位置都可以来访问,但是建议将官方的注释掉,用下面这种方式
  // state: {
    
    
  // },
  state(){
    
    
    return{
    
    
      loginStatus:'用户已经登录'
    }
  },
  getters: {
    
    
  },
  mutations: {
    
    
  },
  actions: {
    
    
  },
  modules: {
    
    
  }
})

If we want to visit, for example, I want to visit in video-info1

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    created(){
    
    
        // 通过this.$store来访问store
        console.log(this.$store.state.loginStatus)
    }
}
</script>
<style>

</style>

insert image description here

data change

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
    
    
  state(){
    
    
    return{
    
    
      loginStatus:'用户已经登录',
      // 1、新增一个count值,方便后续修改操作
      count: 0
    }
  },
  getters: {
    
    
  },
  //2、 如果你要修改数据的话,就在mutations里操作,因为虽然可以直接通过赋值的方式来修改,但是不建议这么做,因为如果数据变了,有N个组件,你不知道是哪个组件变更了这个数据,不好维护全局的状态数据
  // 这个里面就是一个个方法,封装了对每一个state中存储的全局变量做变更的方法供所有组件使用,就相当于一个method
  mutations: {
    
    
    // 3、这个state就是上面的state,存储数据的state,你看得vue的组件里,我们都是用this.来访问组件里的数据,但是在vuex里,我们用的是state来代替this
    changeCount(state,num){
    
    
      // 4、这里就是传入多少,就为count加多少
      state.count+=num
      console.log('mutations执行了,count的值为:',state.count)
    }
  },
  actions: {
    
    
  },
  modules: {
    
    
  }
})

where to call it

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
        <button v-on:click="handler">调用全局方法</button>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    created(){
    
    
        console.log(this.$store.state.loginStatus)
    },
    methods:{
    
    
        // 1、我们加methods,因为全局变量一般都是在主逻辑的某一个地方,要用的时候才去使用,比如说点击了某个按钮
        handler(){
    
    
            // 2、注意,不是直接去访问mutations,而是通过commit的方式来做一个提交,第一个参数是方法的名称,第二个参数就是方法的入参了
            this.$store.commit('changeCount',1)
            this.$store.commit('changeCount',1)
            this.$store.commit('changeCount',1)
        }
    }
}
</script>
<style>

</style>

As a result,
insert image description here
do you still remember the plug-in installed at that time, and it can be used now.
insert image description here
There is also an important function called TimeLine.
For example, we refresh the page first
and then click the button to observe TimeLine.
insert image description here
It records the status change and the corresponding time, but it can only If the record is synchronous, if it is asynchronous, only one result can be recorded

Changes to asynchronous results

import Vue from 'vue'
import Vuex, {
    
     Store } from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
    
    
  state(){
    
    
    return{
    
    
      loginStatus:'用户已经登录',
      count: 0
    }
  },
  getters: {
    
    
  },
  mutations: {
    
    
    changeCount(state,num){
    
    
      state.count+=num
      console.log('mutations执行了,count的值为:',state.count)
    }
  },
  actions: {
    
    
    delayChangeCount(store,num){
    
    
      // 1、还记得上面说的,要修改数据,只能在mutations里,而且是通过commit的方式,那actions也不例外,和组件一样,也是调用mutations的方法  ,action里面全是异步的操作   
      setTimeout(()=>{
    
    
        store.commit('changeCount',num)
      },3000)
    }
  },
  modules: {
    
    
  }
})


We also use in VideoInfo1

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
        <button v-on:click="handler">调用全局方法</button>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    created(){
    
    
        console.log(this.$store.state.loginStatus)
    },
    methods:{
    
    
        handler(){
    
    
            this.$store.commit('changeCount',1)
            this.$store.commit('changeCount',2)
            // 这次不是用commit了,而是用dispatch,执行、发送的意思
            this.$store.dispatch('delayChangeCount',10)
            this.$store.commit('changeCount',3)
        }
    }
}
</script>
<style>

</style>

The sequence of results
insert image description here
is that changeCount is called twice first, and then the third asynchronous method delayChangeCount is executed. After waiting for three seconds, the fourth changeCount is executed first, and after three seconds, the changeCount in the delayChangeCount method is executed. It can also be seen through the parameters

computed property

import Vue from 'vue'
import Vuex, {
    
     Store } from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
    
    
  state(){
    
    
    return{
    
    
      loginStatus:'用户已经登录',
      count: 0
    }
  },
  // 1、就相当于我们的计算属性,是带有缓存属性的,就像插件的computed方法,如果参数不变,不管调用几次,只计算一次
  getters: {
    
    
    len(state){
    
    
      console.log('getters执行了')
      // 2、返回了state.loginStatus的长度
      return state.loginStatus.length
    }
  },
  mutations: {
    
    
    changeCount(state,num){
    
    
      state.count+=num
      console.log('mutations执行了,count的值为:',state.count)
    }
  },
  actions: {
    
    
    delayChangeCount(store,num){
    
    
      setTimeout(()=>{
    
    
        store.commit('changeCount',num)
      },3000)
    }
  },
  modules: {
    
    
  }
})

call method

<template>
    <div>
        <h3>二级组件:点赞情况分析</h3>
        <button v-on:click="handler">调用全局方法</button>
    </div>
</template>
<script>
export default {
    
    
    name: 'VideoInfo1',
    created(){
    
    
        console.log(this.$store.state.loginStatus)
    },
    methods:{
    
    
        handler(){
    
    
            this.$store.commit('changeCount',1)
            this.$store.commit('changeCount',2)
            this.$store.dispatch('delayChangeCount',10)
            this.$store.commit('changeCount',3)
            // 这次也不是commit也不是dispatchle ,而是使用getters.方法名来调用对应方法了
            console.log(this.$store.getters.len)
            console.log(this.$store.getters.len)
            console.log(this.$store.getters.len)
            console.log(this.$store.getters.len)
            console.log(this.$store.getters.len)
        }
    }
}
</script>
<style>

</style>

The result
insert image description here
is printed 5 times, yes, but the actual call is only called once

module management

import Vue from 'vue'
import Vuex, {
    
     Store } from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
    
    
  state(){
    
    
    return{
    
    
      loginStatus:'用户已经登录',
      count: 0
    }
  },
  getters: {
    
    
    len(state){
    
    
      console.log('getters执行了')
      return state.loginStatus.length
    }
  },
  mutations: {
    
    
    changeCount(state,num){
    
    
      state.count+=num
      console.log('mutations执行了,count的值为:',state.count)
    }
  },
  actions: {
    
    
    delayChangeCount(store,num){
    
    
      setTimeout(()=>{
    
    
        store.commit('changeCount',num)
      },3000)
    }
  },
  modules: {
    
    
    // 1、比如说state中的两个值,可能只是和user有关的,在一个app里很多功能,比如购物功能等,那如果不同的功能有不同的全局处理,比如说a里面有两个值,这两个值又不想被b用,这种情况下为乐避免混乱,
    //让数据更好管理,就需要使用模块,也就是modules
    a:{
    
    
      state, 
      getters,
      mutations,
      actions,
      modules
    },
    // 2、里面的内容就和store/index.js几乎是一样的,按需添加
    b:{
    
    
      state, 
      getters,
      mutations,
      actions,
      modules
    }
  }
})

Use
Before calling, just add the name of the corresponding module
insert image description here
. But since it has been modularized, then simply re-module, create a new modules folder under the store module, and create a.js and b.js below, the contents inside Replace the content of the corresponding module in modules
insert image description here

Guess you like

Origin blog.csdn.net/qq13933506749/article/details/131594705