vue+(vue2

一、vuex

vuex状态管理

Vue应用程序的状态(state)管理器。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  • 把“状态”换成“数据”。
  • 如果你的项目中,需要用到在各个子组件中共享数据,则你就需要用到vuex。

请添加图片描述
第一步:先引入vue.js,再引入vuex.js

 <!-- 引入Vue.js -->
 <script src="./libs/vue.js"></script>
 <!-- 引入Vuex.js -->
 <script src="./libs/vuex.js"></script>

第二步:实例化vuex中的store对象

  • 实例化一个对象,就是通过new的方式去创建一个对象
// 创建一个仓库  需要传入一个配置对象
let store = new Vuex.Store({
    // state是状态  是集中管理的状态
    // 状态是响应式的
    // 组件中的data中的状态也是状态式
    state: {
        counter: 0
    },
    // 修改状态的唯一途径
    mutations: {
        // 每一个mutations就是一个函数
        // 第1个参数是仓库中的state
        // payload 是commit mutation时,传递的参数
        add(state, payload) {
            // state.counter++;
            state.counter += payload
        },
        sub(state) {
            state.counter--;
        }
    },
    // 放异步代码,如果有异步操作,代码需要写在actions中
    actions: {

    },
    // 类似于组件中的计算属性
    // 根据已有状态计算出一个新的状态
    getters: {

    }
});

第三步:注入到Vue实例中

let vm = new Vue({
     el: "#app",
     store, // vuex也是一个插件,需要挂载到根组件上,就意味着,它的子子孙孙,都可以使用这个仓库了
     components: {
         AddCounter,
         SubCounter
     },
     data() {
         return {

         }
     }
 });

第四步:定义两个组件并在App中使用之

let AddCounter = Vue.extend({
     template: `
        <div>
            <p>我是addcounter组件</p>
            <p>在addcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
            <button @click="add">加1</button>
        </div>
    `,
     methods: {
         add() {
             // 这样是粗暴地修改状态 极力不推荐
             // 如果其它组件也这样修改状态,状态不好追踪了
             // this.$store.state.counter++;

             // 需要commit一个mutation,通过mutation去修改状态
             this.$store.commit("add", 100)
         }
     }
 })
 let SubCounter = Vue.extend({
     template: `
        <div>
            <p>我是subcounter组件</p>
            <p>在subcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
            <button @click="sub">减1</button>
        </div>
    `,
     methods: {
         sub() {
             // this.$store.state.counter--;

             this.$store.commit("sub")
         }
     }
 })

第五步:使用store中的数据

  • 一旦你在vue的实例中注入了store,则在所有的子组件及 vue的实例中,你都可以通过:this.$store.state. 数据名 去获取数据
  • 类似于我们把router注入到vue实例中,我们就可以通过this.$router 和 this.$route操作路由。
<p>在addcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
 <p>在subcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
  • 可以通过:this.$store.state. 数据名 = 值 去修改数据,但是,vuex反对这么做

两种方法去使用数据

  • 获取:this.$store.state. 数据名
  • 修改:在组件内部通过this.$commit方法触发事件,执行mutations当中的对应的方法

vuex的四个概念

请添加图片描述

  • state: 放数据。在组件之间共享
  • mutations: 修改数据 修改数据的唯一途径
  • getters: 从state中的数据中,取出一部分来,依据数据项产生新的结果。类似于vue实例中的computed(计算属性)。
  • actions: 在对数据实现异步操作时,要用的
store
  • 每一个 Vuex 应用的核心就是 store(仓库)
  • store是一个容器,包含着vue应用的状态(state)

两大特点

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新
  • 你不能直接更改 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交(commit) mutations。这样使得我们可以方便地跟踪每一个状态的变化
    请添加图片描述

在组件中应该如何去获取保存在vuex. 中的数据

  • 方法一:this.$store.state.xxx
  • 方法二:变通一下,在组件内部用一个计算属性来获取数据
  • 方法三:mapState

mapState

  • this.$store.state.count写起来比较麻烦。在vuex中提供一个便捷的写法:mapState。
  • 它的作用:是把写在vuex.store.state中的数据直接映射到组件中计算属性中。

请添加图片描述

getters

在组件中使用getters

  • 方法一:this.$store.getters.failedNumber
  • 方法二 :mapGetters
  • 与mapState类似,它的作用也是用来帮助我们去简化代码。我们如果直接定义一个计算属性也是可以的。

请添加图片描述

mutations

作用是:它是唯一的用来修改数据的工具

  • 方法一:this.$store.commit
  • 方法二:mapMutations

请添加图片描述

actions

在mutations中,如果操作是异步的,在控制台中并不能追踪到

  • 可以把异步操作写在actions中
  • 虽然把异步操作写在actions中,但是改变状态的唯一方式是不变,还是通过mutations

action与mutations的区别

  • actions 提交的是 mutations,而不是直接变更状态。
  • actions 可以包含任意异步操作。
  • action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,可以通过context.commit提交,也可以通过context.state获取state。

**在组件中使用actions
**

  • 方法一: this.$store.dispatch(“actions名”)
  • 方法二:mapActions

请添加图片描述

二、路由

前端路由介绍

路由其实是网络工程中的一个术语

  • 在架构一个网络时,非常重要的两个设备就是路由器和交换机
  • 目前在我们生活中路由器也是越来越被大家所熟知,因为我们生活中都会用到路由器
  • 路由器主要维护的是一个映射表,映射表会决定数据的流向

前端路由的实现方案(前端路由是如何做到URL和内容进行映射呢?监听URL的改变)

  • 前端路由的核心是什么呢?改变URL,但是页面不进行整体的刷新
  • URL的hash
  • HTML5的History

URL的hash

  • URL的hash也就是锚点(#), 本质上是改变window.location的href属性
  • 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
  • hash的优势就是兼容性更好,在老版IE中都可以运行,但是缺陷是有一个#,显得不像一个真实的路径
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <a href="#/home">home</a>
        <a href="#/about">about</a>
        <div class="router-view"></div>
    </div>

    <script>
        // 1,获取router-view
        const routerViewEl = document.querySelector(".router-view");
        // 2, 监听hashchange
        window.addEventListener("hashchange", () => {
            switch (location.hash) {
                case "#/home":
                    routerViewEl.innerHTML = "home";
                    break;
                case "#/about":
                    routerViewEl.innerHTML = "about";
                    break;
                default:
                    routerViewEl.innerHTML = "default";
            }
        })
    </script>
</body>

</html>

HTML5的History(history接口是HTML5新增的, 它有六种模式改变URL而不刷新页面)

  • replaceState:替换原来的路径
  • pushState:使用新的路径
  • popState:路径的回退
  • go:向前或向后改变路径
  • forward:向前改变路径
  • back:向后改变路径
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
</head>
<style>
    * {
        /* global font */
        font-family: Verdana;
        font-size: 18px;
    }

    #root {
        display: flex;
        flex-direction: row;
    }

    #content {
        display: flex;
        display: block;
        width: 800px;
        height: 250px;
        /* vertically centered text */
        line-height: 250px;
        border: 2px solid #555;
        margin: 32px;
        text-align: center;
    }

    .route {
        cursor: pointer;
        justify-content: center;
        width: 150px;
        height: 50px;
        /* vertically centered text */
        line-height: 50px;
        position: relative;
        border: 2px solid #555;
        background: white;
        text-align: center;
        margin: 16px;
    }

    .route.selected {
        background: yellow;
    }
