Vue2+Vue3基础知识总结

Vue3新特性

setup()
新的配置项,值为一个函数,用于配置组件中所用到的所有数据、方法。若返回一个对象,则对象中的属性、方法在模板中均可以直接使用;若返回一个渲染函数,则可以自定义渲染内容(了解)。
注意:不建议和vue2的配置项混用;setup不能是一个async函数。
setup执行的时机:在beforeCreate之前执行一次,this是undefined。
setup的参数:props 值为对象,包含组件外部传递过来,且组件内部声明接收了的属性。
context:上下文对象;attr值为对象,包含租金按外部传递过来,但没有在props配置中声明的属性,相当于this.$attrsslots收到的插槽内容,相当于this.$slotsemit分发自定义事件的函数,相当于this.$emit
ref函数
作用:定义一个响应式数据的引用对象(reference对象,简称ref对象)
语法:
定义数据:const xxx = ref(initValue) js中操作数据 :xxx.value 模板中读取数据:<div>{{ xxx }}</div>
注意:接收的数据可以是基本类型也可以是对象类型;基本类型数据的响应式靠Object.defineProperty()getset实现;对象类型数据的响应式使用到了vue3中的reactive函数。
reactive函数
作用:定义一个对象类型的响应式数据(基本类型应该使用ref函数)
语法: const 代理对象 = reactive(源对象) 接受一个对象(或数组),返回一个代理对象(proxy对象)
特点:reactive定义的响应式数据是深层次的,内部基于ES6的Proxy实现,通过代理对象操作源对象数据。
计算属性与监视
computed函数
与vue2中computed配置功能一致
写法

import {computed} from 'vue'

setup() {
	...
	// 1)计算属性——简写
	let fullName = computed(() = {
		return person.firstName + '-' + person.lastName
	})
	// 2)计算属性——完整
	let fullName = computed(() => {
	get() {
		return person.firstName + '-' + person.lastName
	},
	set(value) {
		const nameArr = value.split('-')
		person.firstName = nameArr[0]
		person.lastName = nameArr[1]
	}
	})
}

watch函数
与vue2中watch配置功能一致
注意 1)监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)
2)监视reactive定义的响应式数据中某个属性时:deep配置有效

// 情况一:监视ref定义的响应式数据
watch(sum, (newValue, oldValue) => {
	console.log('sum变化了', newValue,oldValue)
}, {immediate:true})

// 情况二:监视多个ref定义的响应式数据
watch([sum, msg], (newValue, oldValue) => {
	console.log('sum或msg变化了', newValue,oldValue)
})

/* 情况三:监视reactive定义的响应式数据
		若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue
		若watch监视的是reactive定义的响应式数据,则强制开启了深度监视(deep属性无效)
*/
watch(person,(newValue,olaValue) => {
	console.log('person变化了',newValue, oldValue)
},{immediate:true, deep:false}) // 此处的deep配置不再奏效

// 情况四:监视reactive定义的响应式数据中的某个属性
watch(() =>person.job,(newValue,oldValue) => {
	console.log('person的job变化了',newValue,oldValue)
}{immediate:true,deep:true})

// 情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([()=> person.name, ()=>person.value],(newValue,oldValue)=> {
	console.log('person的name或age变化了',newValue,oldValue)
})

// 特殊情况
watch(()=>person.job, (newValue, oldValue) =>{
console.log('person的job变化了',newValue,oldValue)
}, {deep:true}) // 此处由于监视的是reactive所定义的对象中的某个属性,所以deep配置有效

watchEffect函数
watch函数的特点:既要指明监视的属性,也要指明监视的回调。
watchEffect函数的特点:不用指明监视哪个属性,监视的回调中用到哪个属性就会监视哪个属性。
watchEffect类似于computed,但computed注重计算出来的值(回调函数的返回值),所以必须要写返回值。而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

// watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调
watchEffect(() => {
	const x1 = sum.value
	const x2 = person.age
	console.log('watchEffect配置的回调执行了')
})

自定义hook函数
hook本质上是一个函数,把setup函数中使用的Composition API进行了封装。类似于vue2中的minxin,自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂。
toRef
作用:创建一个ref对象,其value值指向另一个对象中的某个属性。语法:const name = toRef(person, 'name') 应用:要将响应式对象中的某个属性单独提供给外部使用时。toRefstoRef功能一致,但可以批量创建多个ref对象,语法:toRefs(person)
shallowReactiveshallowRef
shallowReactive只处理对象最外层属性的响应式(浅响应式)。shallowRef只处理基本数据类型的响应式,不进行对象的响应式处理。如果有一个对象数据,结构比较深,但变化时只是外层属性变化,则考虑使用shallowReactive;如果有一个对象数据,后续功能不会修改该对象中的属性,而是生成新的对象来替换,考虑使用shallowRef
readonlyshallowReadonly readonly:让一个响应式数据变为只读的(深只读)。shallowReadonly:让一个响应式数据变为只读的(浅只读)。应用场景:不希望数据被修改时。
toRawmarkRaw
toRaw作用:将一个由reactive生成的响应式对象转为普通对象。使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作不会引起页面更新。
markRaw作用:标记一个对象,使其永远不会再成为响应式对象。应用场景:有些值不应被设置为响应式的,例如复杂的第三方类库等;当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
customRef:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制。
provideinject
作用:实现祖孙组件间通信,父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据。
isRef:检查一个值是否为一个ref对象
isReactive:检查一个对象是否是由reactive创建的响应式代理
isReadonly:检查一个对象是否是由readonly创建的只读代理
isProxy:检查一个对象是否是由reactive或者readonly方法创建的代理

