基于Vue3实现最简单的 mini-vue
✨代码已上传至CSDN文库,如需要请点击下载min-vue,私信也可免费提供代码。
✨运行顺序 npm install ==>npm run build ==>npm run dev
✨Github mini-vue
项目目录结构
项目配置
webpack.config.js
const path =require('path');
module.exports ={mode:'development',devtool:false,// devtool: 'inline-cheap-source-map',entry:'./src/index.js',//入口文件output:{filename:'mini-vue.js',path: path.resolve(__dirname,'dist'),clean:true,// library: 'MiniVue',// libraryTarget: 'umd'},devServer:{contentBase:'./src/examples',//项目启动html页面publicPath:'/dist',watchContentBase:true,//在文件改变时会进行页面刷新,默认情况下该配置是禁止的。},};
入口 html
examples/index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Expamels</title><script src="../dist/mini-vue.js"></script></head><body></body></html>
入口文件依赖 js
src/index.js
import{ reactive }from'./reactive/reactive';import{ effect }from'./reactive/effect';//监听countconst observed =(window.observed =reactive({count:0,}));effect(()=>{
console.log('observed.count is ==>', observed.count);});//监听数组// const observed = (window.observed = reactive([1,2,3]));// effect(()=>{// console.log('index 4 is ==>',observed[4]);// })// effect(()=>{// console.log('length is ==>',observed.length);// })//监听effect嵌套// const observed = (window.observed = reactive({// count1: 0,// count2: 0,// }));// effect(() => {// effect(() => {// console.log('count2 is ==>', observed.count2);// });// console.log('count1 is ==>', observed.count1);// });
reactive对象代理
reactive/reactive.js
import{ hasChanged, isArray, isObject }from'../untils';import{ track, trigger }from'./effect';const proxyMap =newWeakMap();exportfunctionreactive(target){//不是对象if(!isObject(target)){return target;}//是否被代理过if(isReactive(target)){return target;}if(proxyMap.has(target)){return proxyMap.get(target);}const proxy =newProxy(target,{get(target, key, receiver){if(key ==='_isReactive'){returntrue;}const res = Reflect.get(target, key, receiver);//收集依赖track(target, key);// return res;//Vue2中初始化data时会递归遍历代理所有深层次对象//Vue3处理深层次代理依赖returnisObject(res)?reactive(res): res;},set(target, key, value, receiver){let oldLength = target.length;//拿到旧值,比较是否发生改变countconst oldValue = target[key];const res = Reflect.set(target, key, value, receiver);if(hasChanged(oldValue, value)){//发生改变--触发依赖trigger(target, key);//处理代理数组if(isArray(target)&&hasChanged(oldLength, target.length)){trigger(target,'length');//传参target key}}return res;},});
proxyMap.set(target, proxy);return proxy;}//Reflect:https://www.jb51.net/article/257679.htm//不管执行几次代理,只代理一次//是否被代理过exportfunctionisReactive(target){//_isReactive私有属性判断是否是响应式对象;//返回布尔类型return!!(target && target._isReactive);}
effect副作用函数
reactive/effect.js
const effectStack =[];//处理effect嵌套effectlet activeEffect;//记录当前正在执行的副作用函数exportfunctioneffect(fn){consteffectFn=()=>{try{
activeEffect = effectFn;
effectStack.push(activeEffect);returnfn();}finally{//执行完成后还原
effectStack.pop();//activeEffect = undefined;
activeEffect = effectStack[effectStack.length -1];}};effectFn();return effectFn;}const targetMap =newWeakMap();//模块类全局变量exportfunctiontrack(target, key){if(!activeEffect){return;}let depsMap = targetMap.get(target);if(!depsMap){
targetMap.set(target,(depsMap =newMap()));}let deps = depsMap.get(key);if(!deps){
depsMap.set(key,(deps =newSet()));}
deps.add(activeEffect);}//trck的逆运算exportfunctiontrigger(target, key){const depsMap = targetMap.get(target);if(!depsMap){return;}const deps = depsMap.get(key);if(!deps){return;}
deps.forEach((effectFn)=>{effectFn();});}
项目公用方法
untils/index.js
exportfunctionisObject(target){returntypeof target ==='object'&& target !==null;}exportfunctionhasChanged(oldValue, value){//旧值和新值不能相等,且同时不能为NaN//Number.isNaN http://t.csdn.cn/PnJX6// console.log(oldValue!==value && (Number.isNaN(oldValue) && Number.isNaN(value)));return oldValue !== value &&!(Number.isNaN(oldValue)&& Number.isNaN(value));}exportfunctionisArray(target){return Array.isArray(target);}
初始化项目依赖
package.json
{"name":"mini-vue3","version":"1.0.0","description":"","main":"src/index.js","scripts":{"test":"jest","build":"webpack","dev":"webpack serve --open","format":"prettier --write ."},"author":"","license":"ISC","devDependencies":{"@babel/core":"^7.13.8","@babel/preset-env":"^7.13.8","@babel/preset-typescript":"^7.13.0","@types/jest":"^26.0.23","babel-jest":"^26.6.3","eslint":"^7.31.0","html-webpack-plugin":"^5.3.2","jest":"^27.0.5","prettier":"2.3.2","webpack":"^5.40.0","webpack-cli":"^4.7.2","webpack-dev-server":"^3.11.2"},"dependencies":{}}
实现效果
监听count
监听数组
监听嵌套effect
版权归原作者 小灵儿呐 所有, 如有侵权,请联系我们删除。