</style>

<body>
    <section id="root">
        <section class="route" id="home">/home</section>
        <section class="route" id="about">/about</section>
        <section class="route" id="gallery">/gallery</section>
        <section class="route" id="contact">/contact</section>
        <section class="route" id="help">/help</section>
    </section>
    <main id="content">Content loading...</main>
</body>
<script type="text/javascript">
    window.onload = event => {
        //监听 路由的点击事件  执行push方法
        window["home"].addEventListener("click", event => push(event))
        window["about"].addEventListener("click", event => push(event))
        window["gallery"].addEventListener("click", event => push(event))
        window["contact"].addEventListener("click", event => push(event))
        window["help"].addEventListener("click", event => push(event))
    }

    function select_tab(id) {
        // 改变 路由按钮的样式
        document.querySelectorAll(".route").forEach(item => item.classList.remove('selected'));
        document.querySelectorAll("#" + id).forEach(item => item.classList.add('selected'));
    }

    function load_content(id) {
        //更新内容
        document.querySelector("#content").innerHTML = 'Content loading for /' + id + '...';
    }

    function push(event) {
        let id = event.target.id;
        select_tab(id);
        document.title = id;
        load_content(id);
        window.history.pushState({
            id
        }, `${id}`, `/page/${id}`);
    }
    window.addEventListener("popstate", event => {
        let stateId = event.state.id;
        select_tab(stateId);
        load_content(stateId);
    });