Vue基础

01 Vue是什么?

Vue:一套用于构建用户界面的渐进式JavaScript框架
Vue的特点:
1.采用组件化模式,提高代码复用率,且让代码更好维护
2.声明式编码,让编程人员无需直接操作DOM,提高开发效率
3.使用虚拟DOM+优秀的Diff算法,尽量复用DOM节点

02 Vue实例的作用范围:

Vue会管理el选项命中的元素及其内部的后代元素

  1. el:用来设置Vue实例挂载的元素
    el的两种写法:
    (1)new Vue 时配置el属性
    (2)先创建Vue实例,随后再通过vm.$mount("#root")指定el的值
    el的写法规范:
    (1)可以使用其他选择器,建议使用ID选择器
    (2)可以使用其他双标签,不能使用HTML和BODY

  2. data:数据对象,Vue中用到的数据定义在data中
    data中可以写复杂类型的数据,渲染复杂类型的数据时,遵守js的语法即可。
    data的两种写法:

1)对象式:
data:{
name:""
}2)函数式:
data:function(){    //此处的this是Vue实例对象
return{
name:""}
}

注:组件运用时必须使用函数式。
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不是Vue实例了
1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象{el,data...}
2.容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
3.容器里的代码被称为Vue模板
4.Vue实例与挂载容器一一对应
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用
6.一旦数据发生改变,那么页面中用到该数据的地方也会自动更新

03 Vue模板语法

Vue模板语法有2大类:
1.插值语法:
功能:用于解析标签体内容
写法:{{xxx}} xxx是s表达式,xxx可以直接读取到data中的所有属性
2.指令语法:
功能:用于解析标签(标签属性,标签体内容,绑定事件…)

04 Vue数据绑定

Vue中有两种绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面
2.双向绑定(v-model): 数据不仅能从data流向页面,还可以从页面流向data
备注:v-model:value 简写为v-model,因为默认收集value值

05 MVVM模型

1.M: 模型(Model):data中的数据
2.V:视图(View):模板代码
3.VM:视图模型(ViewModel):Vue实例
data中所有的属性最后都出现在了VM身上
VM身上所有的属性及Vue原型上所有的属性,在Vue模板中都可以直接使用

06 数据代理

(1)数据代理
运用Object.defineProperty(操作对象,“属性名”,{配置项})方法
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
(2)Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
好处:更加方便操作data中的数据
基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上,为每一个添加到vm上的属性都指定一个getter/setter
getter/setter内部去操作data中对应的属性

07 事件处理

1.使用v-on绑定事件
2.事件的回调需要配置在methods对象中,最终会在vm上
3.methods中配置的函数都是Vue所管理的函数,this的指向是vm或组件实例对象
4.@click="demo($event)"可以实现传参

Vue中常用的事件修饰符:

prevent:阻止默认事件
stop:阻止事件冒泡
once:事件只触发一次
Vue常用的按键别名:
回车 =>enter
删除 =>delete(捕获“删除”和“退格”键)
退出 =>esc
空格 =>space
换行 =>tab(配合keydown使用)
上 =>up (下左右以此类推)

08 计算属性(computed)

1.定义:要用的属性不存在,要通过已有属性计算得来
2.原理:底层借助了Object.defineproperty方法提供的gettersetter
3.getter函数什么时候执行?
(1)初次读取时会执行一次
(2)当依赖的数据发生变化时会被再次调用
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
5.备注:
计算属性最终会出现在vm上,直接读取使用即可
如果计算属性要被修改,那么必须写set函数去响应修改,且set中要引起计算时依赖的数据发生变化。
只有考虑读取不考虑修改的情况下才可以使用计算属性的简写方式

computed:{
         // 计算属性靠返回值决定,所以一定要加上return!!!
          fullName(){
             return this.fullName = this.firstName + "-" +this.lastName
          }
},

10 监视属性

1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视
3.监视的两种写法:
(1)new Vue时传入watch配置
(2)通过Vm.$watch监视
4.深度监视:
(1)Vue中的watch默认不监测对象内部值的改变(一层)
(2)配置deep:true可以监测对象内部值的改变(多层)
5.备注:
Vue本身可以监测对象内部值的改变,但Vue提供的watch默认不可以,使用watch时根据数据的具体结构,决定是否采用深度检测。
watch里面的handler()什么时候调用?当监测对象发生改变时
immediate:true 初始化时让handler调用一下
deep:true 深度监测
没有下面两个属性时可以简写

computed和watch之间的区别

1.computed能完成的功能,watch都可以完成
2.watch能完成的功能,computed不一定能完成。例如:watch可以进行异步操作。
注意:
所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数、promise的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

11 绑定样式

1.class样式:

//(1)字符串写法:适用于样式的类名不确定,需要动态指定。
<class="basic"  :class="mood">
data数值 mood= "normal" 调用changeMood()

//(2)数组写法:适用于要绑定的样式个数不确定、名字也不确定。
<:class="classArr">
data数值 classArr["样式1""样式2""样式3"]

//(3)对象写法:适用于要绑定的样式个数确定、名字也确定,但要动态决定用不用
<:class="classObj">
data数值 classObj:{样式1false, 样式2: false}
//注:样式键名一定要是css文件里定义过的

2.style样式(了解):

// (1)对象写法:
<:style="styleObj">
data数值 styleObj:{样式1"", 样式2: ""}
//(2)数组写法:
<:style="styleArr">
data数值 styleArr:[{样式1:"",样式2:""},{styleObj2}],
//注:样式键名一定是符合js语法的,数组里面为样式对象

