Vuex相关知识点
1、什么是Vuex?
Vuex是Vue的一个全局状态管理模块,它的作用是多个组件共享状态及数据(即当某个组件将全局状态修改时,在绑定了该状态的另一个组件也将响应)。
2、Vuex组成部分
- state:是存储的基本数据。
- Getters:对数据获取之前的再次编译,可以理解为state的计算属性
const getters = {
username: state => state.user.username,
nickname: state => {state.user.nickname = Vue.ls.get(CONSTANTS.ACCOUNT).nickName; return state.user.nickName},
};
- Mutations:提交更改数据(使用store.commit方法更改state存储的状态)。
this.$store.commit('mutations中对应的方法名',e.target.value)
- Actions:actions 提交的是mutation,不是直接的去变更状态 ,它是专门进行异步操作(使用this.$store.dispatch方法)。
Actions中的方法有两个默认参数
context 上下文(相当于箭头函数中的this)对象
payload 挂载参数
this.$store.dispatch('actions名称',{ XXX:xxx })
PS:因为是异步操作,一般我们在使用的时候会将异步操作封装为一个Promise对象
editUserInfo(context,payload){
return new Promise((resolve,reject)=>{
context.commit('edit',payload)
resolve()
})
}
- Module:Module是store分割的模块,当状态较多时,会采用模块化管理。每个模块拥有自己的state、getters、mutations、actions。
const app = {
state: {
fixSiderbar: false,
multipage: true //默认多页签模式
},
mutations: {
TOGGLE_FIXED_SIDERBAR: (state, fixed) => {
Vue.ls.set(CONSTANTS.DEFAULT_FIXED_SIDEMENU, fixed);
state.fixSiderbar = fixed
},
SET_MULTI_PAGE(state, multipageFlag) {
Vue.ls.set(CONSTANTS.DEFAULT_MULTI_PAGE, multipageFlag);
state.multipage = multipageFlag
}
},
actions: {
ToggleFixSiderbar({commit}, fixSiderbar) {
commit('TOGGLE_FIXED_SIDERBAR', fixSiderbar);
},
ToggleMultipage({commit}, multipageFlag) {
commit('SET_MULTI_PAGE', multipageFlag);
}
}
};
export default app
store.js文件中
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
app,
......
},
});
PS:模块中mutations中接受的第一个参数是自身局部模块的state
- 辅助函数:mapState、MapGetters、MapActions、mapMutations等
computed: {
...mapState({//相当于把state中的addRouters映射到this.mainRouters中
mainRouters: state => state.permission.addRouters,
permissionMenuList: state => state.user.permissionList
})
},
...mapActions(['setSidebar']),//组件中可直接调用this.setSideBar
3、Vuex的原理:
- 使用了Vue的混入机制,在Vue的beforeCreate钩子前混入(mixin)vuexInit,并在init中将$store属性注册到Vue中。
- Vuex的getters:借助vue的计算属性computed实现数据实时监听。
- Vuex的state:借助vue的data是响应式,将state存入vue实例组件的data中实现。
Vue组件常用通信方式
Vue组件简单常用的通信方式有以下几种:
1、父子通信:
- 父向子传值:通过props;
- 子向父传值:通过事件形式
changeMessage() {
this.$emit("handleChange","向父组件传值");
}
//子组件
<div @handleChange="changeDivMsg" ></div>
-
父调用子方法:通过ref
1)在子组件上定义ref=“refName”
2)父组件的方法中使用
<test-table ref="deployTab" @selectChange="deploySelectChange"></test-table>
script>
import TestTable from './TestTable ';
export default {
components: {
TestTable
},
methods: {
deploySelectChange() {//调用子组件方法
this.$refs.deployTab.batchStopAppDeploys();
}
}
}
</script>
- 子调用父方法:provide / inject; p a r e n t ; 通 过 事 件 形 式 p r o v i d e / i n j e c t : 允 许 一 个 祖 先 组 件 向 其 所 有 子 孙 后 代 注 入 一 个 依 赖 。 作 用 : 主 要 解 决 了 跨 级 组 件 间 的 通 信 问 题 , 一 般 用 于 子 组 件 获 取 父 组 件 的 状 态 。 t h i s . parent;通过事件形式 provide / inject:允许一个祖先组件向其所有子孙后代注入一个依赖。 作用:主要解决了跨级组件间的通信问题,一般用于子组件获取父组件的状态。 this. parent;通过事件形式provide/inject:允许一个祖先组件向其所有子孙后代注入一个依赖。作用:主要解决了跨级组件间的通信问题,一般用于子组件获取父组件的状态。this.parent.method(在子组件里面 this.$parent 得到的是父组件的实例)
//父组件
provide: function() {
return {
//给addTab定义一个getAdd的调用名称
getParentMsg: this.getMessage,
};
},
getMessage(id){
if(id != null){
console.log("调用父方法并传值:"+id)
}
}
//子组件:
inject: ["getParentMsg"],
//子组件调用父组件的方法
<span @click="getParentMsg(1)">点击获取父组件Msg信息</span>
2、兄弟通信:eventBus(事件总线)
EventBus:相当于所有组件共用相同的事件中心,可以向该中心发送或接收事件。
使用:
1)main.js初始化EventBus
Vue.prototype.$EventBus = new Vue()
2)通信
this.$eventBus.$emit('changeVal',value)
this.$eventBus.$on('changeVal', (e) => {
this.val = e
})
3、跨级嵌套通信:eventBus;provide / inject等。
provide/inject
//父组件
export default {
provide: {
test: '测试'
}
}
// 子组件
export default {
inject: ['test'],
mounted () {
console.log(this.test);
}
}
4、其他非父子组件传参方式
- 使用路由:< router-link >中在query/params中传值,子组件使用this.$route.query获取
- 本地存储localStorage
- 状态管理Vuex
vue中computed和watch的区别
1、computed:计算属性
- 支持缓存,只有当计算属性中依赖的一个或多个数据发生改变,才会重新进行计算。否则读取缓存中的数据。
- 不支持异步,当computed内有异步操作时无效,无法监听数据的变化。
- 在computed中的,属性都有一个get和一个set方法。
当数据变化时,调用set方法。
当需要读取当前数据时,调用get方法。 - 监听对象可以是data和props中的属性
computed: {//进行一些简单的计算
getMessage () {
return this.message+'||'+this.number
}
}
2.watch:监听属性,一般用来监听属性的变化(也可用来监听计算属性)
- 不支持缓存,数据发生变化会直接触发相应的操作。
- watch支持异步。
- 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
- 监听对象可以是data、props、computed
- 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发 回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。
注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
watch: {
number (newVal, oldVal) {
console.log('number has changed: ', newVal)
}
}
总结:computed的话是通过几个数据的变化,来影响一个数据,而watch,则是可以一个数据的变化,去影响多个数据。
Vue生命周期钩子函数
1、什么是生命周期钩子函数
组件创建、更新、销毁三个阶段 所触发执行的函数。
2、Vue提供的生命周期钩子
- beforeCreate: 在实例初始化之后,数据观测(data observer)和初始化事件(init event,Vue内部初始化事件)之前被调用。(el和data并未初始化)
- created:在实例已经创建完成之后被调用。(完成了data数据的初始化,el没有)
- 数据观测
- 属性和方法的运算
- watch/event事件回调
- DOM还未生成,挂载阶段还未开始,$el 属性不可见。
- beforeMount: 在挂载开始之前被调用(完成了el和data的初始化)
- 相关的render函数首次被调用。
- $el属性已经可见
PS:在这时,其实el中还是显示的{{}},这里应用的虚拟DOM技术,先把坑占住了。到后面mounted挂载的时候再把值渲染进去。
- mounted :el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。(完成了挂载)
PS:注意mounted只会执行一次。
存在期生命周期函数:beforeUpdate、updated
只有在Vue需要改变数据时才会触发存在期的钩子函数
- beforeUpdate: 在数据更新之前调用,虚拟DOM变化之前调用。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
- updated :在数据更新和虚拟DOM重新渲染后调用。调用时,组件DOM已经更新。
- beforeDestroy:在实例销毁之前调用。实例仍然完全可用。(一般用于移除事件监听器、定时器等,避免内存泄露)
- destroyed:在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
var、let 和const的区别
区别 | var | let | const |
---|---|---|---|
是否具备块级作用域 | × | √ | √ |
是否存在变量提升 | √ | × | × |
是否添加全局属性 | √ | × | × |
能否重复声明变量 | √ | × | × |
是否存在暂时性死区 | × | √ | √ |
是否必须设置初始值 | × | × | √ |
能否改变指针指向 | – | √ | × |
总结:
- var允许在声明之前使用,let和const不能在声明之前使用(变量提升)。
PS:变量提升—无论声明在何处,都会被提升至所在作用域的顶部
console.log(a) // 正常运行,打印出 undefined
var a = 1
------------------------
console.log(b) // 报错,Uncaught ReferenceError: b is not defined
let b = 1
------------------------
console.log(c) // 报错,Uncaught ReferenceError: b is not defined
const c = 1
- var变量可以重复声明,cost和let不能重复声明
if (true) {
var c;
let c; // Uncaught SyntaxError: Identifier 'c' has already been declared
}
if (true) {
let d;
var d; // Uncaught SyntaxError: Identifier 'd' has already been declared
}
- 如果区块中存在let和const,则使用let、const 命令声明变量之前,该变量都是不可用的。
var tmp = 123;
if (true) {
// TDZ 开始
tmp = 'abc'; // ReferenceError
let tmp; // TDZ 结束
}
- var和let在声明变量时,可以不用设置初始值,const必须设置。
- var不存在块级作用域,let和const具有块级作用域。
{
let a =10;
var b= 8;
}
console.log(a);//ReferenceError: a is not defined
console.log(b);//1
-
const用来声明只读常量,声明的变量不可随意修改,否则会导致SyntaxError(语法错误)。
1) 简单数据类型(数值,字符串,布尔值):值保存在变量指向的那个内存地址,因此等同于常量。 2) 复合类型的数据(对象和数组):变量指向的是内存地址,保存的是一个指针,const只能保存这个指针地址是固定的,至于他指向的数据结构是不是可变的,就完全不能控制了。 PS:所以说const只是保证变量名指向的地址不变,并不保证该地址的数据不变
const PI = 3.1415
PI = 3 // 报错,Uncaught TypeError: Assignment to constant variable.
/*不会报错,因为names1指向的地址不变,改变的只是内部数据*/
const names1 = [];
names1[0] = 1;
names1[1] = 2;
console.log(names1);
/*出错,因为变量names2指向的地址不能发生改变,应始终指向[]所在的地址,[1,4]与[6,7]不是同一个地址*/
const names2=[1,4];
names2=[6,7]; //报错
- ES6中使用 var 和 function 声明的全局变量依旧作为全局对象的属性,使用 let, const 命令声明的全局变量不属于全局对象的属性。
var a = 10;
console.log(window.a); //10
console.log(this.a) //10
let b = 20;
console.log(window.b); // undefined
console.log(this.b) // undefined
async/await 异步操作
1、async和await介绍—基于Promise解决异步
- async:用于申明一个function是异步的
- await:用于等待一个异步方法执行完成
2、async的返回值
async函数返回的是一个Promise对象。
PS:
- 由于Promise的特点是无等待,所以在没有await的情况下,会立即执行async函数并返回一个Promise
- 如果在函数中return一个直接量,async会通过Promise.resolve( )封装成Promise对象
- 如果函数内部抛出错误,async会通过Promise.reject()返回一个promise对象
async function timeout(flag) {
if (flag) {
return 'hello world'
} else {
throw 'my god, failure'
}
}
console.log(timeout(true)) // 调用Promise.resolve() 返回promise 对象。
console.log(timeout(false)); // 调用Promise.reject() 返回promise 对象。
3、await的使用
1)await只能在async函数内部使用
2)await关键字后面跟Promise对象
- await实际上等待的是一个返回值。不仅可以等待async函数返回的Promise对象,还可以是任意表达式的结果。
function getSomething() { return "something"; }
async function testAsync() {
return Promise.resolve("hello async");
}
async function test() {
const v1 = await getSomething();
const v2 = await testAsync();
console.log(v1, v2);
}
test();
- 如果await等待的是Promise,则await会进行阻塞,并等待Promise对象resolve,然后得到resolve的值。(这就是await必须用在async函数中的原因,因为async内部所用的阻塞都封在了一个Promise对象中异步执行)
- await只关心异步成功的消息resove(data),拿到对应的数据信息data。至于失败消息reject(error)不进行处理(可让await后的Promise对象catch或使用try…catch统一处理)
async getFaceResult () {
try {
let location = await this.getLocation(this.phoneNum);
if (location.data.success) {
let info= location.data.obj.info;
let result = await this.getFaceList(province, city);
if (result.data.success) {
this.list = result.data.obj;
}
}
} catch(err) {
console.log(err);
}
}
参考资料:
https://blog.csdn.net/time_____/article/details/114980805?spm=1001.2014.3001.5501
https://blog.csdn.net/u011423258/article/details/88641870
https://blog.csdn.net/time_____/article/details/110185339?spm=1001.2014.3001.5501
https://blog.csdn.net/qq_42033567/article/details/107162586