笔记
脚手架文件结构:
|—— node_modules
|—— public
| |—— favicon.ico:页签图标
| |—— index.html:主页面
|—— src
| |—— assets:存放静态资源
| | |—— logo.png
| |—— component:存放组件
| | |—— HelloWorld.vue
| |—— App.vue:汇总所有组件
| |—— main.js:入口文件
|—— .gitignore:git版本管理忽略的配置
|—— babel.config.js:babel的配置文件
|—— package.json:应用包配置文件
|—— README.md:应用描述文件
|—— package-lock.json:包版本控制文件
关于不同版本的Vue
-
vue.js与vue.runtime.xxx.js的区别:
(1)vue.js是完整的Vue,包含:核心功能+模板编译器
(2)vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板编译器
-
因为veu.runtime.xxx.js没有模板编译器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
vue.config.js配置文件
使用vue inspect>output.js可以查看脚手架的默认配置
使用veu.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh
ref属性
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
- 使用方式:
打标识:…
或
获取:this.$refs.xxx
配置项props
功能:让组件接收外部传过来的数据
(1)传递数据:
(2)接收数据:
第一种方式(只接受):
props:[‘name’,‘age’]
第二种方式(限制类型):
props:{
name:String,
age:Nember
}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String,
required:true,
default:'张三'
}
}
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发生警告
如果你想要修改传过来的数据,可以赋值给data内,再修改data内的数据
mixin(混入)
功能:可以把多个组件共用的配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){…},
methods:{…}
…
}
第二步使用混入,例如:
(1)全局混入:Vue.mixin(xxx)
(2)局部混入:mixins:[‘xxx’]
插件
功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
定义插件:
对象.install = function(Vue,options){
// 1.添加全局过滤器
Vue.filter(…)
// 2.添加全局指令
Vue.directive(...)
// 3.配置全局混入(合)
Vue.mixin(...)
// 4.添加实例方法
Vue.prototype.$myMethod = function(){...}
Vue.prototype.$myProperty = xxx
}
使用插件:Vue.use(plugins)
scoped样式
作用:让样式在局部生效,防止冲突
写法:
Todo-List 案例
组件化编码流程
- 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
- 实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一堆组件再用
- 一个组件在用:放在组件自身即可
- 一堆组件在用:放在他们共同的父组件上(状态提升)
- 实现交互:从绑定事件开始
**props
**适用于
a.父组件 ==> 子组件 通信
b.子组件 ==> 父组件 通信(要求父组件先給子组件一个函数)
使用**v-model
时要切记:v-model
绑定的值不能是props
传过来的值,因为props
是不可以修改的,props
传过来的值若是对象数据类型的值,修改对象中的属性时Vue
**不会报错,但不推荐使用
src/App.vue
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"/>
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
<MyFooter :todos="todos"
:checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>
</div>
</div>
</div>
</template>
<script>
import MyHeader from './components/MyHeader'
import MyList from './components/MyList'
import MyFooter from './components/MyFooter.vue'
export default {
name: 'App',
components: { MyHeader, MyList, MyFooter },
data() {
return {
// 由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
todos:[
{id:'001',title:'抽烟',done:true},
{id:'002',title:'喝酒',done:false},
{id:'003',title:'开车',done:true}
]
}
},
methods: {
//添加一个todo
addTodo(todoObj){
this.todos.unshift(todoObj)
},
//勾选or取消勾选一个todo
checkTodo(id){
this.todos.forEach((todo)=>{
if(todo.id === id) todo.done = !todo.done
})
},
//删除一个todo
deleteTodo(id){
this.todos = this.todos.filter( todo => todo.id !== id )
},
//全选or取消全选
checkAllTodo(done){
this.todos.forEach((todo)=>{
todo.done = done
})
},
//清除所有已经完成的todo
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
return !todo.done
})
}
}
}
</script>
<style>
/*base*/
body {background: #fff;}
.btn {display: inline-block;padding: 4px 12px;margin-bottom: 0;font-size: 14px;
line-height: 20px;text-align: center;vertical-align: middle;cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;}
.btn-danger {color: #fff;background-color: #da4f49;border: 1px solid #bd362f;}
.btn-danger:hover {color: #fff;background-color: #bd362f;}
.btn:focus {outline: none;}
.todo-container {width: 600px;margin: 0 auto;}
.todo-container .todo-wrap {padding: 10px;border: 1px solid #ddd;border-radius: 5px;}
</style>
src/components/MyHeader.veu
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认"
v-model="title" @keyup.enter="add"/>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name:'MyHeader',
props:['addTodo'], // 接收从App传递过来的addTodo
data() {
return {
title:'' // 收集用户输入的title
}
},
methods: {
add(){
// 校验数据
if(!this.title.trim()) return alert('输入不能为空')
// 将用户的输入包装成一个todo对象
const todoObj = { id:nanoid(), title:this.title, done:false }
// 通知App组件去添加一个todo对象
this.addTodo(todoObj)
// 清空输入
this.title = ''
}
},
}
</script>
<style scoped>
/*header*/
.todo-header input {width: 560px;height: 28px;font-size: 14px;
border: 1px solid #ccc;border-radius: 4px;padding: 4px 7px;}
.todo-header input:focus {outline: none;border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);}
</style>
src/components/MyList.vue
<template>
<ul class="todo-main">
<MyItem v-for="todoObj in todos":key="todoObj.id"
:todo="todoObj" :checkTodo="checkTodo":deleteTodo="deleteTodo"/>
</ul>
</template>
<script>
import MyItem from './MyItem'
export default {
name:'MyList',
components:{MyItem},
// 声明接收App传递的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件MyItem用的
props:['todos','checkTodo','deleteTodo']
}
</script>
<style scoped>
/*main*/
.todo-main {margin-left: 0px;border: 1px solid #ddd;border-radius: 2px;padding: 0px;}
.todo-empty {height: 40px;line-height: 40px;border: 1px solid #ddd;
border-radius: 2px;padding-left: 5px;margin-top: 10px;}
</style>
src/components/MyItem.vue
<template>
<li>
<label>
<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,因为修改了props -->
<!-- <input type="checkbox" v-model="todo.done"/> -->
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
<span>{{ todo.title }}</span>
</label>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
</li>
</template>
<script>
export default {
name:'MyItem',
//声明接收todo、checkTodo、deleteTodo
props:['todo','checkTodo','deleteTodo'],
methods: {
// 勾选or取消勾选
handleCheck(id){
this.checkTodo(id) // 通知App组件将对应的todo对象的done值取反
},
// 删除
handleDelete(id){
if(confirm('确定删除吗?')){
this.deleteTodo(id) // 通知App组件将对应的todo对象删除
}
}
},
}
</script>
<style scoped>
/*item*/
li {list-style: none;height: 36px;line-height: 36px;padding: 0 5px;
border-bottom: 1px solid #ddd;}
li label {float: left;cursor: pointer;}
li label li input {vertical-align:middle; margin-right:6px; position:relative;top: -1px;}
li button {float: right;display: none;margin-top: 3px;}
li:before {content: initial;}
li:last-child {border-bottom: none;}
li:hover{background-color: #ddd;}
li:hover button{display: block;}
</style>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qLMaHPI5-1661310261360)(C:\Users\11465\AppData\Roaming\Typora\typora-user-images\image-20220814220407532.png)]
webStorage
1.存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
2.浏览器端通过**Window.sessionStorage
和Window.localStorage
**属性来实现本地存储机制
3.相关API:
1.xxxx.Storage.setItem('key','value);
该方法接受一个键值对作为参数,会把键值对添加到存储中,如果键,名存在,则更新其对应的值
2.xxxx.Storage.getItem('key');
该方法接受一个键值对作为参数,返回键名对应的值
3.xxxx.Storage.removeItem('key');
该方法接受一个键值对作为参数,并把该键名从存储中删除
4.xxxx.Storage.clear();
该方法会清空存储中所有的数据
备注
1.sessionStorage存储的内容会随着浏览器窗口关闭而消失
2.localStorage存储的内容,需要手动清除才会消失
3.xxxxStorage.getItem('key')
如果key对应的value获取不到,那么getItem的返回值是null
4.JSON.parse(null)
的结果还是null
组件的自定义事件
1.一种组件间通信的方式,适用于:子组件 ----> 父组件
2.使用场景:子组件想给父组件传数据,那么就要在父组件中给子组件绑定自定义事件(事件的回调在A中)
3.绑定自定义事件
a.第一种方式:在父组件中**<Demo @事件名='回调'/>
或<Demo v-on:事件名='回调'/>
**
b.第二种方式:在父组件中this.$refs.demo.$on('事件','回调')
<Demo ref='demo'/>
...
mounted(){
this.$ref.demo.$on('atguigu',this.test)
}
c.若想让自定义事件只能触发一次,可以使用once
修饰符,或$once
方法
1.触发自定义事件this.$emit('事件名','数据')
2.解绑自定义事件this.$off('事件名')
3.组件上也可以绑定原生DOM事件,需要使用native修饰符 @click.native='show'
上面绑定自定义事件,即使绑定的是原生事件也会被认为是自定义的,需要叫native
,加了后就将此事件给组件的根元素
注意:通过this.$refs.demo.$on('事件名','回调')
绑定自定义事件时,回调函调要么配置在methods
中,要么用箭头函数,否则this指向会出问题
全局事件总线(GlobalEventBus)
-
一种组件间通信的方式,适用于任意组件间通信
-
安装全局事件总线:
new Vue({ ..... beforeCreate(){ Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm }, ..... })
-
使用事件总线:
-
接受数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){ demo(data){.....} } ...... mounted(){ this.$bus.$on('xxx',this.demo) }
-
提供数据:
this.$bus.$emit('xxx',数据)
-
-
最好在beforeDestroy钩子中,用$off去解绑当前组件所绑定的事件。
$nextTick
这是一个生命周期钩子
this.$nextTick(回调)
在下一次DOM更新结束后执行其指定的回调
什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick
所指定的回调函数中执行
过渡与动画
Vue
封装的过渡与动画:在插入、更新或移除DOM
元素时,在合适的时候给元素添加样式类名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E9mG1fjD-1661310261367)(C:\Users\11465\AppData\Roaming\Typora\typora-user-images\image-20220816104330293.png)]
写法
- 准备好样式
- 元素进入的样式
v-enter
进入的起点v-enter-active
进入过程中v-enter-to
进入的终点
- 元素离开的样式
v-leave
离开的起点v-leave-active
离开过程中v-leave-to
离开的终点
- 元素进入的样式
- 使用 包裹要过渡的元素,并配置 name属性,此时需要将上面样式名的v换为name
- 要让页面一开始就显示动画,需要添加appear
<transition name='hello' :appear='true'>
<h1 v-show='isShow'>你好啊</h1>
</transition>
<style>
.hello-enter-active {
animation: hello 1s linear;
}
.hello-leave-active {
animation: hello 1s linear reverse;
}
//动画帧
@keyframes hello {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0px);
}
}
</style>
-
备注:若有多个元素需要过渡,则需要使用==,且每一个元素都要指定key==值
<transition-group name='hello' :appear='true'> <h1 v-show='isShow' key='1'>你好啊</h1> <h1 v-show='!isShow' key='2'>尚硅谷</h1> </transition-group>
-
第三方动画库 Animate.css
Vue中的Ajax配置代理slot插槽
1.Vue脚手架配置代理
本案例需要下载 axios库 npm i axios
配置参考文档 Vue-Cli devServer.proxy
vue.config.js是一个可选的配置文件,如果项目的(和 package.json同级的)根目录中存在这个文件,那么它会被 @vue/cli-service自动加载。你也可以使用package.json中的Vue字段,但是注意这种写法需要你严格遵照JSON的格式来写
方法一
在vue.config.js中添加如下配置
module.exports = {
devServer:{
proxy:'http://localhost:5000'
}
}
说明
- 优点:配置简单,请求资源时直接发给前端(8080)即可
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,才会将请求会转发给服务器(优先匹配前端资源)
方法二
编写vue.config.js配置具体代理规则
module.exports = {
devServer:{
proxy:{
'/api1':{ //匹配所有以'/api1'开头的请求路径
target:'http://localhost:5000', //代理目标的基础路径
pathRewrite:{'^/api1':''}, //代理往后端服务器的请求去掉 /api1 前缀
ws:true, //WebSocket
changeOrigin:true,
},
'/api2':{
target:'http://localhost:5001',
pathRewrite:{'^/api2':''},
ws:true,
changeOrigin:true,
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/
说明
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理
- 缺点:配置略微繁琐,请求资源时必须加前缀
module.exports = {
pages:{
index:{
entry:'src/main.js',
}
},
lintOnsave:false,
// 开启代理服务器(方式1)
// devServer:{
// proxy:'http://localhost:5000'
// }
// 开启代理服务器(方式2)
devServer:{
proxy:{
'/api1':{
target:'http://localhost:5000',
pathRewrite:{'^/api1':''},
// ws:true, //用于支持webSocket,默认值为true
// changeOrigin:true, //用于控制请求头中host值,默认值为true
},
'/api2':{
target:'http://localhost:5001',
pathRewrite:{'^/api2':''},
}
}
}
}
src/App.vue
<template>
<div>
<button @click='getStudents'>获取学生信息</button>
<button @click='getCars'>获取汽车信息</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
name:'App',
methods:{
getStudents(){
axios.get('http://localhost:8080/demo/students').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
},
getCars(){
axios.get('http://localhost:8080/demo/cars').then(
response => {
console.log('请求成功了',response.data)
},
error => {
console.log('请求失败了',error.message)
}
)
},
}
}
</script>
。。。。。。。
Vuex
5.1.理解Vuex
5.1.1.Vuex是什么
- 概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
- Vuex Github地址
5.1.2.什么时候使用 Vuex
- 多个组件依赖同一状态
- 来自不同组件的行为需要变更同一状态
5.1.3.Vuex工作原理图
5.2.求和案例
5.2.1.使用纯 vue 编写
src/App.vue
<template>
<div>
<Count/>
</div>
</template>
<script>
import Count from "./components/Count.vue";
export default {
name: "App",
components: { Count },
};
</script>
src/components/Count.vue
<template>
<div>
<h2>当前求和为:{{ sum }}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "Count",
data() {
return {
sum: 0, // 当前的和
n: 1, // 用户选择的数字
};
},
methods: {
increment() {
this.sum += this.n;
},
decrement() {
this.sum -= this.n;
},
incrementOdd() {
if (this.sum % 2) {
this.sum += this.n;
}
},
incrementWait() {
setTimeout(() => {
this.sum += this.n;
}, 500);
},
},
};
</script>
<style>
button {margin-left: 5px;}
</style>
5.2.2.搭建 Vuex 环境
-
下载安装 vuex
npm i vuex@3
(适配vue2) -
创建
src/store/index.js
该文件用于创建 Vuex 中最核心的 storeimport Vue from 'vue' import Vuex from 'vuex' // 使用Vuex插件 Vue.use(Vuex) const actions = {} // 准备actions--用于响应组件中的动作 const nutations = {} // 准备mutations--用于操作数据 const state = {} // 准备state--用于存储数据 // 创建并暴露store export default new Vuex.store({ actions, mutations, state })
-
在
src/main.js
中创建 vm 时传入 store 配置项import Vue from 'vue' import App from './App.vue' import store from './store' // 引入store Vue.config.productionTip = false // 关闭生产提示 new Vue({ el:'#app', render:h => h(App), store, beforeCreate(){ Vue.prototype.$bus = this } })
5.2.3. 使用 Vuex 编写
Vuex的基本使用
-
初始化组件数据 state,配置 actions、mutations、操作文件 store.js
-
组件中读取 vuex 中的数据
$store.state.数据
-
组件中修改 vuex 中的数据
$store.dispatch('actions中的方法名',数据)
或$store.commit('mutations中的方法名',数据)
若没有网络请求或其他业务需求,组件中也可以跳过 actions,即不写 dispatch,直接编写 commit
src/store/index.js
该文件用于创建Vuex中最为核心的storeimport Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) // 应用Vuex插件 // 准备actions--用于响应组件中的动作 const actions = { /* jia(context,value){ console.log('actions中的jia被调用了') context.commit('JIA',value) }, jian(context,value){ console.log('actions中的jian被调用了') context.commit('JIAN',value) }, */ jiaOdd(context,value){ console.log('actions中的jiaOdd被调用了') if(value%2){ context.commit('JIA',value) } }, jiaWait(context,value){ console.log('actions中的jiaWait被调用了') setTimeout(()=>{ context.commit('JIA'.value) },500) } } // 准备mutations--用于操作数据 const mutations = { JIA(state,value){ state.sum += value }, JIAN(state,value){ state.sum -= value } } // 准备state--用于存储数据 const state = { sum:0, } // 创建并暴露store export default new Vuex.Store({ actions, mutations, state }
src/components/count.vue
<template> <div> <h1>当前求和为:{{ $store.state.sum }}</h1> <select v-model.number="n"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementOdd">当前求和为奇数再加</button> <button @click="incrementWait">等一等再加</button> </div> </template> <script> export default { name:'Count', data() { return { n:1, //用户选择的数字 } }, methods: { increment(){ this.$store.commit('JIA',this.n) }, decrement(){ this.$store.commit('JIAN',this.n) }, incrementOdd(){ this.$store.dispatch('jiaOdd',this.n) }, incrementWait(){ this.$store.dispatch('jiaWait',this.n) }, } } </script> <style lang="css">button{margin-left: 5px;}</style>
5. 3. getters 配置项
-
概念:当 state 中的数据需要加工后使用时,可以使用 getters 加工,相当于 全局计算属性
-
在
store.js
中追加getters
配置..... const getters = { bigSum(){ retuen state.sum * 10 } } // 创建并暴露store export default new Vuex.Store({ ..... getters })
-
组件中读取数据
$store.getters.bigSum
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 准备actions--用于响应组件的动作
const actions = {
addOdd(context,value){
console.log('action中的addOdd被调用了')
if(value%2){
context.commit('JIA',value)
}
},
addWait(context,value){
console.log('actions中的addWait被调用了')
setTimeout(()=>{
context.commit('JIA',value)
},500)
}
}
// 准备mutations--用于操作数据
const mutations = {
JIA(state,value){
state.sum += value
},
JIAN(state,value){
state.sum -= value
}
}
// 准备state--用于存储数据
const state = {
sum:0,
}
// 准备getters--用于将state中的数据进行加工
const getters = {
bigSum(){
return state.sum * 10
}
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
src/components/Count.vue
<template>
<div>
<h1>当前求和为:{{ $store.state.sum }}</h1>
<h3>当前求和的10倍为:{{ $store.getters.bigSum }}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data(){
return {
n:1,
}
},
methods:{
increment(){this.$store.commit('JIA',this.n)},
decrement(){this.$store.commit('JIAN',this.n)},
incrementOdd(){this.$store.dispatch('addOdd',this.n)},
incrementWait(){this.$store.dispatch('addWait',this.n)},
},
}
</script>
<style>button{margin-left: 5px;}</style>
5.4. 四个 map 方法的使用
-
mapState方法:用于帮助映射 state 中的数据为计算属性
src/components/Count.vue
..... computed:{ /* sum(){ return $store.state.sum }, school(){ return $store.state.school }, subject(){ return $store.state.subject }, */ // 借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), // 借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), }
-
mapGetters方法:用于帮助映射 getters 中的数据为计算属性
src/components/Count.vue
..... computed:{ /* bigSum(){ return $store.getters.bigSum } */ // 借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), // 借助maGetters生成计算属性:bigSum(数组写法) ...mapState(['bigSum']), }
-
mapActions方法:用于帮助生成与 actions 对话的方法,即包含
$store.dispatch(xxx)
的函数src/components/Count.vue
..... methods:{ /* incrementOdd() this.$store.dispatch('addOdd',this.n) }, incrementWait(){ this.$store.dispatch('addWait',this.n) }, */ // 借助mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'addOdd',incrementWait:'addWait'}), // 借助mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['addOdd','addWait']), }
-
mapMutations方法:用于帮助生成与 mutations 对话的方法,即包含
$store.commit(xxx)
的函数src/components/Count.vue
..... methods:{ /* increment(){ this.$store.commit('JIA',this.n) }, decrement(){ this.$store.commit('JIAN',this.n) }, */ // 借助mapMutations生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), // 借助mapActions生成:increment、decrement(数组形式) ...mapMutations(['JIA','JIAN']), }
注意:mapActions 与 mapMutations 使用时,若需要传递参数:在模板中绑定事件时传递好参数,否则参数是事件对象
src/components/Count.vue
<template> <div> <h1>当前求和为:{{ sum }}</h1> <h3>当前求和的10倍为:{{ bigSum }}</h3> <h3>我是{{ name }},我在{{ school }}学习</h3> <select v-model.number="n"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment(n)">+</button> <button @click="decrement(n)">-</button> <button @click="addOdd(n)">当前求和为奇数再加</button> <button @click="addWait(n)">等一等再加</button> </div> </template> <script> import {mapState,mapGetters,mapActions,mapMutations} from 'Vuex' export default { name:'App', data(){ return { n:0, //用户选择的数字 } }, computed:{ ...mapState(['sum','school','name']), ...mapGetters(['bigSum']) } methods:{ ...mapActions({incrementOdd:'addOdd',incrementWait:'addWait'}), ...mapMutations({increment:'JIA',decrement:'JIAN'}), } } </script> <style> button{ margin-left: 5px; } </style>
5.5. 多组共享数据案例
src/App.vue
<template>
<div>
<Count/><hr/>
<Person/>
</div>
</template>
<script>
import Count from "./components/Count.vue";
import Person from "./components/Person.vue";
export default {
name: "App",
components: { Count, Person },
};
</script>
src/store/index.js
该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const actions = {
jiaOdd(context,value){
console.log('actions中的jiaOdd被调用了')
if(context.state.sum % 2){
context.commit('JIA',value)
}
},
jiaWait(context,value){
console.log('actions中的jiaWait被调用了')
setTimeout(()=>{
context.commit('JIA',value)
},500)
}
}
//准备mutations——用于操作数据(state)
const mutations = {
JIA(state,value){
console.log('mutations中的JIA被调用了')
state.sum += value
},
JIAN(state,value){
console.log('mutations中的JIAN被调用了')
state.sum -= value
},
ADD_PERSON(state,value){
console.log('mutations中的ADD_PERSON被调用了')
state.personList.unshift(value)
}
}
//准备state——用于存储数据
const state = {
sum: 0,
school: '尚硅谷',
subject: '前端',
personList: []
}
//准备getters——用于将state中的数据进行加工
const getters = {
bigSum(state){
return state.sum*10
}
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
src/components/Count.vue
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h3>当前求和放大10倍为:{{ bigSum }}</h3>
<h3>我在{{ school }},学习{{ subject }}</h3>
<h3 style="color:red">Person组件的总人数是:{{ personList.length }}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">当前求和为奇数再加</button>
<button @click="incrementWait(n)">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
export default {
name:'Count',
data() {
return {
n:1, //用户选择的数字
}
},
computed:{
...mapState(['sum','school','subject','personList']),
...mapGetters(['bigSum'])
},
methods: {
...mapMutations({increment:'JIA',decrement:'JIAN'}),
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
}
}
</script>
<style lang="css">button{margin-left: 5px;}</style>
src/components/Person.vue
<template>
<div>
<h1>人员列表</h1>
<h3 style="color:red">Count组件求和为:{{ sum }}</h3>
<input type="text" placeholder="请输入名字" v-model="name">
<button @click="add">添加</button>
<ul>
<li v-for="p in personList" :key="p.id">{{ p.name }}</li>
</ul>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
import { mapState } from "vuex"
export default {
name:'Person',
data() {
return {
name:''
}
},
computed:{
personList(){return this.$store.state.personList},
sum(){return this.$store.state.sum}
},
methods: {
add(){
if (this.name === "") return
const personObj = {id:nanoid(),name:this.name}
this.$store.commit('ADD_PERSON',personObj)
this.name = ''
}
},
}
</script>
5.6. 模块化+命名空间
-
目的:让代码更好维护,让多种数据分类更加明确
-
修改
store.js
为了解决不同模块命名冲突问题,将不同模块的
namespaced:true
,之后在不同页面中引入getters
actions
mutations
时,需要加上所属的模块名const countAbout = { namespaced:true, // 开启命名空间 state:{x:1}, mutations:{...}, actions:{}, getters:{ bigSum(state){ return state.sum * 10 } } } const personAbout = { namespaced:true, state:{...}, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { countAbout, personAbout } })
-
开启命名空间后,组件中读取
state
数据// 方式1:自己直接读取 this.$store.state.personAbout.list // 方式2:借助mapState读取 ...mapState('countAbout',['sum','school','subject'])
-
开启命名空间后,组件中读取
getters
数据// 方式1:自己直接读取 this.$store.getters['personAbout/firstPersonName'] // 方式2:借助mapGetters读取 ...mapGetters('countAbout',['bigSum'])
-
开启命名空间后,组件中调用
dispatch
// 方式1:自己直接dispatch this.$store.dispatch('personAbout/addPersonwang',person) // 方式2:借助mapActions ...mapActions('counAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
-
开启命名空间后,组件中调用
commit
// 方式1:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) // 方式2:借助mapcommit ...mapcommit('counAbout',{increment:'JIA',decrement:'JIAN'})
Vue Router 相关理解 基本路由 多级路由
6.1 相关理解
6.1.1 vue-router 的理解
- vue 的一个插件库,专门用来实现 SPA 应用
6.1.2 对SPA应用的理解
-
单页 Web 应用(single page web application,SPA)
-
整个应用只有一个完整的页面
-
点击页面的导航链接不会刷新页面,只会做页面的局部更新
-
数据需要通过
ajax
请求获取
6.1.3 路由的理解
-
什么是路由?
a. 一个路由就是一组映射关系(key-value)
b. key 为路径,value 可能是 function 或 component
-
路由分类
a. 后端路由
- 理解:value 是 function,用于处理客户端提交的请求
- 工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据
b. 前端路由
- 理解:value 是 component,用于展示页面内容
- 工作过程:当浏览器的路径改变时,对应的组件就会显示
6.2 基本路由
-
安装 vue-router,
npm i vue-router@3
(和vue2对应) -
应用插件
Vue.use(VueRouter)
-
编写 router 配置项
import VueRouter from 'vue-router' // 引入VueRouter import About from '../components/About' // 路由组件 import Home from '../components/About' // 路由组件 // 创建router实例对象,去管理一组一组的路由规则 const router = new VueRouter({ routers:[ { path:'/about', component:About }, { path:'/home', component:Home } ] }) // 暴露router export default router
-
实现切换
<router-link></router-link>
浏览器会替换为 a 标签active-class
可配置高亮样式<router-link active-class='active' to='/about'>About</router-link>
-
指定展示位置
<router-view></router-view>
src/router/index.js
该文件用于创建整个应用的路由器
import VueRoutre from 'vue-router'
import About from '../compontents/About'
import Home from '../components/Home'
export default new VueRouter({
routers:[
{
path:'/about',
compontent:About
},
{
path:'/home',
component:Home
}
]
})
src/main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router' // 引入VueRouter插件
import router from './router' // 引入router路由器
Vue.config.productionTip = false
Vue.use(VueRouter) // 引用插件
new Vue({
el:'#app',
render:h => h(App),
router,
})
src/App.vue
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Vue Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!-- 原始html中我们使用a标签实现页面的跳转 -->
<!-- <a class="list-group-item active" href="./about.html">About</a> -->
<!-- <a class="list-group-item" href="./home.html">Home</a> -->
<!-- Vue中借助router-link标签实现路由的切换 -->
<router-link class="list-group-item"
active-class="active" to="/about">About</router-link>
<router-link class="list-group-item"
active-class="active" to="/home">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</div>
</div>
</div>
</div>
</template>
src/components/Home.vue
<template>
<h2>我是Home的内容</h2>
</template>
<script>
export default {
name:'Home'
}
</script>
src/components/About.vue
<template>
<h2>我是About的内容</h2>
</template>
<script>
export default {
name:'About'
}
</script>
6.3. 几个注意事项
-
路由组件通常存放在 pages 文件夹,一般组件通常存放在 components 文件夹
比如上一节的案例就可以修改为
src/pages/Home.vue
src/pages/About.vue
src/router/index.js
src/compontents/Banner.vue
src/App.vue
-
通过切换,”隐藏“了的组件,默认是被销毁掉的,需要的时候在去挂载
-
每一个组件都有自己的 $route 属性,里面存储着自己的路由信息
-
整个应用只有一个 router ,可以通过组件的 $router 属性获取到
src/router/index.js
// 该文件专门用于创建整个应用的路由器 import VueRouter from 'vue-router' import Home from '../pages/Home' import About from '../pages/About' export default new VueRouter({ routers:[ { path:'/home', componen:Home }, { path:'/about', component:About } ] })
src/components/Banner.vue
<template> <div class='col-xs-offset-2 col-xs-8'> <div class='page-header'><h2>Vue Router Demo</h2></div> </div> </template> <script> export default { name:'Banner', } </script>
src/App.vue
<template> <div> <div class="row"> <Banner/> </div> <div class="row"> <div class="col-xs-2 col-xs-offset-2"> <div class="list-group"> <!-- 原始html中我们使用a标签实现页面跳转 --> <!-- <a class="list-group-item active" href="./about.html">About</a> <a class="list-group-item" href="./home.html">Home</a> --> <!-- Vue中借助router-link标签实现路由的切换 --> <router-link class="list-group-item" active-class="active" to="/about"> About</router-link> <router-link class="list-group-item" active-class="active" to="/home"> Home</router-link> </div> </div> <div class="col-xs-6"> <div class="panel"> <div class="panel-body"> <!-- 指定组件的呈现位置 --> <router-view></router-view> </div> </div> </div> </div> </div> </template> <script> import Banner from './components/Banner.vue' export default { name:'App', components:{Banner} } </script>
6.4. 多级路由
-
配置路由规则,使用 children 配置项
src/router/index.js
import VueRouter from 'vue-router' import Home from '../pages/Home' import About from '../pages/About' import News from '../pages/News' import Message from '../pages/Message' export default new VueRouter({ routers:[ { path:'/home', component:Home, children:[ // 通过children配置子级路由 { path:'news', // 此处一定不要带 / ,因为会自动带上 component:News }, { path:'message', component:Message } ] }, { path:'/about', component:About } ] })
-
跳转(要写完整路径)
<router-link to='/home/news'>News</router-link>
src/pages/Home.vue
<template>
<div>
<h2>Home组件内容</h2>
<div>
<ul class="nav nav-tabs">
<li><router-link class="list-group-item"
active-class="active" to="/home/news">News</router-link></li>
<li><router-link class="list-group-item"
active-class="active" to="/home/message">Message</router-link></li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name:'Home',
}
</script>
src/pages/News.vue
<template>
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
</template>
<script>
export default {
name:'News'
}
</script>
src/pages/Message.vue
<template>
<ul>
<li>
<a href="/message1">message001</a>
</li>
<li>
<a href="/message2">message002</a>
</li>
<li>
<a href="/message/3">message003</a>
</li>
</ul>
</template>
<script>
export default {
name:'News'
}
</script>
src/router/index.js
import VueRouter from 'vue-router'
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
export default new VueRouter({
routers:[
{
path:'/home',
component:Home,
children:[ // 通过children配置子级路由
{
path:'news', // 此处一定不要带 / ,因为会自动带上
component:News
},
{
path:'message',
component:Message
}
]
},
{
path:'/about',
component:About
}
]
})
Vue Router query 命名路由 params props
6.5. 路由的 query 参数
-
传递参数
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法(推荐)--> <router-link :to="{ path:'/home/message/detail', query:{ id:m.id, title:m.title }}">跳转</router-link>
-
接收参数
$route.query.id $route.query.title
src/router/index.js
import VueRouter from 'vue-router'
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
path:'message',
component:Message,
children:[
{
path:'detail',
component:Detail
}
]
}
]
},
]
})
src/pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转并携带query参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link> -->
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link
:to="{
path:'/home/message.detail',
query:{
id:m.id,
title:m.title
}
}">{{m.title}}</router-link>
</li>
</ul>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message',
data(){
return {
messageList:[
{id:001,title:'消息001'},
{id:002,title:'消息002'},
{id:003,title:'消息003'}
]
}
}
}
</script>
src/pages/Detail.vue
<template>
<ul>
<li>消息编号:{{$route.query.id}}</li>
<li>消息标题:{{$route.query.title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail'
}
</script>
6.6. 命名路由
命名路由
-
作用:可以简化路由的跳转(to)
-
如何使用
a. 给路口命名
{ path:'/demo', component:Demo, children:[ { path:'test', component:Test, children:[ { name:'hello', // 给路由命名 path:'welcome', component:Hello, } ] } ] }
b. 简化跳转
<!-- 简化前,需要写完整的路径 --> <router-link to="/demo/test/welcome">跳转</router-link> <!-- 简化后,直接通过名字跳转 --> <router-link :to="{name:'hello'}">跳转</router-link> <!-- 简化写法配合传递参数 --> <router-link :to="{ name:'hello', query:{ id:666, title:'你好' } }">跳转 </router-link>
src/router/index.js
import VueRouter from "vue-router"; import Home from '../pages/Home' import About from '../pages/About' import News from '../pages/News' import Message from '../pages/Message' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News }, { path:'message', component:Message, children:[ { name:'detail', // name配置项为路由命名 path:'detail', component:Detail } ] } ] } ] })
src/pages/Message.vue
<template> <div> <ul> <li v-for="m in messageList" :key="m.id"> <!-- 跳转路由并携带query参数,to的字符串写法 --> <!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`"> {{m.title}} </router-link> --> <!-- 跳转路由并携带query参数,to的对象写法 --> <router-link :to="{ name:'detail', //使用name进行跳转 query:{ id:m.id, title:m.title } }"> {{m.title}} </router-link> </li> </ul> <hr/> <router-view></router-view> </div> </template> <script> export default { name:'News', data(){ return{ messageList:[ {id:'001',title:'消息001'}, {id:'002',title:'消息002'}, {id:'003',title:'消息003'} ] } } } </script>
6.7. 路由的 params 参数
-
配置路由,声明接收 params 参数
{ path:'/home', component:Home, children:[ { path:'news', component:News }, { path:'message', component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', // 使用占位符声明接受params参数 component:Detail } ] } ] }
-
传递参数
特别说明:路由携带params参数时,若使用to的对象写法时,则不能使用 path 配置项,必须使用 name 配置!
<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="`/home/message/detail/666/你好`">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:666, title:'你好' } }">跳转 </router-link>
-
接受参数
$route.params.id $route.params.title
src/router/index.js
import VueRouter from "vue-router"; import Home from '../pages/Home' import About from '../pages/About' import News from '../pages/News' import Message from '../pages/Message' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News }, { path:'message', component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', // 使用占位符声明接收params参数 component:Detail } ] } ] } ] })
src/pages/Message.vue
<template> <div> <ul> <li v-for="m in messageList" :key="m.id"> <!-- 跳转路由并携带params参数,to的字符串写法 --> <!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`"> {{m.title}} </router-link> --> <!-- 跳转路由并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:m.id, title:m.title } }"> {{m.title}} </router-link> </li> </ul> <hr/> <router-view></router-view> </div> </template> <script> export default { name:'News', data(){ return{ messageList:[ {id:'001',title:'消息001'}, {id:'002',title:'消息002'}, {id:'003',title:'消息003'} ] } } } </script>
src/pages/Detail.vue
<template> <ul> <li>消息编号:{{ $route.params.id }}</li> <li>消息标题:{{ $route.params.title }}</li> </ul> </template> <script> export default { name:'Detail' } </script>
6.8. 路由的 props 配置
props 作用:让路由组件更方便的收到参数
{ name:'xiangqing', path:'detil/:id', component:Detail, // 第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件 // props:{a:900} // 第二种写法:props值为布尔值,为true时,则把路由收到的所有params参数通过props传给Detail组件 // props:true // 第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件 props($route){ return { id:$route.query.id, title:$route.query.title } } }
src/router/index.js
import VueRouter from "vue-router"; import Home from '../pages/Home' import About from '../pages/About' import News from '../pages/News' import Message from '../pages/Message' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path: '/about', component: About }, { path:'/home', component:Home, children:[ { path:'news', component:News }, { path:'message', component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', component:Detail, // props的第一种写法,值为对象, // 该对象中的所有key-value都会以props的形式传给Detail组件 // props:{a:1,b:'hello'} // props的第二种写法,值为布尔值, // 若布尔值为真,会把该路由组件收到的所有params参数,以props的形式传给Detail组件 // props:true // props的第三种写法,值为函数 props(params) { // 这里可以使用解构赋值 return { id: params.id, title: params.title, } } } ] } ] } ] })
src/pages/Message.vue
<template> <div> <ul> <li v-for="m in messageList" :key="m.id"> <router-link :to="{ name:'xiangqing', params:{ id:m.id, title:m.title } }"> {{m.title}} </router-link> </li> </ul> <hr/> <router-view></router-view> </div> </template> <script> export default { name:'News', data(){ return{ messageList:[ {id:'001',title:'消息001'}, {id:'002',title:'消息002'}, {id:'003',title:'消息003'} ] } } } </script>
src/pages/Detail.vue
<template> <ul> <li>消息编号:{{ id }}</li> <li>消息标题:{{ title }}</li> </ul> </template> <script> export default { name:'Detail', props:[ 'id','title' ] } </script>
-
Vue Router replace 编程式导航 缓存路由组件
6.9. 路由跳转的 replace 方法
-
作用:控制路由跳转时操作浏览器历史记录的模式
-
浏览器的历史记录有两种写入方式:push 和 replace
push 是追加历史记录
replace 是替换当前记录,路由跳转时候默认是 push 方式
-
开启 replace 模式
<router-link :replace="true" ...>News</router-link>
简写
<router-link replace ...>News</router-link>
总结:浏览记录本质是一个栈,默认 push ,点开新页面就会在栈顶追加一个地址,后退,栈顶指针向下移动,改为 replace 就是不追加,而将栈顶地址替换
src/pages/Home.vue
<template>
<div>
<h2>Home组件内容</h2>
<div>
<ul class="nav nav-tabs">
<li>
<router-link replace class="list-group-item" active-class="active"
to="/home/news">News</router-link>
</li>
<li>
<router-link replace class="list-group-item" active-class="active"
to="/home/message">Message</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name:'Home'
}
</script>
6.10. 编程式路由导航(不用 <router-link>
)
作用:不借助 <router-link>
实现路由跳转,让路由跳转更加灵活
this.$router.push({})
内传的对象与 <router-link>
中的 to 相同
this.$router.replace({})
this.$router.forward()
前进
this.$router.back()
后退
this.$router.go(n)
可前进也可后退,n(步数)为正是进,为负是退
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
src/components/Banner.vue
<template>
<div>
<div>
<h2>Vue Router Demo</h2>
<button @click="back">后退</button>
<button @click="forward">前进</button>
<button @click="testGo">测试一下go</button>
</div>
</div>
</template>
<script>
export default {
name:'Banner',
methods:{
back(){
this.$router.back()
},
forward(){
this.$router.forward()
}.
test(){
this.$router.go(3)
},
}
src/pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
<button @click="showPush(m)">push查看</button>
<button @click="showReplace(m)">replace查看</button>
</li>
</ul>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'News',
data(){
return{
messageList:[
{id:'001',title:'消息001'},
{id:'002',title:'消息002'},
{id:'003',title:'消息003'}
]
}
},
methods:{
showPush(m){
this.$router.push({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
},
showReplace(m){
this.$router.replace({
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
})
}
}
}
</script>
6.11. 缓存路由组件
作用:让不展示的路由组件保持挂载,不被销毁
<keep-active inclue="News"><router-view></router-view></keep-active>
<keep-active inclue="['News','Message']"><router-view></router-view></keep-active>
// 缓存一个路由组件
<keep-alive include="News"> // include中写想要缓存的组件名,不写表示全部缓存
<router-view></router-view>
</keep-alive>
// 缓存多个路由组件
<keep-alive :include="['News','Message']">
<router-view></router-view>
</keep-alive>
src/pages/Home.vue
<template>
<div>
<h2>Home组件内容</h2>
<div>
<ul class="nav nav-tabs">
<li><router-link replace class="list-group-item" active-class="active"
to="/home/news">News</router-link></li>
<li><router-link replace class="list-group-item" active-class="active"
to="/home/message">Message</router-link></li>
</ul>
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
name:'Home'
}
</script>
Vue Router activated deactivated 路由守卫
6.12. activated deactivated
activated 和 deactivated 是路由组件所独有的两个钩子,用于捕获路由组件的激活状态
具体使用
- activated 路由组件被激活时触发
- deactivated 路由组件失活时触发
src/pages/News.vue
<template>
<ul>
<li :style="{opacity}"> 欢迎学习Vue</li>
<li>news001 <input type="text"/></li>
<li>news002 <input type="text"/></li>
<li>news003 <input type="text"/></li>
</ul>
</template>
<script>
export default {
name:'News',
data(){
return {
opacity:1
}
},
activated(){
console.log('News组件被激活了')
this.timer = setInterval(()=>{
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
deactivated(){
clearInterval(this.timer)
}
}
</script>
6.13. 路由守卫
作用:对路由进行权限控制
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫
====