12 条件渲染

1.v-if/v-else-if/v-else
适用于:切换频率较低的场景
特点:不展示的DOM元素直接被移除
注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”
2.v-show
适用于:切换频率较高的场景
特点:不展示的DOM元素的样式被隐藏
注:使用template时只能与v-if连用

13 列表渲染

v-for指令
1.用于展示列表数据
2.语法:v-for="(item, index) in xxx" :key="yyy"
3.可遍历:数组(常用)、对象、字符串、指定次数

key的作用和原理

面试题:标题react、vue中的key有什么作用?(key的内部原理)

1.虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM旧虚拟DOM的差异比较,比较规则如下:
2.对比规则:
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:
a.若虚拟DOM中内容没变,直接使用之前的真实DOM
b.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
(2)旧虚拟DOM中未找到与新虚拟DOM相同的key:
创建新的真实DOM,随后渲染到页面
3.用index作为key可能会引发的问题:
(1)若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 =>页面效果没问题,但效率低
(2)如果结构中还包含输入类的DOM:会产生错误的DOM更新 => 界面有问题
4.开发中如何选择key?
(1)最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
(2)如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

Vue监视数据的原理

1.Vue会监视data中所有层次的数据。
2.如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1)对象中后追加的属性,Vue默认不做响应式处理。
(2)如需给后添加的属性做响应式,请使用如下API:

Vue.set(target, propertyName/index, value)
//或
vm.$set(target, propertyName/index, value)

3.如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
4.在Vue中修改数组中的某个元素一定要用如下方法:

1)使用这些API:push()、pop()、shift()、unshift()splice()、sort()、reverse()2)Vue.set()或vm.$set()
// 注意:Vue.set()或vm.$set()不能给vm或vm的根数据对象添加属性 

14 收集表单数据

若:<input type="text"/>,则v=model收集的是value值,即用户输入的值
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值
若:<input type="checkbox"/>,
(1)没有配置input的value属性,那么收集的就是checked(布尔值)
(2)配置input的value属性:
a.v-model的初始值是非数组,那么收集的就是checked
b.v-model的初始值是数组,那么手机的就是value组成的数组

***************************************************************
//备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤

15 过滤器

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)

语法:1.注册过滤器:Vue.filter(name,callback)new Vue(filter:{})
2.使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
******************************************
// 备注:1)过滤器也可以接收额外参数,多个过滤器也可以串联
(2)并没有改变原本的数据,是产生新的对应的数据。

16 内置指令

通过Vue实现常见的网页效果
Vue指令:以v-开头的一组特殊语法

1 内容绑定,事件绑定:v-text, v-html, v-on基础  >>计时器
2 显示切换,属性绑定:v-show,v-if,v-bind  >>图片切换
3 列表循环,表单元素绑定:v-for, v-on补充, v-model >>记事本

v-text指令的作用是:设置标签的文本值
默认写法会替换全部的内容,使用差值表达式 {{}} 可以替换指定内容
内部支持写表达式

v-html:设置标签的innerHTML
内容中有html结构会被解析为标签
v-text指令无论内容是什么只会解析为文本
与插值语法的区别:
(1)v-html会替换掉节点中所有的内容,{{xxx}}则不会
(2)v-html可以识别html结构
注意:v-html有安全性问题
(1)在网站上动态渲染任意html是非常危险的,容易导致xss攻击
(2)一定要在可信度内容上使用v-html,永远不要用在用户提交的内容上

v-cloak指令:(没有值)
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。

v-once指令:(没有值)
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2. 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

v-on:为元素绑定事件
指令可简写为@
绑定的方法定义在methods属性中
方法内部通过this关键字可以访问定义在data中的数据
补充:
事件绑定的方法写成函数调用的形式,可以传入自定义参数
定义方法时需要定义形参来接受传入的实参
事件的后面跟上 .修饰符 可以对事件进行限制
.enter 可以限制触发的按键为回车
事件修饰符有多种

v-show:根据真假切换元素的显示状态
原理是修改元素的display 实现显示隐藏
指令后面的内容,最终都会解析为布尔值
值为true元素显示,值为false元素隐藏
数据改变之后,对应元素的显示状态会同步更新

v-if:根据表达值的真假,切换元素的显示和隐藏(不是样式,而是操纵dom元素)
本质上是通过操纵dom元素来切换显示状态
表达式的值为true,元素存在于dom树中,为false,从dom树中移除
频繁的切换 v-show,反之使用v-if,前者的切换消耗小

v-bind:为元素绑定属性(如src title class)
v-bind:属性名= 表达式
简写为 :
需要动态的增删class建议使用对象的方式

v-for:根据数据生成列表结构
数组经常和v-for结合使用
语法是(item, index) in 数据
item代表每一项,index索引
数据:data中对应的数据
item和index可以结合其他指令一起使用
数组长度的更新会同步到页面上,是响应式的。

v-model:获取和设置表单元素的值(双向数据绑定)
绑定的数据会和表单元素值相关联
绑定的数据 <==>表单元素的值
只能应用在表单类元素(输入类元素)上

17 自定义指令

1.定义语法

1)局部指令:
new Vue({
directives:{指令名:配置对象}
})new Vue({
directives{指令名:回调函数}
})2)全局指令:
Vue.directive(指令名,配置对象) 
或
 Vue.directive(指令名,回调函数)
 
***************************************
<!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
     需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点 
-->
directives:{
	 big(element,binding) {
	      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;
	          // element.focus();
	      }
	  }
	}

