1.vue
1.vue3底层通过Proxy实现了数据监听,替代了vue2中的Object.defineProperty
2.vue的异步更新原理
数据频繁发生变化,但dom为什么只是更新了一次
- vue数据发生变化之后,不会立即更新dom,而是异步更新
- 监听到数据变化,vue开启一个队列,并缓存在同一事件循环中发生的所有数据变化
- 如果同一个
watcher被多次触发,只会被推入到队列一次,避免重新修改相同的dom - 同步任务执行完毕,开始执行异步watcher队列的任务,一次性更新dom
3.nextTick为什么要优先使用微任务实现?
- vue nextTick的源码实现,异步优先级判断,总结就是
Promise > MutationObserver > setImmediate > setTimeout - 优先使用Promise,因为根据
event loop与浏览器更新渲染时机,宏任务 → 微任务 → 渲染更新,使用微任务,本次event loop轮询就可以获取到更新的dom - 如果使用宏任务,要到下一次
event loop中,才能获取到更新的dom
Vue异步更新 - nextTick为什么要microtask优先
4.虚拟dom
为什么使用虚拟dom?
- 频繁的改变dom会造成浏览器的回流和重排
- 使用虚拟dom,当数据变化,页面需要更新时,通过diff算法,对新旧节点进行对比,产生差异,一次性对dom进行批量更新操作,进而提高了性能
- 虚拟dom的本质是js对象,而dom与平台强相关,方便跨平台操作
5.vue-router
- 路由的模式:
hash 模式、history 模式 - hash模式(路由中带#号),通过
hashchange事件来监听路由的变化
window.addEventListener('hashchange', ()=>{}) - history 模式,利用了
pushState()和replaceState()方法,实现往history中添加新的浏览记录、或替换对应的浏览记录 popstate事件来监听路由的变化,window.addEventListener('popstate', ()=>{})Vue Router原理
6.vuex[vue3]
1.什么情况下我们应该使用vuex?
vuex帮我们做状态管理,而且是大型的单页面应用
使用:
<a-button @click="add" type="primary"> + </a-button>
计算器:{{ count }}
<a-button @click="inc" type="primary"> - </a-button>
import { defineComponent, computed } from "vue";
import { useStore } from "vuex";
let store = useStore();
let count = computed(() => store.state.counter.count);
let add = () => {
// store.commit("counter/ADD_COUNT");
store.dispatch("counter/setCount", { count: 1000 }).then((count) => {
console.log("执行成功,counter:"+count);
});
};
let inc = () => {
store.commit("counter/INC_COUNT");
};
store.js
import { reactive } from "vue"
const counter = {
// 带命名空间的模块
namespaced: true,
state: {
count: 1,
users: [
{ name: 'Tom', age: 18 },
{ name: 'Jerry', age: 22 },
{ name: 'Bom', age: 12 },
],
},
getters: {
getUsers(state) {
// console.log("state11", state.users)
let users = state.users.filter(item => {
return item.age >= 18
})
return users;
}
},
// 同步
mutations: {
["INC_COUNT"](state, payload) {
// console.log("state", state.count)
state.count--
},
["ADD_COUNT"](state, payload) {
// console.log("state", state.count)
state.count++
},
["SET_COUNT"](state, payload) {
// console.log("payload", payload.count)
state.count += payload.count;
}
},
// 异步
actions: {
async setCount(conSETText, payload) {
// console.log('conText', conText)
let count = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(payload.count)
}, 1000)
})
conText.commit('SET_COUNT', { count: count });
return Promise.resolve(count);
}
}
}
export default reactive(counter)
7.pinia
为什么使用Pinia?
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态
安装:
npm install pinia
在main.js中引入
import { createPinia } from 'piniaimport { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
// 创建pinia 实例
const pinia = createPinia()
createApp(App).use(router).use(pinia).mount('#app')
使用
<h2 class="">{{ helloWorld }}</h2>
<h2 class="">{{ count }}</h2>
<h2 class="">电话号码:{{ phoneHidden }}</h2>
<button @click="handleClick">点击增加</button>
<!-- 多条数据同时更新状态数据,推荐使用$patch方式更新。 -->
<button @click="handleClickPatch">修改数据($patch)</button>
<button @click="handleClickMethod">修改数据($patch+函数)</button>
<button @click="handleClickActions">修改数据(actions)</button>
<script setup>
import { mainStore } from "../store/index";
// 变成响应式
import { storeToRefs } from 'pinia'
const store = mainStore();
const { helloWorld, count, phoneHidden } = storeToRefs(store);
const handleClick = () => {
store.count++;
store.helloWorld = store.helloWorld === "我变了" ? "HelloWorld" : "我变了";
};
const handleClickPatch = () => {
store.$patch({
count: store.count + 2
});
};
const handleClickMethod = () => {
store.$patch((state) => {
console.log('state', state)
state.count++;
});
};
//直接调用changeState
const handleClickActions = () => {
store.changeState()
}
</script>
pinia模块的创建
import { defineStore } from 'pinia'
export const mainStore = defineStore('main', {
state: () => {
return {
helloWorld: "helloWorld",
count: 0,
phone: '13120907614',
listArray: userStore().list
}
},
getters: {
phoneHidden(state) {
return state.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
},
},
actions: {
// 在用actions的时候,不能使用箭头函数,因为箭头函数绑定是外部的this
changeState() {
this.count++
this.helloWorld = '通过action改变'
},
getList(){
console.log(userStore().list)
}
}
})
8.vue3和vue2的区别
- vue3性能比vue2快很多
- 用
proxy代替Object.defineproperty,解决了vue2种新增属性监听不到的问题 - diff方法优化 vue3新增了静态标记(patchflag),虚拟节点对比时,就只会对这些带有静态标记的节点
- 静态提升: vue3不参与更新的元素,会做静态提升,只有被创建一次
- 组合API:可以将data与对应的逻辑写在一起,更容易理解
- 更好的支持ts
- Fragment:模板可以有多个根元素