1.Vuex
dispatch
state:相当于Vue的data
mutations:类似于事件,每个 mutation 都有一个字符串的事件类型 (type)和 一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
actions: Action 类似于 mutation,不同在于Action 提交的是 mutation,而不是直接变更状态,Action 可以包含任意异步操作
getters:可以认为是 store 的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,接受 state 作为其第一个参数
好了,就这么简单可以用了
localStorage 和 SessionStorage的区别:
localStorage:关闭窗口后数据一直存在,并且在同源不同窗口下也能共享;
seesionStorage:当前窗口关闭前有效
nextTick();
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM,在引入VUE的地方引入 不可单独引入否则会报错(elementUI框架中VUE3的写法)
延迟调用优先级:Promise > MutationObserver > setImmediate > setTimeout
next-tick.js 对外暴露了nextTick这一个参数,所以每次调用Vue.nextTick时会执行:
- 把传入的回调函数cb压入callbacks数组
- 执行timerFunc函数,延迟调用 flushCallbacks 函数
- 遍历执行 callbacks 数组中的所有函数
这里的 callbacks 没有直接在 nextTick 中执行回调函数的原因是保证在同一个 tick 内多次执行nextTick,不会开启多个异步任务,而是把这些异步任务都压成一个同步任务,在下一个 tick 执行完毕。
使用Vue.nextTick()是为了可以获取更新后的DOM 。
触发时机:在同一事件循环中的数据变化后,DOM完成更新,立即执行Vue.nextTick()的回调。
同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback触发
生命周期
场景:
在实例初始化之后,数据观测(data observer)和 event/watcher事件配置之前调用
场景:
在实例创建完成后立即被调用,实例已完成数据观测(data observer),属性和方法的运算,watch/event事件回调,挂载阶段还没开始
场景:
在挂载开始之前被调用,相关的render函数首次被调用
ps:该钩子在服务器端渲染期间不被调用
场景:
el 被创建的 vm.$el 替换,并在挂载到实例上去之后调用该钩子,如果root实例挂载了一个文档元素,当mounted被调用 vm.$el 也在文档内
场景:
数据更新时调用,发生在虚拟DOM打补丁之前,这里适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
场景:
数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
场景:
keep-alive 组件激活时调用。
该钩子在服务器端渲染期间不被调用。
vue3 生命周期
生命周期钩子vue2到vue3映射关系
beforeCreate -> use setup() created -> use setup() beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestroy -> onBeforeUnmount destroyed -> onUnmounted errorCaptured -> onErrorCaptured
引用时只需导入钩子并将它们包在 setup 方法中即可。
vue3中使用Proxy代理
var proxy = new Proxy(target, handler);
var obj = new Proxy({}, { get: function (target, propKey, receiver) { console.log(`getting ${propKey}!`); return Reflect.get(target, propKey, receiver); }, set: function (target, propKey, value, receiver) { console.log(`setting ${propKey}!`); return Reflect.set(target, propKey, value, receiver); } });
handler可以有以下几种属性
get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。 set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。 has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。 deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。 ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。 getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。 isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。 setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。 construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
vue2定义数据使用data,定义方法使用methods
export default {
name: 'App',
data(){
return {
title: 'vue3',
num: 3
}
},
methods:{
hello () {
alert('hello vue3');
}
}
}
vue3定义数据和方法在setup()方法里面,return一个对象
export default {
name: 'App',
setup(){
return {
title: 'vue3',
num: 3,
hello () {
alert('hello vue3');
}
}
}
}
在 2.x 中,在组件上使用 v-model 相当于绑定 value的prop 并触发input 事件
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
在 3.x 中, v-model 相当于传递了 mo
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
###### 变化
prop:value => modelValue
事件:input => update:modelValue
delValue的 prop 并接收抛出的 update:modelValue 事件
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
###### 变化
prop:value => modelValue
事件:input => update:modelValue
v-if 和 v-for 优先级
同一元素使用时在vue2中v-for高于v-if
在vue3中v-if的优先级要高
修饰符: v-on.native
vue3移除native修饰符。
在vue2中,v-on.native修饰符把原生的事件绑定到子组件根元素上。
vue2:
<my-component v-on:close="handleComponentEvent" v-on:click.native="handleNativeClickEvent" />
vue3:
在vue3中,.native 修饰符已被移除。同时新增的 emits 选项,子组件定义真正会被触发的事件。
未在子组件emits定义为组件触发的所有事件监听器,Vue 现在将把它们作为原生事件监听器添加到子组件的根元素中 (除非在子组件的选项中设置了 inheritAttrs: false)+。
my-component v-on:close="handleComponentEvent" v-on:click="handleNativeClickEvent" />
子组件中
script> export default { emits: ['close'] } script>
v-for绑定key值,为什么不建议使用index作为key值?
如果只是展示列表数据,key值可以是索引;如果列表中的数据会经常发生变化,特别是列表数据的位置会发生变化,这时候key一定要设置为对象身上的唯一属性,目的是:当列表更新时,会大大提高列表重新渲染的性能损耗。
因为vue在渲染数据时,先将数据生成一份虚拟DOM,再将虚拟DOM生成对应的真实DOM挂载到页面中。当vue中的数据修改后,会重新生成一份虚拟DOM,并跟之前的虚拟DOM进行匹配,如果两份虚拟DOM中的key和key对应的值完全相同,不会重新生成对应的真实DOM;只有key和key对应的值不同的虚拟DOM,才会生成新的真实DOM并挂载的页面中。
div class="home">添加button> ul> li v-for="item in list" :key="item.id">{{ item }}li> ul> div>
VUE项目中使用this.$forceUpdate();解决页面v-for中修改item属性值后页面v-if不改变的问题
yield*
yield*表达式用于委托另一个generator或可迭代对象
语法:yield*[[expression]];
expression 返回一个可迭代对象的表达式。
描述 yield* 表达式迭代操作数,并返回他产生的每个值。
yield* 表达式本身的值是当迭代器关闭时返回的值(即done为true时)。
委托给其他生成器
g1() yield出去的每个值都会在g2()的next()方法中返回,就像那些yield语句是写在g2()里一样
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
var iterator = g2();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
委托给其他可迭代对象
出=除了生成器对象这一种可迭代对象,yield*换可以yield其他任意可以迭代的对象,比如说数组、字符串、arguments对象等等
function* g3() {
yield* [1, 2];
yield* "34";
yield* arguments;
}
var iterator = g3(5, 6);
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: "3", done: false }
console.log(iterator.next()); // { value: "4", done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: 6, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
yield* 是一个表达式,不是语句,所以它会有自己的值。
function* g4() {
yield* [1, 2, 3];
return "foo";
}
var result;
function* g5() {
result = yield* g4();
}
var iterator = g5();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true },
// 此时 g4() 返回了 { value: "foo", done: true }
console.log(result); // "foo"
vue3
路由导航守卫提示报错信息
vue-router4路由 No match found for location with path警告
场景
1.动态路由
通过前端静态路由地址分模块按照约定值控制菜单路由
解决方案
在初始静态路由文件下增加
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error-page/404.vue')
}
或检查其路由配置(正常来说按照正常来说 路由文件配置问题会在第一时间将错误抛出)