2.配置对象中常用的3个回调:
(1)bind:指令与元素成功绑定时调用
(2)inserted:指令所在元素被插入页面时调用
(3)update:指令所在模板结构被重新解析时调用
3.备注:
(1)指令定义时不加v-,但使用时要加v-;
(2)指令名如果是多个单词,要使用kebab-case命名方式,不要使用cameCase命名。

18 生命周期

又名:生命周期回调函数、生命周期函数、生命周期钩子
是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
生命周期函数中的this指向是 vm组件实例对象

常用的生命周期钩子:
(1)mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
(2)beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
关于销毁Vue实例:
(1)销毁后借助Vue开发者工具看不到任何信息
(2)销毁后自定义事件会失效,但原生DOM事件依然有效
(3)一般不会在beforeDestroy操作数据,因为即使操作数据,也不会再触发更新流程了。

19 组件

  • 非单文件组件
    组件:实现应用中局部功能代码和资源的集合
    Vue中使用组件的三大步骤:
    (1)定义组件(创建组件)
    (2)注册组件
    (3)使用组件(写组件标签)

1.如何定义一个组件?
使用Vue.extend(options)创建,其中optionsnew Vue(options)时传入的那个options几乎一样,但也有点区别:
(1)el不要写,为什么?
最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
(2)data必须写成函数,为什么?
避免组件被复用时,数据存在引用关系
备注:使用template可以配置组件结构
2.如何注册组件?
(1)局部注册:靠new Vue的时候传入components选项
(2)全局注册:靠Vue.component("组件名",组件)
3.编写组件标签

        // 第一步:创建school组件
        const school = Vue.extend({
            // 组件一定不要写el配置项,因为最终所有的组件都要被vm所管理,由vm决定服务于哪个容器
            template:`
            <div>
                ...
            </div>
            `,
            data() {
                return {
                    ...
                }
            },
            methods: {
                ...
                }
            },
        })
        
 // 第二步:全局注册组件
 Vue.component("hello",hello)
 new Vue({
            el:"#root",
           ...
            // 第二步:注册组件(局部注册)
            components:{
                school,
                student
            },
        })
        
<!-- 第三步:编写组件标签 -->
        <school></school>


*****************************************************
几个注意点:
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)
备注:
(1)组件名尽可能回避HTML中已有的元素名称,例如h2,H2都不行。
(2)可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:<school></school>
第二种写法:<school/>
备注:不使用脚手架时,<school/>会导致后续组件不能渲染。
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options

关于VueComponent

1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
3.特别注意:每次调用Vue.extend,返回的都是一个全新的 VueComponent!!
4.关于this指向:
(1)组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是 VueComponent 的实例对象
(2)new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是Vue实例对象
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性、方法

Vue的网络应用:axios+vue

axios:网络请求库

axios原理

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

axios特性:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换JSON 数据
  • 客户端支持防御 XSRF

axios的使用

安装axios:npm install axios -save

// main.js:
// 1.axios的基本使用
import axios from "axios"
// 请求方式一: axios(config)
// 传入config对象
axios({
  // 默认发送get请求
  url:"...",
  params: {
    type:"pop",
    page:1
  },
  // method:"get"
}).then(res => {
  console.log(res);
})
********************************
// 请求方式二:axios.get(url[,config])
axios.get(地址?查询字符串).then(funtion(response){}, function(err){})
查询字符串拼接:key=value&key2=value2

axios.post(地址,参数对象).then
(function(response){},function(err){})
参数对象:{key:value,key2:value2}

**********************************************
key:由接口文档提供
value:具体传输的数据
axios必须先导入才可以使用
使用get或post方法即可以发送对应的请求
then方法中的回调函数会在请求成功或失败时触发
通过回调函数的形参可以获取响应内容,或错误信息

注意事项:

  • axios回调函数中的this指向已经改变,无法访问到data中数据。需要额外将this保存一份,回调函数中直接使用保存的this即可
  • 网络应用和本地应用最大的区别就是改变了数据来源
  • 页面的逻辑代码建议和页面分离,使用单独的js文件编写
  • 服务器返回的数据比较复杂时,获取的时候需要注意层级结构
  • 自定义参数可以让代码的复用性更高
  • 通过审查元素快速定位到需要操纵的元素
  • 响应式数据都需要在data中定义

有时候,我们可能需要同时发送两个请求:使用axios.all,可以放入多个请求的数组;axios.all([ ])返回的结果是一个数组,使用 axios.spread可将数组[res1,res2]展开为res1,res2

// 2.axios发送并发请求:多个请求到达后代码才可继续向下执行
axios.all([axios(), axios()])
.then(axios.spread((res1,res2) => {
  ...
}))

axios的请求和响应拦截器

  • 请求拦截器
    在请求发送前进行必要操作处理,例如添加统一cookie、请求体加验证、设置请求头等,相当于是对每个接口里相同操作的一个封装;
  • 响应拦截器
    同理,响应拦截器也是如此功能,只是在请求得到响应之后,对响应体的一些处理,通常是数据统一处理等,也常来判断登录失效等。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
  
如果你想在稍后移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

axios的全局配置

在开发中很多参数都是固定的,这个时候我们可以利用axios的全局配置抽取公共的部分

axios.defaults.baseURL = "..."
axios.defaults.timeout = 5000

axios的封装

在实际开发中,为了应对后续请求配置的变化,应当避免使用全局的axios和对应的配置进行网络请求,对axios进行封装,创建对应的axios实例,便于后期维护。

// 对axios的封装:src/network/request.js:

import axios from "axios"
export function request(config) {
  // 1.创建axios的实例
  const instance = axios.create({
    baseURL:"...",
    timeout:5000
  })
  // 发送真正的网络请求 原理:instance本身就是promise
  return instance(config)
}
 
***************************************************
// 实例的使用: main.js:
//封装request模块
import {request} from "./network/request";
request({
  url:"..."
}).then(res => {
  console.log(res); 
}).catch(err => {
  console.log(err);
})

官方文档

vue-cli

01 render函数

关于不同版本的Vue:
1.vue.js与vue.runtime.xxx.js的区别:
(1)vue.js是完整版的Vue,包含:核心功能+模板解析器
(2)vue.runtime.xxx.js是运行版的Vue,只包含:核心功能,没有模板解析器
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容

02 ref属性

1.被用来给元素或子组件注册引用信息(id的替代者)
2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3.使用方式:
打标识:<h1 ref="xxx">......</h1><School ref="xxx"></School>
获取:this.$refs.xxx

03 配置项props

功能:让组件接收外部传过来的数据(父子关系)

1)传递数据:
<Demo name="xxx"/>2)接收数据:
第一种方式(只接收):
props:["name"]
第二种方式(限制类型):
propos: {
name:String
}
第三种方式(限制类型、限制必要性、指定默认值):
props :{
name: {
type:String,
required:true,
default:"yyy"}
}

备注:props是只读的,Vue底层会检测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

04 mixin(混入)

功能:可以把多个组件共用的配置提取成一个混入对象
使用方式:

第一步定义混合,例如:
//minxin.js:
export const mixin = {
	data(){...},
    methods: {
        showName() {
            ...
        }      
    },
}

***********************************
第二步使用混合,例如:
import {mixin} from "../mixin"1)全局混入:Vue.mixin(mixin)2)局部混入:mixins:[mixin]

05 插件

功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
定义插件:
对象.install = function(Vue,options) {配置项...}
使用插件:Vue.use()

06 scoped样式

作用:让样式在局部生效,防止冲突。
写法:<style scoped>

总结TodoList案例

1.组件化编码流程:
(1)拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
1)一个组件在用:放在组件自身即可。
2)一些组件在用:放在它们共同的父组件上(状态提升)。
(3)实现交互:从绑定事件开始
2.props适用于:
(1)父组件 =>子组件 通信
(2)子组件 =>父组件 通信(要求父先给子一个函数)
3.使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
4.props传过来的若是对象类型的值,修改对象中的属性时Vue不会不报错,但不推荐这样做。

07 浏览器本地存储WebStorage

1.存储内容一般支持5MB左右
2.浏览器通过Window.sessionStorageWindow.localStorage属性来实现本地存储机制。
备注:
1.sessionStorage存储的内容会随着浏览器窗口关闭而消失
2.localStorage存储的内容需要手动清除才会消失。
3.如果key对应的value获取不到,返回值为null
4.JSON.parse(null)的结果依然是null

08 组件的自定义事件

1.一种组件间通信的方式,适用于:子组件 =>父组件
2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)
3.绑定自定义事件:

1)第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>2)第二种方式,在父组件中:
<Demo ref="demo"/>
...
mounted(){
this.$refs.demo.$on("atguigu",this.test)
}

(3)若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法
4.触发自定义事件:this.$emit("atguigu",数据)
5.解绑自定义事件:this.$off("atguigu")
6.组件上也可以绑定原生DOM事件,需要使用native修饰符
7.注意:通过this.$refs.xxx.$on("atguigu",回调)绑定自定义事件时,回调要么配置在methos中,要么用箭头函数,否则this指向会出问题!

09 全局事件总线

1.一种组件间通信的方式,适用于任意组件间通信
2.安装全局事件总线

new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})

3.使用事件总线:

1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
methods() {
demo(data){....}
}
....
mounted() {
this.$bus.$on("xxxx",this.demo)
}2)提供数据:this.$bus.$emit("xxxx",数据)

4.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

10 消息订阅与发布(pubsub)

1.一种组件间通信方式,适用于任意组件间通信
2.使用步骤:
(1)安装 pubsub:npm i pubsub-js
(2)引入:import pubsub from "pubsub-js"
(3)接收数据:

// A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods() {
demo(data) {...}
}
....
mounted() {
this.pid = pubsub.subscribe("xxx",this.demo) //订阅消息
}

(4)提供数据:pubsub.publish("xxx",数据)
(5)最好在beforeDestroy钩子中,用Pubsub.unsubscribe(pid)去取消订阅。

11 nextTick

1.语法:this.$nextTick(回调函数)
2.作用:在下一次DOM更新结束后执行其指定的回调
3.什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行

12 Vue封装的过渡与动画

作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
写法:

// 1.准备好样式:1)元素进入的样式:
v-enter:进入的起点
v-enter-active:进入的过程中
v-enter-to:进入的终点
(2)元素离开的样式:
v-leave:离开的起点
v-leave-active:离开的过程中
v-leave-to:离开的终点
// 2.使用<transition>包裹要过渡的元素,并配置name属性:
<transition name="hello">
	<h1 v-show="isShow">你好啊!</h1>
</transition>
// 3.备注:若有多个元素需要过渡,则需要使用:<transition-group>,
且每个元素都要指定key值。

13 Vue脚手架配置代理

【方法一】

// 在vue.config.js中添加如下配置:
  devServer: {
        proxy: 'http://localhost:5000'
    }

