框架和浏览器原理

54 阅读3分钟

1.vue

1.vue3底层通过Proxy实现了数据监听,替代了vue2中的Object.defineProperty

2.vue的异步更新原理

数据频繁发生变化,但dom为什么只是更新了一次

  1. vue数据发生变化之后,不会立即更新dom,而是异步更新
  2. 监听到数据变化,vue开启一个队列,并缓存在同一事件循环中发生的所有数据变化
  3. 如果同一个watcher被多次触发,只会被推入到队列一次,避免重新修改相同的dom
  4. 同步任务执行完毕,开始执行异步watcher队列的任务,一次性更新dom

3.nextTick为什么要优先使用微任务实现?

  1. vue nextTick的源码实现,异步优先级判断,总结就是Promise > MutationObserver > setImmediate > setTimeout
  2. 优先使用Promise,因为根据 event loop 与浏览器更新渲染时机,宏任务 → 微任务 → 渲染更新,使用微任务,本次event loop轮询就可以获取到更新的dom
  3. 如果使用宏任务,要到下一次event loop中,才能获取到更新的dom

Vue异步更新 - nextTick为什么要microtask优先

4.虚拟dom

为什么使用虚拟dom?

  1. 频繁的改变dom会造成浏览器的回流和重排
  2. 使用虚拟dom,当数据变化,页面需要更新时,通过diff算法,对新旧节点进行对比,产生差异,一次性对dom进行批量更新操作,进而提高了性能
  3. 虚拟dom的本质是js对象,而dom与平台强相关,方便跨平台操作

详解vue的diff算法

5.vue-router

  1. 路由的模式:hash 模式history 模式
  2. hash模式(路由中带#号),通过hashchange事件来监听路由的变化
    window.addEventListener('hashchange', ()=>{})
  3. history 模式,利用了pushState() 和replaceState() 方法,实现往history中添加新的浏览记录、或替换对应的浏览记录
  4. popstate事件来监听路由的变化,window.addEventListener('popstate', ()=>{}) Vue Router原理

6.vuex[vue3]

vuex官网

image.png

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?

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)
        }
    }
})

image.png

8.vue3和vue2的区别

  1. vue3性能比vue2快很多
  2. proxy代替Object.defineproperty,解决了vue2种新增属性监听不到的问题
  3. diff方法优化 vue3新增了静态标记(patchflag),虚拟节点对比时,就只会对这些带有静态标记的节点
  4. 静态提升: vue3不参与更新的元素,会做静态提升,只有被创建一次
  5. 组合API:可以将data与对应的逻辑写在一起,更容易理解
  6. 更好的支持ts
  7. Fragment:模板可以有多个根元素

9.生命周期:

image.png

2.react