</script>

</html>

认识vue-router

前端流行的三大框架, 自己的路由实现

  • Angular的ngRouter
  • React的ReactRouter
  • Vue的vue-router

Vue Router 是 Vue.js 的官方路由

  • 它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用(SPA)变得非常容易
  • 路由用于设定访问路径, 将路径和组件映射起来
  • 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
  • 安装Vue Router:npm install vue-router@3.5.3

路由的使用步骤

  • 第一步:创建路由需要映射的组件(打算显示的页面)
  • 第二步:通过new VueRouter创建路由对象,并且传入routes和history模式
    • 安装插件 Vue.use(VueRouter);
    • 配置路由映射: 组件和路径映射关系的routes数组
    • 创建基于hash或者history的模式
  • 第三步:通过 router 配置参数注入路由,从而让整个应用都有路由功能
  • 第四步:路由使用: 通过router-link和router-view
// router/index.js

//配置路由
//引入vue-router插件:经过打印查看,引入进来的VueRouter构造函数
//vue基础学习构造函数:Vue、VueComponent、Vuex.Store、VueRouter
import VueRouter from 'vue-router';
import Vue from 'vue';
//安装插件
Vue.use(VueRouter);
//引入路由组件
import Home from '../pages/Home';
import About from '../pages/About';

//配置项目的路由
//通过VueRouter【路由器】类,创建了一个VueRouter类的一个实例!!!
//对外暴露
export default new VueRouter({
    mode: 'history',
    routes: [{
    // path配置的是根路径: /
    path: "/",
    // redirect是重定向, 也就是我们将根路径重定向到/home的路径下, 这样就可以得到我们想要的结果了
    redirect: "/home"
}, {
    //path设置路由的K,path有的属性值务必都是小写的
    path: "/home",
    //component设置路由的V,一个K对应一个V
    component: Home,
}, {
    path: '/about',
    component: About
},
    ]
});
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from "./routes/router"

// 把路由对象挂载到根实例上
// 那么它的子子孙孙都可以使用这个路由对象
new Vue({
    router,
    render: h => h(App),
}).$mount('#app')
// Home.vue
<template>
  <div>
    <h1>Home组件</h1>
  </div>
</template>

<script>
export default {
  name: "Home",
};
</script>

<style>
</style>
// About.vue
<template>
  <div>
      <h1>About组件</h1>
  </div>
</template>

<script>
export default {
  name:"About"
}
</script>

<style>

</style>
// App.vue
<template>
  <div id="app">
    <!-- router-link 当成a标签 -->
    <router-link to="/home" active-class="active">Home</router-link> &nbsp;&nbsp;
    <router-link to="/about" active-class="active">About</router-link>
    <hr>
    <!-- 路由的出口:路由匹配到的组件,需要放到路由出口 -->
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
};
</script>

<style lang="less">
.active{
  color: red;
}
</style>

router-link

router-link属性

  • to属性: 是一个字符串,或者是一个对象
  • replace属性:设置 replace 属性的话,当点击时,会调用 router.replace(),而不是 router.push();
  • active-class属性:设置激活a元素后应用的class,默认是router-link-active
  • exact属性:精确匹配模式

路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载:

  • 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效
  • 也可以提高首屏的渲染效率
    Vue Router默认就支持动态来导入组件
  • 因为component可以传入一个组件,也可以接收一个函数,该函数需要放回一个Promise,而import函数就是返回一个Promise
  • 分包是没有一个很明确的名称的,其实webpack从3.x开始支持对分包进行命名(chunk name)
{
    path: "/",
    redirect: "/home"
}, {
    path: "/home",
    component: ()=>import(/* webpackChunkName: "home" */"../pages/Home.vue"),
}, {
    path: '/about',
    component: ()=>import(/* webpackChunkName: "about" */"../pages/About.vue"),
},

打包后的代码如下
请添加图片描述

