文章目录
一、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>
<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>
<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>
<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>
<router-link to="/about" active-class="active">about</router-link>
<router-link to="/mine" active-class="active">mine</router-link>
<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>
<router-link to="/about" active-class="active">about</router-link>
<router-link to="/mine" active-class="active">mine</router-link>
<hr>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
}
},
methods:{
},
components: {
},
};
</script>
<style lang="less">
.active{
color: red;
}
</style>
其他导航守卫:
- Vue还提供了很多的其他守卫函数,目的都是在某一个时刻给予我们回调,让我们可以更好的控制程序的流程或者功能
- https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html
完整的导航解析流程:
- 导航被触发。
- 在失活的组件里调用 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>