说明:
1.优点:配置简单,请求资源时直接发给前端(8080)即可。
2.缺点:不能配置多个代理,不能灵活地控制请求是否走代理。
3.工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(优先匹配前端资源

【方法二】

// 编写vue.config.js配置具体代理规则:
devServer: {
        proxy: {
          '/api1': {  // 匹配所有以"/api1"开头的请求路径
            target: 'http://localhost:5000',  //代理目标的基础路径
            pathRewrite:{"^/api1":""},
            ws: true, //默认为true
            changeOrigin: true // 默认为true
          },

          '/api2': { //匹配所有以“/api2”开头的请求路径
            target: 'http://localhost:5001',
            pathRewrite:{"^/api2":""},
          },
/*
changeOrigin设置为 true 时,服务器收到的请求中的host为:localhost:5000
changeOrigin设置为 false 时,服务器收到的请求中的host为:localhost:8080
*/

说明:
1.优点:可以配置多个代理,且可以灵活的控制请求是否走代理
2.缺点:配置略微繁琐,请求资源时必须加前缀

14 ajax请求的几种方式

1.xhr (最原始)
2.jQuery的封装
3.axios(常用)
4.fetch(与xhr平级)
5.vue-resourse(vue的一个库,对xhr的封装,不再维护)
安装:npm i vue-resourse (安装失败了)
在main.js中导入:import vueResourse form "vue-resourse"
使用:Vue.use(vueResourse)
安装成功后,vm及所有vc身上都会带有$http属性
发送请求方法:同axios,将所有axios替换成this.$http即可

15 插槽

1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件=>子组件
2.分类:默认插槽、具名插槽、作用域插槽
3.使用方式:

1)默认插槽:
// 父组件中:
<Category>
	<div>html结构1</div>
</Category>
// 子组件中:
<template>
	<div>
		<slot>插槽默认内容</slot>
	</div>
</template>2)具名插槽:
// 父组件中:
<Category>
      <!-- 使用具名插槽必须使用template结构 -->
      <template slot="center">
        <div>html结构1</div>
      </template>
      <!-- 两种写法 -->
      <template v-slot:footer>
        <div>html结构2</div>
      </template>
    </Category>
// 子组件中:
<template>
    <div>        
        <!-- 定义一个插槽 -->
        <slot name="center">插槽默认内容</slot>
        <slot name="footer">插槽默认内容</slot>
    </div>
</template>3)作用域插槽:
// 1.理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
// (games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
2.具体编码:
// 父组件中:
<Category title="游戏">
      <!-- 使用作用域插槽必须加template结构  -->
      <template scope="message">
         <!-- 生成的是ul列表 -->
         <ul>
          <li v-for="(g,index) in message.games" :key="index">{{g}}</li>
        </ul> 
      </template>     
</Category>
<Category title="游戏">
        <!-- 解构赋值写法 -->
      <template scope="{games}">
          <!-- 生成的是h4标题 -->
          <h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
      </template>
</Category>

// 子组件中:
<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <!-- 定义一个插槽 -->
        <slot :games="games">如果没有设置结构则显示这句话</slot>
    </div>
</template>

<script>
export default {
    name:"Category",
    props:["title"],
   //数据在子组件自身
    data() {
      return {
        games:["红色警戒","穿越火线","劲舞团","超级玛丽"],
      }
    },    
}
</script>

vue-router

01路由

(1)理解:一个路由(route)就是一组映射关系(key-value),多个路由需要路由器(router)进行管理
(2)前端路由:key是路径,value是组件。

02 基本使用

(1)安装 vue-router,命令:npm i vue-router
(2)应用插件:Vue.use(VueRouter)
(3)编写路由器配置项:src/router/index.js

// 该文件专门用于创建整个应用的路由器
// 引入插件
import vueRouter from 'vue-router'
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home' // 出现了 /# 表示路由已就位
// 创建并暴露一个路由器 
export default new vueRouter({ //是一个构造函数
    // 配置路由规则
    routes:[
        { path:"/about", component:About},
        { path:"/home",component:Home}
        ]
}) 

(4)实现切换 :App.vue

<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>
<!-- 注:1.to表示想把路径改成什么,不是相对路径
     2. router-link 最终也会变成a标签渲染到页面
     3.使用 active-class 指定动态高亮
-->

(5)展示指定位置

 <router-view></router-view>

