vue3核心流程
1.vue3核心过程:编译时=>运行时=>响应式数据=虚拟dom(vnode)=>dom渲染
2.vue3中关键包:compiler-core,compiler-dom,compiler-sfc,reactivity,runtime-core,runtime-dom
3.其中响应式和模版模版编译-关联的过程如下:
那么总结起来就是三步:
- 1.第一步获取我们写的template模版,通过complie编译成AST抽象语法树【】
- 2.第二步通过createElement方法把ast转换为vnode
- 3.第三步就是通过render方法把vnode变为真实dom
无奖问答:vue3为什么要先转换成vnode?目的是解决什么问题?有什么好处?
下面开始vue3 响应式模块的原理部分
1.为什么要使用响应式 reactive/ref?
目标:达到自动更新视图,当数据发生变化时,无需关心视图的更新操作逻辑;使得状态和视图操作解耦合
2.具体实现原理
核心思想:1.获取属性时 收集依赖; 2.数据变动,派发更新;【类比服务端能够劫持或代理更新和获取操作】
前置条件:数据劫持,数据代理。
使用代理对象方式,监听属性的获取和变更。
在vue2中使用object.definePropty 实现的,无法监听对象属性的增删或数组操作,在vue3 则使用更为高效的 proxy实现。
3.响应式系统定义和使用
vue playgroud组件定义
<script setup>
import { ref,reactive } from 'vue'
//const msg = ref('Hello World!')
//定义状态
const state =reactive({count:123})
//定义操作
const add=()=>state.count++;
</script>
<!-- 定义视图 -->
<template>
<div>
<!--
<h1>{{ msg }}</h1>
<input v-model="msg" /> -->
<h2>count:{{ state.count }}</h2>
<button @click='add'>增加</button>
</div>
</template>
<style scoped>
div{
color:red
}
</style>
4.动手实践-响应式 [解决了一个问题:状态如何驱动和解耦视图] 1.原始方式==面向dom操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="module">
//定义状态
let state={count:1};
//定义状态操作
const add=()=>{
state.count++;
}
const render = ()=>{
document.body.innerHTML = `<div>${state.count}</div>`
}
//定义渲染方法 vue react 中都有vnode->dom
render();
//耦合操作
window.addEventListener('click',()=>{
//状态操作
add();
//重新渲染
render();
})
</script>
</body>
</html>
2.响应式操作方式 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<button id="btn">点击</button>
<script type="module">
import {effect,reactive,ref} from './reactive.js';
const btn = document.getElementById('btn');
const app = document.getElementById('app');
const state = reactive({count:1})
// let state = ref(1);
//
const render = ()=>{
app.innerHTML = `nums=>${state.count}`
}
//用来跟踪和响应数据的变化指入口
effect(render)
//事件触发和视图更新解耦
btn.addEventListener('click',()=>{
state.count++;
})
</script>
</body>
</html>
reactive.js
//依赖map
/**
* {counter:[fn1,fn2],counter2:[fn3,fn4]}
*/
//当前effect
let __activeEffect=null;
//副作用收集
export const effect= (fn) => {
console.log('Effect');
__activeEffect = fn;
fn();
__activeEffect = null;
}
//响应式对象 监听obj变化
export const reactive = (obj) => {
const triggerMap = new Map();
console.log('Reactive');
//依赖收集
const handler= {
get(target, key) {
console.log('Get');
const result = Reflect.get(target, key);
if (__activeEffect) {
// track(target, key); //依赖收集 可单独抽离成api
if(!triggerMap.has(key)) {
triggerMap.set(key, []);
}
triggerMap.get(key).push(__activeEffect);
}
return result;
},
//派发更新
set(target, key, value) {
console.log('Set');
const oldValue = target[key];
const result = Reflect.set(target, key, value);
if (oldValue !== value) {
//派发更新 //trigger(target, key);
triggerMap.get(key).forEach((effect) => {
effect();
})
}
return true;
}}
return new Proxy(obj,handler)}
export const ref = (value) => {
return reactive({value});
}
5.响应式流程总结
源码大致位置
vue reactive 源码关键位置: