vue3源码学习

使用最新的vue3.0  输入命令   vue add vue-next
 ****************
option api    和   compositi on api的区别 
1, a 传统对象api,  b hooks api 函数式变成 增强复用 
2,  b 使用了ref  computed  很好的支持了 tree-shaking(摇树)
3,  b 取代了 mixins
4,    hooks 每次都产生一个hooks闭包,b第一次会产生一个闭包,其他用响应式实现

 ****************

import {reactive, ref , computed, onMounted, watchEffect} from 'vue';

reactive 把对象变成响应式 
ref  把基本数据类型变成响应式 
computed  计算属性 
onMounted   
 watchEffect 数据响应后,通知给组件更新  这个函数执行 意味着 
数据变了 vdom的diff 开始最小化操作dom

 ****************

proxy  不支持IE11  需要polyfill 提供支持

@vue/reactivity 是一个新的工具包,vue依赖这个包实现 
composition =  @vue/reactivity + 生命周期 

ref/reactive 的代码实现

ref 

// 手动实现一个 ref 

let activeEffect // 临时存储依赖改变的方法
// 工具类
class Dep{
    constructor(){
        this.subs = new Set(); // 依赖容器
    }
     depend(){  // 收集依赖
        if(activeEffect){
            this.subs.add(activeEffect);
        }
     }
     notofy(){ // 数据变化 触发effect 执行 
        this.subs.forEach(effect=>effect())
     }
}
const dep = new Dep();  // vue3 中这个将变成一个大的map对象 
// ref 实现 一个 基础数据绑定的实现  
function ref(ininVal){
    let _v = ininVal;
    let state = {
        get value(){  
            // 获取值, 收集依赖 
            dep.depend();
            return _v;
        }, // 子面量的get写法
        set value(val){
            // 通知函数执行effect ,改变值 
            _v=val;
           dep.notofy(); // 执行effect 修改dom
        }
    }
    return state;
}


let state = ref(0);

function effect(fn){
    console.log(fn)
    activeEffect = fn // 先往临时变量存个方法
    fn();   // 然后调用get 就可以收集到依赖
     //watcheffect 执行dom的更新 
}
// 传入一个方法 ,实际vue3执行的不是我们的这个方法,是某个关键方法 
effect(()=>{ // 先执行一次  
    console.log(state.value)
})
 
 setInterval(()=>{
    state.value++;
 },1000)

手工实现一个reactive

// 配合index.html 手动实现一个 reactive


// WeakMap key 必须是对象 ,万一key的弱引用对象被删除则会被自动清除,
// 设计有助于防止内存泄漏, 有一种使用场景是和dom进行绑定;
let targetMap = new WeakMap();
const effectStack = [];

function track(target,key){  // 收集依赖 ,因为 reactive可能有多个,一个又有多个属性在变化 
    const effect = effectStack[effectStack.length - 1];
    if(effect){
        let depMap = targetMap.get(target);
        if(!depMap){
            depMap=new Map();
            targetMap.set(target,depMap);
        }
        let dep = depMap.get(key);
        if(!dep){
            dep= new Set();
            depMap.set(key, dep);
        }
    
        dep.add(effect);
    }
}
function trigger(target,key,info){ // 触发更新
    let depMap = targetMap.get(target);
    if(!depMap){ // 如果执行的话没有依赖就中断
        return 
    }
    const effects = new Set();
    const computedRenders = new Set();
    
    let deps = depMap.get(key);
    deps.forEach(effect => {
        if(effect.computed){
            computedRenders.add(effect)
        }else{
            effects.add(effect);
        }
    });
    // 两者处理的其他的东西不一样
    computedRenders.forEach(computed=>computed());
    effects.forEach(effect=>effect());
}

function effect(fn,options={}){  // 副作用
    //  {lazy:false, computed:false} = options
    // lazy是否是第一次 ,第一次不执行,否则执行, flag
    // computed 是否是计算属性 
    // computed  是一个特殊的 effect 
    // fn 是用户自定义的方法

    let e = createReactiveEffect(fn,options); // 获取effect 
    if(!options.lazy){
        e();
    }
    return e;
}

function createReactiveEffect(fn,options){
    const effect = function effect(...args){
        return run(effect,fn,args );
    }
   effect.deps = []; // 清理依赖和缓存
   effect.computed = options.computed;
   effect.lazy = options.lazy;
   return effect
}

function run(effect,fn,args){
    if(effectStack.indexOf(effect)===-1){
        try{
            effectStack.push(effect); // 维护
            return fn(...args);
        }finally{
            effectStack.pop(); // 维护清理掉 
        }
    }

}


let baseHandler = {
    get(target,key){ // 使用 reflect.get 更合理  ,把 目标的get 方法重写 
        const res = target[key]; 
        track(target,key); // 收集依赖
        return res; 
    },
    set(target,key,val){ // 使用 reflect.set 更合理  ,把 目标的set 方法重写 
        const info = {oldVal: target[key],newVal:val};
        target[key] = val;
        trigger(target,key,info); // 需要更新时,把所有的值都传递出去 
    },
 //    has, ownkey 等都可以拦截 
}
function reactive(target){  // 变成响应式的  
    let observed = new Proxy(target,baseHandler)

    return observed;

}

function computed(fn){  // 基于effect去实现的
    const runner = effect(fn,{computed:true,lazy:true});
    return {
        effect: runner,
        get value(){
            return runner();
        }
    }
}

index.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
    <div id='app'>
        
    </div>
    <button id='btn'>btn</button>
</div>
</body>
<script src='./reactive.js'></script>
<script>
    const root = document.getElementById('app');
    const btn = document.getElementById('btn');
    let obj = reactive({
        name : '八神',
        age : 18
    })
    let double = computed(()=>obj.age*2);
    effect(()=>{
        console.log('数据变了',obj.age);
        root.innerHTML = `<h2>${obj.name}</h2><h3>今年${obj.age}</h3><h4>双倍年龄是${double.value}岁</h4>` 
    })
    
    btn.addEventListener('click',()=>{
        obj.age+=1;
    },false);
</script>
</html>

html

 

***********************************

.性能对比  2和3 
1, proxy 取代 defineproperty
2,   vdom 重写   a. 静态标记   b. 纯静态节点会被标记 ,重新渲染的时候根本不会动

    5, event 等)
动态节点, 会维护在一个数组内(block内部)
为什么  vue 和react 需要编译   
3, diff 算法 
vue2 的时候是 双端比较  比较两个对象  只算出需要更新的部分
vue3加入了 最长递增子序列  

jsx  动态性太好 整体渲染(vue2的静态标记也不多)但是静态标记就会不起作用,
 还是要多用 template 


.compiler 

编译原理
ast  --》 transform --》 generate 
 template parse -》 ast  抽象语法树 
transform 做优化 v-if   扩展 在这个模块 加上vue 语义
generate  生成执行代码  render 函数渲染  

.静态标记 
vdom 其实template是编译成了一个大的对象,json的每个属性上都说明了自己是谁是干嘛的
有没有孩子节点(静态标记代码: 1,text,2,class 3, props,4, fullprops
静态标记 对 性能做到了极致. 灵感来源于prepack.io 

.ssr 对比 
把dom 全部静态节点变成了字符串, 只有一个buffer 不停的往里面推送字符串
Vue2把template重新计算编译了 其实是性能浪费

.自定义render

 **************** 

vue 的watch 知道component层面, component内部使用component内部使用diff算法 
Diff 算法 有16.6毫秒的瓶颈 会倒是卡顿, 把 diff算法的应用缩小到了componnet上 就从设计上很好的解决了这个瓶颈问题 
React 全部都是diff算法 , 也存在 16.6毫秒的问题, 这个时候他是通过fiber架构取解决这个问题的,把树变成了链表, diff 算法 到了16.6毫秒 后 马上把 处理器还给浏览器,让浏览器继续动画等内容 , 过了之后再继续回来dom diff计算,  备胎 算法(利用空闲时间来计算 diff )

************************* 

 

|& 位运算 控制路由权限

| 授权
 & 验证


Vite  新一代开发工具 替代webpack  复杂度 o1

利用浏览器的import来进行速度的提升

socket 热更新 

参考大圣老师的讲解整理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个开源的Java开发框架,它简化了Spring应用程序的配置和部署过程。Vue是一个流行的JavaScript框架,用于构建用户界面。 目前,Vue3还没有发布官方的稳定版本,但是它的源代码已经可以在GitHub上找到。Vue3相对于Vue2有一些重要的改变和改进。其中一些改变包括:重构了内部架构,使用了Proxy代替Object.defineProperty实现侦听属性的变化,提供了更好的Tree Shaking和按需加载支持,以及更好的TypeScript集成等。 当谈及Spring Boot与Vue3的源码时,我们可能会考虑到两个方面:Spring Boot对于Vue3的支持和Vue3实现Spring Boot的实例。 对于前者,Spring Boot可以作为后端框架与Vue3前端进行交互。Spring Boot提供了RESTful API的支持,可以与前端进行数据交换和状态管理。同时,Spring Boot还可以提供认证和授权功能,保护前端应用程序的安全性。这意味着,我们可以使用Spring Boot构建后端服务,通过接口与Vue3前端进行通信。 对于后者,Vue3不能直接实现Spring Boot的功能。因为Vue3是用JavaScript编写的前端框架,而Spring Boot是用Java编写的后端框架。它们是不同的技术栈,无法直接交互。但是,我们可以使用Vue3配合Spring Boot进行前后端的开发。Vue3可以通过RESTful API与Spring Boot进行数据交互,同时实现前端的用户交互和界面呈现。 总结来说,Spring Boot和Vue3是两个不同的框架,用于不同的应用程序层。Spring Boot是一个用于构建后端服务的Java框架,而Vue3是一个用于构建前端应用程序的JavaScript框架。它们可以通过RESTful API进行交互,实现前后端的数据交换和状态管理。对于Vue3的源码,我们可以通过GitHub上的源代码仓库来了解和学习

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值