(6)注意事项
(1 路由组件通常存放在pages/views文件夹,一般组件通常存放在components文件夹
(2 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
(3 每个组件都有自己的$route属性,里面存储着自己的路由信息。
(4 整个应用只有一个router,可以通过组件的$router属性获取到;
一般组件:引入、注册,亲自写的组件标签;
路由组件:靠路由规则匹配出来的,由路由器给渲染的组件。
工作过程描述:用户点击了路由链接修改了路径,前端路由器检测到了,匹配规则时发现该路径对应哪个组件,于是将该组件渲染出来放在指定的位置。

03 多级路由(嵌套路由)

(1)配置路由规则,使用children配置项:

routes:[
        { path:"/about", component:About},
        { 
            path:"/home",
            component:Home,
            // 配置子路由
            children:[
                {path:"news", component:News}, //此处一定不要写/news
                {path:"message", component:Message}
            ]
        }
        ]

(2)跳转(要写完整路径):

<router-link to="/home/news">News</router-link>

04 路由的query参数

1)传递参数

<!-- 写法一:跳转路由器并携带query参数to的字符串写法
  在to前面加: 里面的内容会被当作js解析,加上模板字符串,
  里面混入js变量的代码写进${}里面
-->
 <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>

(2)接收参数

$route.query.id
$route.query.title

05 命名路由

(1)作用:可以简化路由的跳转
(2)如何使用
给路由命名:

routes:[
   { path:"/about", component:About},
   { 
       path:"/home",
       component:Home,
       // 配置子路由
       children:[
           {path:"news", component:News},
           {
               path:"message", 
               component:Message,
               children:[
                   // 给路径过长的路由取名 可以简化跳转编码
                   {name:"detail", path:"detail", component:Detail}
               ]
           }
       ]
   }
]

********************************************************************
简化跳转:
<!--简化前需要写完整的路径-->
 <router-link to="/home/message/detail">跳转</router-link>
<!--简化后,直接通过名字跳转-->
<router-link :to="{name:'detail'}">跳转</router-link>
<!--简化写法配合传递参数-->
 <router-link 
   :to="{
       name:'detail',
       query:{
           id:m.id,
           title:m.title
       }
   }">
   {{m.title}}
</router-link>

06 路由的params参数

(1)配置路由,声明接收params参数

children:[
// 给路径过长的路由取名 可以简化跳转编码
  // 给path添加占位符,配合params传参
  {name:"detail", path:"detail/:id/:title", component:Detail}
]

(2)传递参数

<!-- 写法一:跳转路由并携带params参数to的字符串写法:直接拼接 -->
<router-link 
:to="`/home/message/detail/${m.id}/${m.title}`"
>
	{{m.title}}
</router-link>

****************************************************************
<!-- 写法二:跳转路由并携带params参数to的对象写法-->
 <router-link 
  :to="{
      name:'detail',
      params:{
          id:m.id,
          title:m.title
      }
  }">
  {{m.title}}
  </router-link>

【特别注意】路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置

(3)接收参数

$route.params.id
$route.params.title

07 路由的props配置

作用:让路由组件更方便的接收参数

{
 name:"detail",
 path:"detail/:id/:title", 
 component:Detail,
 
 *********************************************************
 //props的第一种写法,值为对象,    
 //该对象中所有的key-value都会以props的形式传给Detail组件
 //--数据是写死的,用得非常少
 props:{a:1,b:2} 
 
 *********************************************************
 //props的第二种写法,值为布尔值,
 //若为真就会把该路由组件收到的所有params参数,
 //以props的形式传给Detail组件 
props:true 

 *********************************************************
 props($route) {
     return {id:$route.query.id,title:$route.query.title}
 }
 // props的第三种写法,值为函数,
 //该对象中所有的 key-value 都会以props的形式传给Detail组件 
  props({query:{id,title}}) {
    return {id,title}
  } //解构赋值的连续写法 -- 可读性差
}

08 <router-link>replace属性

作用:控制路由跳转时操作浏览器历史记录的模式
浏览器的历史记录有两种写入方式,分别为push和replace,push是追加历史记录,replace是替换当前栈顶的记录。路由跳转时默认为push
如何开启replace模式:

<router-link replace ...>News</router-link>

09 编程式路由导航

作用:不借助实现路由跳转,让路由跳转更加灵活
具体编码:

//$router的两个API
this.$router.push({
    name:'detail',
    query:{
        id:m.id,
        title:m.title
    }
})
this.$router.replace({
 name:'detail',
  query:{
      id:m.id,
      title:m.title
  }
})
this.$router.back()
this.$router.forward()
// 向后退两部
 this.$router.go(-2)

10 缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁
具体编码

// 找到其父组件
<keep-alive include="News"> // 这里写的是组件名
	<router-view></router-view>
</keep-alive>

// 缓存多个组件写法
:include="['News','Message']"

11 两个新的生命周期钩子

Vue在特殊时候帮我们调用的特殊的函数
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
具体名字:
(1)activated 路由组件被激活时触发
(2)deactivated 路由组件失活时触发

12 路由守卫

作用:对路由进行权限控制
分类:全局守卫(前置、后置)、独享守卫、组件内守卫

(1)全局守卫

// ***全局前置守卫,初始化的时候被调用,每一次路由切换之前被调用

// 接收三个参数
router.beforeEach((to,from,next)=>{
console.log(to,from);

************************************************************
 // 一、name写法 
 // 事先给所有路由组件配置名字
 if(to.name === "News" || to.name === "Message");
 
************************************************************
 // 二、path写法
  if(to.path === "/home/news" || to.path === "/home/message")
   
****************************************************************     
 // 三、当组件过多怎么判断? 
 // 给路由组件配置meta属性 meta:{isAuth:true}
 if(to.meta.isAuth===true) //判断当前路由是否需要权限控制
	 { // 事先在浏览器应用loaclStorage配置好school:atguigu
	     if(localStorage.getItem("school") === "atguigu") {
	      //权限控制的具体规则
	      // school的值对上了才允许访问这两个界面
	      next()
	     } else {alert("学校名错误,无权限访问!")}
	 } else {
	     next()  //放行
	 }
	 

})
// ***全局后置守卫,初始化的时候被调用,每一次路由切换之后被调用

// 适用场景:当组件被过滤之后需要进行的操作
// 提出需求:页签名称改变
router.afterEach((to,from)=> { //接收两个参数
    console.log(to,from);
    //将title配置在meta里
    //设置默认 并修改index.html的title配置
    document.title = to.meta.title || "硅谷系统" 
})

// 在暴露之前使用路由守卫过滤
export default router

(2)独享守卫

某一个路由所独享的

beforeEnter(to,from,next){
...
}

(3)组件内守卫

// 通过路由规则,进入该组件时被调用
    beforeRouteEnter (to, from, next){
}
// 通过路由规则,离开该组件时被调用
    beforeRouteLeave (to, from, next){
}

13 路由器的两种工作模式

对于一个url来说,什么是hash值?——#及其后面的内容就是hash值
hash值不会包含在HTTP请求中,即:hash值不会带给服务器
hash模式
(1)地址中永远带着#号,不美观
(2)若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
(3)兼容性较好
history模式
(1)地址干净,美观
(2)兼容性和hash模式相比略差
(3)应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

配置路由器工作模式

router{
mode:"hidtory"
routes: ...
}

vuex

01 概念

专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信

02 适用范围

(1)多个组件依赖于同一状态
(2)来自不同组件的行为需要变更同一状态

03 搭建Vuex环境

(1)npm i vuex 安装Vuex
(2)Vue use(vueX)
(3)创建store管理actionsmutationsstate
(4)vc =>store

1)创建文件:src/store/index.js