路由其他属性

  • name属性:路由记录独一无二的名称;
  • meta属性:自定义的数据
{
    path: "/",
    redirect: "/home"
}, {
    path: "/home",
    component: ()=>import(/* webpackChunkName: "home" */"../pages/Home.vue"),
    name:"home"
}, {
    path: '/about',
    component: ()=>import(/* webpackChunkName: "about" */"../pages/About.vue"),
    name:"about",
    meta:{
        name:"wc",
        age:18
    }
},

嵌套路由和404组件

嵌套路由

  • 我们匹配的Home、About等都属于第一级路由,我们在它们之间可以来回进行切换
  • Home页面本身,也可能会在多个组件之间来回切换
    • 比如Home中包括Cart、Mine,它们可以在Home内部来回切换
    • 这个时候我们就需要使用嵌套路由,在Home中也使用 router-view 来占位之后需要渲染的组件

404组件

  • 对于哪些没有匹配到的路由,我们通常会匹配到固定的某个页面
  • 在路由规则最后面配置:{ path:“*”, component:NotFount },
import Vue from "vue";
import VueRouter from "vue-router"

// 自定义的组件  直接引入  下面的组件,一上来,就全部引入
import Home from "../components/Home"
// import About from "../components/About"
import NotFount from "../components/NotFount"
import Cart from "../components/Cart"
// import Mine from "../components/Mine"

// 能不能点击某个连接时,用到了这个组件,再去引入呢?
// 答:可以,使用路由的懒加载


Vue.use(VueRouter);

// 配置路由规则
let routes = [
    { path:"/", redirect:"/home" },
    { 
        path:"/home", 
        component:Home,
        children:[
            { path:"/home", redirect:"/home/cart" },
            { path:"/home/cart", component:Cart },
            { path:"/home/mine", component:()=>import(/* webpackChunkName: "Mine" */"../components/Mine") },
        ]
    },
    // { path:"/about", component:About },
    { path:"/about", component:()=>import(/* webpackChunkName: "About" */"../components/About") },
    { path:"*", component:NotFount },
];

let router = new VueRouter({
    // hash路由有一个特点,就是#
    mode:"hash", // hash路由
    routes
})

export default router;
// Home.vue
<template>
  <div>
    <h1>Home组件</h1>
    <router-link to="/home/cart">购物车</router-link>  &nbsp;&nbsp;
    <router-link to="/home/mine">我的</router-link>
    <hr>
    <router-view />
  </div>
</template>

<script>
export default {
  name: "Home",
};
</script>

<style>
</style>
// About.vue
<template>
  <div>
      <h1>About组件</h1>
  </div>
</template>

<script>
export default {
  name:"About"
}
</script>

<style>

</style>
// Cart.vue
<template>
  <div>
      <h3>购物车</h3>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// Mine.vue
<template>
  <div>
      <h3>我的</h3>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// NotFount.vue
<template>
  <div>
      <h3>你的页面飞了</h3>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// App.vue
<template>
  <div id="app">
    <!-- router-link 当成a标签 -->
    <router-link to="/home" active-class="active">Home</router-link> &nbsp;&nbsp;
    <router-link to="/about" active-class="active">About</router-link>
    <hr>
    <!-- 路由的出口:路由匹配到的组件,需要放到路由出口 -->
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
  data(){
    return{
    }
  },
  methods:{
  
  },
  components: {
  },
};
</script>

<style lang="less">
.active{
  color: red;
}
</style>

动态路由

动态路由基本匹配

多时候我们需要将给定匹配模式的路由映射到同一个组件

  • 例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但是用户的ID是不同的;
  • 在Vue Router中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数;

获取动态路由的值

  • 在template中,直接通过 $route.params获取值
  • 在created中,通过 this.$route.params获取值
import VueRouter from "vue-router";
import Vue from "vue";

import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import NotFount from "../components/NotFount"

Vue.use(VueRouter);

let routes = [
    { path:"/", redirect:"/home" },
    { path:"/home", component:Home },
    { path:"/about", component:About },
    { path:"/mine/:name/:age/:address", component:Mine },
    { path:"*", component:NotFount },
];

let router = new VueRouter({
    // hash带#    
    // history不带#
    mode:"history",
    routes
})

export default router;
// Home.vue
<template>
  <div>
      <h2>Home</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// About.vue
<template>
  <div>
      <h2>About</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// Mine.vue
<template>
  <div>
      <h2>Mine -- {{ name }}</h2>
      <h2>Mine -- {{ age }}</h2>
      <h2>Mine -- {{ address }}</h2>
  </div>
</template>

<script>
export default {
  // 需要获取动态路由参数
  // 使用路由,需要知道4个知识点
  //     1)<router-view />  路由出口
  //     2)<router-link />  a标签   点击跳转
  //     3)$router  对象  有一堆的方法  挂载到当前组件实例上  this
  //     3)$route   对象  有一堆的属性  挂载到当前组件实例上  this

  data(){
    return{
      name:"",
      age:"",
      address:"",
    }
  },
  // 生命周期函数(钩子函数)
  created(){
    // 获取动态路由参数  
    console.log(this.$route);
    console.log(this.$route.params.name);

    this.name = this.$route.params.name
    this.age = this.$route.params.age
    this.address = this.$route.params.address
  }

}
</script>

<style>

</style>
// NotFount.vue
<template>
  <div>
      <h2>404</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// App.vue
<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
  data(){
    return{
    }
  },
  methods:{
  
  },
  components: {
  },
};
</script>

<style lang="less">
.active{
  color: red;
}
</style>

在router-link中进行如下跳转:

<router-link to="/main/wc/18/bj">我的</router-link>

编程式路由(代码的页面跳转)

有时候我们希望通过代码来完成页面的跳转,比如点击的是一个按钮

  • 此时,我们可以使用编程式路由
  • this.$router.push("/about")
  • 当然,我们也可以传入一个对象
    • this.$router.push({path:"/about"})
    • this.$router.push({name:"about"})

query方式的参数

  • this.$router.push({path:“/about”,query:{name:“wc”,age:18}})
  • 在界面中通过 $route.query 来获取参数

params方式的参数

  • this.$router.push({path:“/about”,params:{ address:“bj” }})
  • 在界面中通过 $route.params 来获取参数

页面的前进后退

  • router的go方法:
    • router.go(1) 向前移动一条记录,与router.forword()相同
    • router.go(-1) 向后移动一条记录,与router.back()相同
    • router.go(3) 前进3条记录
    • router.go(100) 如果没有那么多记录,静默失败
    • router.go(-100) 如果没有那么多记录,静默失败
  • router也有back:
    • 通过调用 history.back() 回溯历史。相当于 router.go(-1)
  • router也有forward:
    • 通过调用 history.forward() 在历史中前进。相当于 router.go(1)
import VueRouter from "vue-router";
import Vue from "vue";

import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import NotFount from "../components/NotFount"

Vue.use(VueRouter);

let routes = [
    { path:"/", redirect:"/home" },
    { path:"/home", name:"home", component:Home },
    { path:"/about", name:"about", component:About },
    { path:"/mine", name:"mine", component:Mine },
    { path:"*", component:NotFount },
];

let router = new VueRouter({
    // hash带#    
    // history不带#
    mode:"history",
    routes
})

export default router;
// Home.vue
<template>
  <div>
    <h2>Home</h2>
    <button @click="toAbout">去about</button>
    <button @click="forward">forward</button>
  </div>
</template>

<script>
export default {
  methods: {
    toAbout() {
      // 实现跳转到about
      // this上有route  还有router
      // route上有一堆的属性
      // router上有一堆方法
      // 跳转方式一:
      // this.$router.push("/about")

      // 跳转方式二:
      // this.$router.push({ path:"/about" })

      // 跳转方式三:
      // this.$router.push({ name:"about" })

      // 跳转传参方式一:
      // this.$router.push({ name:"about", params:{ address:"bj" } })

      // 跳转传参方式二:
      this.$router.push({ name:"about", query:{ score:"100分" } })

      // replace
      // this.$router.replace({ name:"about", query:{ score:"100分" } })
    },

    forward(){
      // this.$router.forward()
      this.$router.go(1)  // go(1) 等价于 forward
    }
  },
};
</script>

<style>
</style>
// About.vue
<template>
  <div>
      <h2>About</h2>
      <!-- <p>{{ $route.params.address }}</p> -->
      <p>{{ $route.query.score }}</p>
      <button @click="back">back</button>
  </div>
</template>

<script>
export default {
  // 4个东西:两个组件   两个对象route  rotuer
  created(){
    console.log(this.$route);
    // console.log(this.$route.params.address);

    console.log(this.$route.query.score);


  },
  methods:{
    back(){
      // this.$router.back();
      this.$router.go(-1); // go(-1) 等价于 back
    }
  }
}
</script>

