1. Vue
1.1 Vue的特点
- 遵循
MVVM
模式 - 编码简洁,体积小,运行效率高,适合移动/PC端开发
- 它本身只关注UI,可以引入其它
第三方库
开发项目
1.2 与其他JS框架的关联
- 借鉴 Angular 的
模板
和数据绑定
技术 - 借鉴 React 的
组件化
和虚拟DOM
技术
1.3 数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据绑定</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
单向数据绑定:<input type="text" v-bind:value="name"><br>
双向数据绑定:<input type="text" v-model:value="name">
</div>
<script>
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
name:'JOJO'
}
})
</script>
</body>
</html>
总结:
-
Vue中有2种数据绑定的方式:
- 单向绑定(
v-bind
):数据只能从data流向页面 - 双向绑定(
v-model
):数据不仅能从data流向页面,还可以从页面流向data
- 单向绑定(
-
备注:
- 双向绑定一般都应用在
表单类元素
上(如:<input>、<select>、<textarea>
等) v-model:value
可以简写为v-model
,因为v-model
默认收集的就是value值
- 双向绑定一般都应用在
1.4 el与data的两种写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>el与data的两种写法</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>Hello,{{name}}!</h1>
</div>
<script>
Vue.config.productionTip = false
//el的两种写法:
// const vm = new Vue({
// // el:'#root', //第一种写法
// data:{
// name:'JOJO'
// }
// })
// vm.$mount('#root')//第二种写法
//data的两种写法:
new Vue({
el:'#root',
//data的第一种写法:对象式
// data:{
// name:'JOJO'
// }
//data的第二种写法:函数式
data(){
return{
name:'JOJO'
}
}
})
</script>
</body>
</html>
总结:
-
el有2种写法:
- 创建Vue实例对象的时候配置el属性
- 先创建Vue实例,随后再通过
vm.$mount('#root')
指定el的值
-
data有2种写法:
- 对象式
- 函数式
-
如何选择:目前哪种写法都可以,以后学到组件时,
data必须使用函数
,否则会报错
1.5 MVVM模型
MVVM模型:
- M:模型(Model),data中的数据
- V:视图(View),模板代码
- VM:视图模型(ViewModel),Vue实例
1.6 Vue中的数据代理
总结:
- Vue中的数据代理通过vm对象来代理data对象中属性的操作(读/写)
- Vue中数据代理的好处:更加方便的操作data中的数据
- 基本原理:
- 通过
object.defineProperty()
把data对象中所有属性添加到vm上。 - 为每一个添加到vm上的属性,都指定一个getter/setter。
- 在getter/setter内部去操作(读/写)data中对应的属性。
- 通过
1.7 监听属性 VS 计算属性
使用计算属性:
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName(){
return this.firstName + '-' + this.lastName
}
}
})
使用监听属性:
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
fullName:'张-三'
},
watch:{
firstName(val){
setTimeout(()=>{
this.fullName = val + '-' + this.lastName
},1000);
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
})
总结:
-
computed
和watch
之间的区别:computed
能完成的功能,watch
都可以完成watch
能完成的功能,computed
不一定能完成,例如:watch
可以进行异步操作
-
两个重要的小原则:
- 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
- 所有
不被Vue所管理的函数
(定时器的回调函数、ajax的回调函数等、Promise的回调函数
),最好写成箭头函数
,这样this的指向才是vm 或 组件实例对象。
1.8 绑定样式
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
mood:'normal',
classArr:['atguigu1','atguigu2','atguigu3'],
classObj:{
atguigu1:false,
atguigu2:false,
},
styleObj:{
fontSize: '40px',
color:'red',
},
styleObj2:{
backgroundColor:'orange'
},
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
},
methods: {
changeMood(){
const arr = ['happy','sad','normal']
const index = Math.floor(Math.random()*3)
this.mood = arr[index]
}
},
})
</script>
1.9 key的作用与原理
面试题: react
、vue
中的key有什么作用?(key的内部原理)
-
虚拟DOM中key的作用:key是虚拟DOM中
对象的标识
,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下: -
对比规则:
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 若虚拟DOM中内容没变, 直接使用之前的真实DOM
- 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
-
用index作为key可能会引发的问题:
- 若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低
- 若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题
-
开发中如何选择key?
- 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的
1.10 过滤器
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>过滤器</title>
<script type="text/javascript" src="../js/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
</head>
<body>
<div id="root">
<h2>时间</h2>
<h3>当前时间戳:{{time}}</h3>
<h3>转换后时间:{{time | timeFormater()}}</h3>
<h3>转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}</h3>
<h3>截取年月日:{{time | timeFormater() | mySlice}}</h3>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,11)
})
new Vue({
el:'#root',
data:{
time:1626750147900,
},
//局部过滤器
filters:{
timeFormater(value, str="YYYY年MM月DD日 HH:mm:ss"){
return dayjs(value).format(str)
}
}
})
</script>
</html>
1.11 v-cloak指令
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>v-cloak指令</title>
<style>
[v-cloak]{
display:none;
}
</style>
</head>
<body>
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
</script>
</html>
总结:
v-cloak
指令(没有值):
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉
v-cloak
属性 - 使用css配合
v-cloak
可以解决网速慢时页面展示出{{xxx}}
的问题
1.12 自定义指令
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>自定义指令</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<!--
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
-->
<body>
<div id="root">
<h2>当前的n值是:<span v-text="n"></span> </h2>
<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
<button @click="n++">点我n+1</button>
<hr/>
<input type="text" v-fbind:value="n">
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{
n:1
},
// 第一种写法:directives:{指令名:配置对象}
// 第二种写法:directives:{指令名:回调函数}
directives:{
//big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
big(element,binding){
console.log('big',this) //注意此处的this是window
element.innerText = binding.value * 10
},
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}
}
})
</script>
</html>
总结:
- 配置对象中常用的3个回调函数:
bind(element,binding)
:指令与元素成功绑定时调用inserted(element,binding)
:指令所在元素被插入页面时调用update(element,binding)
:指令所在模板结构被重新解析时调用
- 备注:
- 指令定义时不加“v-”,但使用时要加“v-”
- 指令名如果是多个单词,要使用
kebab-case
命名方式,不要用camelCase
命名
new Vue({ el:'#root', data:{ n:1 }, directives:{ 'big-number'(element,binding){ element.innerText = binding.value * 10 } } })
1.13 Vue生命周期
2. VueComponent
关于VueComponent
:
- school组件本质是一个名为
VueComponent
的构造函数,且不是程序员定义的,是Vue.extend
生成的 - 我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:
new VueComponent(options)
- 特别注意:每次调用
Vue.extend
,返回的都是一个全新的VueComponent
! - 关于
this
指向:- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的
this
均是VueComponent实例对象
- new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的
this
均是Vue实例对象
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的
VueComponent
的实例对象,以后简称vc(也可称之为:组件实例对象)
Vue的实例对象,以后简称vm
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>一个重要的内置关系</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<school></school>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
Vue.prototype.x = 99
const school = Vue.extend({
name:'school',
template:`
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showX">点我输出x</button>
</div>
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
methods: {
showX(){
console.log(this.x)
}
},
})
const vm = new Vue({
el:'#root',
data:{
msg:'你好'
},
components:{school}
})
</script>
</html>
总结:
- 一个重要的内置关系:
VueComponent.prototype.__proto__ === Vue.prototype
- 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue 原型上的属性、方法
3. 使用Vue CLI脚手架
Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,请执行:
vue inspect > output.js
3.1 render函数
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
// 简写形式
render: h => h(App),
// 完整形式
// render(createElement){
// return createElement(App)
// }
})
总结:
关于不同版本的函数:
vue.js
与vue.runtime.xxx.js
的区别:vue.js
是完整版的 Vue,包含:核心功能+模板解析器vue.runtime.xxx.js
是运行版
的 Vue,只包含核心功能,没有模板解析器
- 因为
vue.runtime.xxx.js
没有模板解析器,所以不能使用template
配置项,需要使用render
函数接收到的createElement
函数去指定具体内容
3.2 plugin插件
src/plugin.js:
export default {
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//定义混入
Vue.mixin({
data() {
return {
x:100,
y:200
}
},
})
//给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = ()=>{alert('你好啊')}
}
}
src/main.js:
import Vue from 'vue'
import App from './App.vue'
import plugin from './plugin'
Vue.config.productionTip = false
Vue.use(plugin,1,2,3)
new Vue({
el:"#app",
render: h => h(App)
})
<template>
<div>
<h2>姓名:{{name | mySlice}}</h2>
<h2>性别:{{sex}}</h2>
<button @click="test">点我测试hello方法</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'JOJO-fdsfdf',
sex:'男'
}
},
methods:{
test() {
this.hello()
}
}
}
</script>
总结:
插件:
- 功能:用于增强Vue
- 本质:包含
install
方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据 - 定义插件:
plugin.install = function (Vue, options) { // 1. 添加全局过滤器 Vue.filter(....) // 2. 添加全局指令 Vue.directive(....) // 3. 配置全局混入 Vue.mixin(....) // 4. 添加实例方法 Vue.prototype.$myMethod = function () {...} Vue.prototype.$myProperty = xxxx }
- 使用插件:
Vue.use(plugin)
3.3 props
props
适用于:
- 父组件 ==> 子组件 通信
- 子组件 ==> 父组件 通信(要求父组件先给子组件一个函数)
- 使用
v-model
时要切记:v-model
绑定的值不能是props
传过来的值,因为props是不可以修改
的 props
传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做
3.4 自定义事件、解除自定义事件
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<button @click="sendStudentName">点我传递学生姓名</button>
<button @click="unbind">解绑自定义事件</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'JOJO',
sex:'男'
}
},
methods:{
sendStudentName(){
this.$emit('jojo',this.name)
},
unbind(){
// 解绑一个自定义事件
// this.$off('jojo')
// 解绑多个自定义事件
// this.$off(['jojo'])
// 解绑所有自定义事件
this.$off()
}
}
}
</script>
3.5 全局事件总线
全局事件总线是一种可以在任意组件间通信的方式,本质上就是一个对象。它必须满足以下条件:1. 所有的组件对象都必须能看见他 2. 这个对象必须能够使用
$on、$emit和$off
方法去绑定、触发和解绑事件
src/main.js:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
}
})
总结:
全局事件总线(GlobalEventBus):
- 一种组件间通信的方式,适用于
任意组件间通信
main.js
安装全局事件总线- 使用事件总线:
mounted
中接收数据this.$bus.$on('xxx',this.demo)
methods
提供数据this.$bus.$emit('xxx',data)
- 最好在
beforeDestroy
钩子中,用this.$bus.$off('demo')
去解绑当前组件所用到的事件
3.6 消息的订阅与发布
消息订阅与发布(pubsub
):
- 消息订阅与发布是一种组件间通信的方式,适用于
任意组件间通信
- 使用步骤:
- 安装pubsub:
npm i pubsub-js
- 引入:
import pubsub from 'pubsub-js'
- 接收数据:A组件
想接收数据
,则在A组件中订阅消息
,订阅的回调留在A组件自身
export default { methods(){ demo(data){...} } ... mounted() { this.pid = pubsub.subscribe('xxx',this.demo) } }
- 提供数据:
pubsub.publish('xxx',data)
- 最好在
beforeDestroy
钩子中,使用pubsub.unsubscribe(pid)
取消订阅
- 安装pubsub:
3.7 $nextTick
$nextTick(回调函数)
可以将回调延迟到下次 DOM 更新循环之后执行
<template>
<div>
<button v-show="!todo.isEdit" @click="handleEdit(todo)">编辑</button>
<div>
<span v-show="!todo.isEdit">{{ todo.title }}</span>
<input
type="text"
v-show="todo.isEdit"
:value="todo.title"
@blur="handleBlur(todo, $event)"
ref="inputTitle"
/>
</div>
</div>
</template>
<script>
export default {
name: 'MyItem',
data() {
return {
todo: {
isEdit: false,
title: '你好啊',
},
}
},
methods: {
handleEdit(todo) {
// 如果todo自身有isEdit属性就将isEdit改成true
if (Object.prototype.hasOwnProperty.call(todo, 'isEdit')) {
todo.isEdit = true
} else {
// 如果没有就向todo中添加一个响应式的isEdit属性并设为true
this.$set(todo, 'isEdit', true)
}
// 当Vue重新编译模板之后执行$nextTick()中的回调函数
// 当todo中数据发生改变后,基于在新的todo数据生成的新dom上操作,需要在nextTick的回调函数中执行
// 如果直接写 this.$refs.inputTitle.focus() 无法在新的input上获取焦点
this.$nextTick(function () {
// 使input框获取焦点
this.$refs.inputTitle.focus()
})
},
// 当input框失去焦点时更新
handleBlur(todo, event) {
todo.isEdit = false
if (!event.target.value.trim()) return alert('输入不能为空!')
todo.title = event.target.value
},
},
}
</script>
总结:
$nextTick
:
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次 DOM 更新结束后执行其指定的回调
- 什么时候用:当
改变数据
后,要基于更新后的新DOM
进行某些操作
时,要在nextTick
所指定的回调函数中执行
3.8 slot插槽
总结:
- 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于==父组件 >
子组件
- 分类:默认插槽、具名插槽、作用域插槽
- 作用域插槽:
- 理解:
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定) - 具体编码:
父组件中: <Category> <template scope="scopeData"> <!-- 生成的是ul列表 --> <ul> <li v-for="g in scopeData.games" :key="g">{{g}}</li> </ul> </template> </Category> <Category> <template slot-scope="scopeData"> <!-- 生成的是h4标题 --> <h4 v-for="g in scopeData.aaaa" :key="g">{{g}}</h4> </template> </Category> 子组件中: <template> <div> <slot :aaaa="games"></slot> </div> </template> <script> export default { name:'Category', props:['title'], //数据在子组件自身 data() { return { games:['红色警戒','穿越火线','劲舞团','超级玛丽'] } }, } </script>
- 理解:
4. Vuex
概念:专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
4.1 基本使用
<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('ADD',this.n)
},
decrement(){
this.$store.commit('SUBTRACT',this.n)
},
incrementOdd(){
this.$store.dispatch('addOdd',this.n)
},
incrementWait(){
this.$store.dispatch('addWait',this.n)
},
},
}
</script>
<style>
button{
margin-left: 5px;
}
</style>
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {
addOdd(context,value){
console.log("actions中的addOdd被调用了")
if(context.state.sum % 2){
context.commit('ADD',value)
}
},
addWait(context,value){
console.log("actions中的addWait被调用了")
setTimeout(()=>{
context.commit('ADD',value)
},500)
},
}
//准备mutations对象——修改state中的数据
const mutations = {
ADD(state,value){
state.sum += value
},
SUBTRACT(state,value){
state.sum -= value
}
}
//准备state对象——保存具体的数据
const state = {
sum:0 //当前的和
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
4.2 四个map方法的使用
mapState
方法:用于帮助我们映射state
中的数据computed: { //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), },
mapGetters
方法:用于帮助我们映射getters
中的数据computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) },
mapActions
方法:用于帮助我们生成与actions
对话的方法,即:包含$store.dispatch(xxx)
的函数methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }
mapMutations
方法:用于帮助我们生成与mutations
对话的方法,即:包含$store.commit(xxx)
的函数methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
4.3 模块化+命名空间
- 目的:
让代码更好维护,让多种数据分类更加明确
- 修改
store.js
: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 } })
- 开启命名空间后,组件中读取数据:
// 1、读取state数据: //方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']), // 2、读取getters数据: //方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum']) // 3、调用dispatch: //方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) // 4、调用commit: //方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
5. Vue Router
5.1 路由的理解
-
什么是路由?
- 一个路由就是一组映射关系(key - value)
- key 为路径,value 可能是 function 或 componen
-
路由分类
- 后端路由:
- 理解:value 是 function,用于处理客户端提交的请求
- 工作过程:
服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据
- 后端路由:
-
前端路由:
- 理解:value 是 component,用于展示页面内容
- 工作过程:
当浏览器的路径改变时,对应的组件就会显示
5.2 路由的使用
- 安装
vue-router
,命令:npm i vue-router
- 应用插件:
Vue.use(VueRouter)
- 编写router配置项:
//引入VueRouter import VueRouter from 'vue-router' //引入Luyou 组件 import About from '../components/About' import Home from '../components/Home' //创建router实例对象,去管理一组一组的路由规则 const router = new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home } ] }) //暴露router export default router
- 实现切换(
active-class
可配置高亮样式):<router-link active-class="active" to="/about">About</router-link>
- 指定展示位:
<router-view></router-view>
5.3 路由的query参数
- 传递参数:
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法 --> <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }">跳转</router-link>
- 接收参数:
$route.query.id $route.query.title
5.4 命名路由
5.5 路由的params参数
5.6 路由的props配置
5.7 缓存路由组件
activated
和deactivated
是路由组件所独有的两个钩子,用于捕获路由组件的激活状态- 具体使用:
activated
路由组件被激活时触发deactivated
路由组件失活时触发
5.8 路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from) => { console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
-
独享守卫:
-
组件内守卫:
原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498