// 引入Vue核心库
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 应用vuex插件
// 为什么不在main.js中引用?因为import语句先执行,要保证import时已引入Vuex
Vue.use(Vuex)

// 准备actions对象--响应组件中对象的动作
const actions = {}
// 准备mutations对象--修改state中的数据
const mutations = {}
// 准备state对象--保存具体的数据
const state = {}

// 创建并暴露store
export default new Vuex.Store({
    // 传入配置项
    actions,
    mutations,
    state
})

***********************************************2)在main.js中创建vm时传入store配置项
...
import store from './store/index'
....
new Vue({
    el:"#app", 
    render:h => h(App),
    store  
})

04 基本使用

(1)初始化数据、配置actions、配置mutations、操作文件index.js
(2)组件中读取vuex中的数据:$store.state.数据
(3)组件中修改vuex中的数据:$store.dispatch("actions中的方法名",数据)$store.commit("mutations中的方法名",数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

05 getters的使用

(1)概念:当state中的数据需要经过加工后再使用时,如果逻辑复杂并且还想复用,可以使用getters加工。getters与state的关系相当于computed与data的关系。
(2)

...
// 在index.js中追加getters配置
const getters = {
    // getters能收到一个参数state
    bigSum(state) {
        // 类似于计算属性,都是靠返回值来决定自己的值
        return state.sum * 10
    }
}
...

(3)组件中读取数据:$store.getters.bigSum

06 四个map方法的使用

(1)mapState方法:用于帮助我们映射state中的数据为计算属性

computed: {
      ....
         // 1.借助mapState生成计算属性,从state中读取数据(对象写法) 
         ...mapState({sum:"sum",school:"school",subject:"subject"}), //展开运算符:在对象里面拼接对象
        // 此处不适用对象的简写,会读取sum变量,而此处是字符串
        
        // 2.借助mapState生成计算属性,从state中读取数据(数组写法) 
        ...mapState(["sum","school","subject"]), //要保证生成的计算属性名和读取出来的名是一致的
       ...
    },

(2)mapGetters方法:用于帮助我们映射getters中的数据为计算属性

computed: {
      ....
        // 1.借助mapGetters生成计算属性,从getters中读取数据(对象写法)
        ...mapGetters({bigSum:"bigSum"}), 
       // 2.借助mapGetters生成计算属性,从getters中读取数据(数组写法)
        ...mapGetters(["bigSum"])  
    },

(3)mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

methods: {
       ...
        // 1.借助mapMutations用commit去联系mutations生成对应的方法(对象写法)
        ...mapMutations({increment:"ADD",decrement:"SUB"}),
        // 2.借助mapMutations用commit去联系mutations生成对应的方法(数组写法)
        // 方法名要和mutations中对应
        // ...mapMutations(["ADD","SUB"]),

(4)mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

 methods: {
      ...
        // 1.借助mapActions用dispatch去联系actions生成对应的方法(对象写法)
        ...mapActions({incrementOdd:"addOdd",incrementWait:"addWait"}),
        // 2.借助mapActions用dispatch去联系actions生成对应的方法(数组写法)
        // ...mapActions(["addOdd","addWait"])
    },

备注

mapActionsmapMutations在使用时,若有传递参数需要,须在模板绑定事件时传递好参数,否则参数为默认事件对象

07 模块化+命名空间

(1)目的:让代码更好维护,让多种数据分类更加明确(业务逻辑)。
(2)修改index.js:

// 模块一
const countAbout = {
    namespaced:true,  //开启命名空间
    state:{x:1},
    actions:{ ... },
    mutationos:{ ... },
    getters:{ ... }
}

// 模块二
const personAbout = {
    namespaced:true,
    ...
}
...

// 暴露并创建store
export default new Vuex.Store({
    // 传入配置项
    modules: {
        countAbout:countOptions,
        personAbout:personOptions
    }
})

(3)开启命名空间后,组件中读取state数据:

//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助 mapState读取
...mapState("countAbout",["sum","school","subject"]),

(4)开启命名空间后,组件中读取getters数据:

//方式一:自己直接读取
this.$store.getters[personAbout/firstPersonName]
//方式二:借助 mapGetters读取
...mapGetters("countAbout",["bigSum"]),

(5)开启命名空间后,组件中调用dispatch

//方式一:自己直接 dispatch
this.$store.dispatch("personAbout/addPersonWang",personObj)
//方式二:借助 mapActions
...mapActions("countAbout",{incrementOdd:"addOdd",incrementWait:"addWait"}),

(6)开启命名空间后,组件中调用commit

//方式一:自己直接 commit
this.$store.commit("personAbout/ADD_PERSON",personObj)
//方式二:借助 mapMutations
...mapMutations("countAbout",{increment:"ADD",decrement:"SUB"}),
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛江清

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值