<style>

</style>
// Mine.vue
<template>
  <div>
      <h2>Mine</h2>
  </div>
</template>

<script>
export default {
  data(){
    return{
    }
  },
}
</script>

<style>

</style>
// NotFount.vue
<template>
  <div>
      <h2>404</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// App.vue
<template>
  <div id="app">
    <router-link to="/home" active-class="active">home</router-link> &nbsp;
    <router-link to="/about" active-class="active">about</router-link> &nbsp;
    <router-link to="/mine" active-class="active">mine</router-link> &nbsp;
    <hr>
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
  data(){
    return{
    }
  },
  methods:{
  
  },
  components: {
  },
};
</script>

<style lang="less">
.active{
  color: red;
}
</style>

路由导航守卫

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
全局的前置守卫beforeEach是在导航触发时会被回调的:

  • to:即将进入的路由Route对象
  • from:即将离开的路由Route对象
  • next: 在Vue2中我们是通过next函数来决定如何进行跳转的,是在Vue3中我们是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next;
// /router/index.js
import VueRouter from "vue-router";
import Vue from "vue";

import Home from "../components/Home"
import About from "../components/About"
import Mine from "../components/Mine"
import Login from "../components/Login"
import NotFount from "../components/NotFount"

Vue.use(VueRouter);

let routes = [
    { path:"/", redirect:"/home" },
    { path:"/home", name:"home", component:Home },
    { path:"/about", name:"about", component:About },
    { path:"/mine", name:"mine", component:Mine },
    { path:"/login", name:"login", component:Login },
    { path:"*", component:NotFount },
];

let router = new VueRouter({
    // hash带#    
    // history不带#
    mode:"history",
    routes
})

// 配置全局路由守卫
// to表示去哪
// from表示从哪里来
// next表示是否放行  放行到哪里
router.beforeEach((to,from,next)=>{
    // console.log("from:",from);
    // console.log("to:",to);
    if(to.path !== "/login"){
        // 去的地方不是/login
        // 只有登录了,才能去/home /about /mine
        if(window.isLogin){
            // 表示已登录
            next();
        }else{
           return next("/login");
        }
    }
    next();
});

export default router;
// Home.vue
<template>
  <div>
    <h2>Home</h2>
  </div>
</template>

<script>
export default {
  methods: {
    toAbout() {
     
    },
  },
};
</script>

<style>
</style>
// About.vue
<template>
  <div>
      <h2>About</h2>
  </div>
</template>

<script>
export default {
  methods:{
  }
}
</script>

<style>

</style>
// Mine.vue
<template>
  <div>
      <h2>Mine</h2>
  </div>
</template>

<script>
export default {
  data(){
    return{
    }
  },
}
</script>

<style>

</style>
// Login.vue
<template>
  <div>
      <button @click="login">登录</button>
  </div>
</template>

<script>
export default {
    methods:{
        login(){
            // 给GO上放一个isLogin是true
            window.isLogin = true;
        }
    }
}
</script>

<style>

</style>
// NotFount.vue
<template>
  <div>
      <h2>404</h2>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
// App.vue
<template>
  <div id="app">
    <router-link to="/home" active-class="active">home</router-link> &nbsp;
    <router-link to="/about" active-class="active">about</router-link> &nbsp;
    <router-link to="/mine" active-class="active">mine</router-link> &nbsp;
    <hr>
    <router-view />
  </div>
</template>

<script>
export default {
  name: "App",
  data(){
    return{
    }
  },
  methods:{
  
  },
  components: {
  },
};
</script>

<style lang="less">
.active{
  color: red;
}
</style>

其他导航守卫:

完整的导航解析流程:

  • 导航被触发。
  • 在失活的组件里调用 beforeRouteLeave 守卫。
  • 调用全局的 beforeEach 守卫。
  • 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  • 在路由配置里调用 beforeEnter。
  • 解析异步路由组件。
  • 在被激活的组件里调用 beforeRouteEnter。
  • 调用全局的 beforeResolve 守卫(2.5+)。
  • 导航被确认。
  • 调用全局的 afterEach 钩子。
  • 触发 DOM 更新。
  • 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

三、过渡动画

Vue的transition动画

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点

当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理

  • 自动嗅探目标元素是否应用了CSS过渡或者动画,如果有,那么在恰当的时机添加/删除 CSS类名
  • 如果 transition 组件提供了JavaScript钩子函数,这些钩子函数将在恰当的时机被调用
  • 如果没有找到JavaScript钩子并且也没有检测到CSS过渡/动画,DOM插入、删除操作将会立即执行

过渡动画class

  • v-enter-from:定义进入过渡的开始状态
    • 在元素被插入之前生效,在元素被插入之后的下一帧移除。
  • v-enter-active:定义进入过渡生效时的状态,
    • 在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线 函数
  • v-enter-to:定义进入过渡的结束状态
    • 在元素被插入之后下一帧生效 (与此同时 v-enter-from 被移除),在过渡/动画完成之后移除
  • v-leave-from:定义离开过渡的开始状态
    • 在离开过渡被触发时立刻生效,下一帧被移除
  • v-leave-active:定义离开过渡生效时的状态
    • 在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟 和曲线函数
  • v-leave-to:离开过渡的结束状态
    • 在离开过渡被触发之后下一帧生效 (与此同时 v-leave-from 被删除),在过渡/动画完成之后移除

请添加图片描述
class的name命名规则如下

  • 如果我们使用的是一个没有name的transition,那么所有的class是以 v- 作为默认前缀
  • 如果我们添加了一个name属性,比如 ,那么所有的class会以 wc- 开头
// App.vue
<template>
  <div>
    <button @click="show = !show">点击我切换显示与隐藏</button>
    <!-- transiton:组件,全局组件。可以在任意组件内直接使用-->
    <!-- name属性值:如果页面中有多个多度动画需求,区分样式类名。 如果没有书写name,默认类名v-xxx开头,
       如果有name属性值,类名就以name属性值开头使用。这样可以去多个过渡动画效果!!!
     -->
    <transition name="jch">
      <div class="box" v-show="show">
        <h3>我是H3标题</h3>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: "",
  data() {
    return {
      show: false,
    };
  },
};
</script>

<!-- 在style标签身上加上一个lang=less属性,代表style里面书写的less样式 -->
<!-- 进入阶段的过渡动画 -->
<style scoped lang="less">
@color: cyan;
@f: red;
.box {
  width: 400px;
  height: 200px;
  background: @color;
  h3 {
    color: @f;
  }
}
/* 进入阶段的过渡动画*/
/*进入开始阶段*/
.jch-enter {
  opacity: 0;
  transform: rotate(0deg);
}

/* 定义进入阶段过渡动画时间、速率类名地方*/
.jch-enter-active {
  /*定义过渡动画时间、速率等等*/
  transition: all 5s;
}

/*进入结束阶段*/
.jch-enter-to {
  opacity: 1;
  transform: rotate(360deg);
}

/*定义离开阶段的过渡动画*/
/*
  离开阶段的开始状态
*/
.jch-leave {
  opacity: 1;
  transform: scale(1);
}

/* 定义离开阶段过渡动画时间、速率类名地方*/
.jch-leave-active {
  transition: all 3s;
}
/*离开阶段的结束状态*/
.jch-leave-to {
  opacity: 0;
  transform: scale(0);
}
</style>

过渡动画遮罩层

// components/ElDialog.vue
<template>
  <div>
    <transition>
      <div class="mask" v-show="visible"></div>
    </transition>
  </div>
</template>

<script>
export default {
  name: "",
  props: ["visible"],
};
</script>

<style scoped>
.mask {
  position: fixed;
  left: 20%;
  top: 20%;
  right: 20%;
  bottom: 20%;
  background: rgba(0, 0, 0, 0.5);
  z-index: 1000;
}

.v-enter {
  transform: scale(0);
}

.v-enter-active {
  transition: all 2s;
}

.v-enter-to {
  transform: scale(1);
}

.v-leave{
 transform: scale(1);
 border-radius: 0px;
}
.v-leave-active{
  transition: all 2s;
}
.v-leave-to{
 transform: scale(0);
 border-radius:50%;
}
</style>
// App.vue
<template>
  <div>
       <button @click="visible=!visible">我是按钮需要遮罩层组件</button>
       <ElDialog :visible="visible"></ElDialog>
  </div>
</template>

<script>
import ElDialog from '@/components/ElDialog'
export default {
  name: '',
  data() {
    return {
      visible:false
    }
  },
  components:{
    ElDialog
  }
}
</script>

<style scoped>

</style>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值