Spiga

分类为扩展阅读的文章

前端提升7:手撸Vue3组件渲染

2025-04-12 23:21:56

摘要:一、实现DOM操作API 1. 构建环境 创建runtime-dom目录,存放dom操作api 创建runtime-core目录,存放允许时虚拟dom操作核心代码 在两个目录中分别构建环境 /packages/runtime-dom/package.json { name: @vue/runtime-dom, module: dist/runtime-dom.esm-bundler.js, unpkg: dist/runtime-dom.global.js, buildOptions: { name: VueRuntimeDOM, formats: [ esm-bundler, cjs, global ] } } /packages/runtime-core/package.json { name: @vue/runtime-core, module: dist/runtime-core.esm-bundler.js, unpkg: dist/runtime-core.global.js, buildOptions: { name: VueRuntimeCore, formats: [ esm-bundler, cjs, global ] } } 2. 定义操作API /packages/runtime-dom/src/nodeOps.ts // dom操作 vue虚拟dom, 通过数据对象在内存中对比差异, 找到最小的改动点,使用dom操作完成更新。 // 原生dom操作api export const nodeOps = { // 插入, 追加 insert: (child, parent, anchor = null) = { parent.insertBefore(child, anchor); // parent.appendChild(child) }, // 删除子节点 remove: child = { const parent = child.parentNode; if (paren…… 阅读全文

前端提升6:手撸vue3响应式实现

2025-04-05 18:21:43

摘要:Vue3响应式的实现跟Vue2最大的不同点是Vue3中的响应式是个独立模块,可以单独拿出来使用。 不仅仅响应式是模块化的,Vue3的设计理念也是基于模块化来设计的。而要使用Vue2的响应式,就必须加载整个Vue2的库。 一、rollup环境搭建 我们使用Vue3搭建上面的时候,经常会用到Vite,而Vite实际上是基于rollup实现的。 Rollup 是一个 JavaScript 模块打包工具,它可以将多个 JavaScript 文件(模块)打包成一个或多个优化后的文件。与 Webpack 类似,但 Rollup 更专注于 ES6 模块的打包,通常用于库/框架的开发。 除了rollup外,esbuild也是一个很不错的前端构建工具。 rollup 类库打包工具, 专注于模块的tree-shaking, 尽量减少模块打包的大小。 拥有庞大的插件生态系统,如代码拆分,语法转换等 常用于构建library, 特别是专注于es6模块 前端工程打包,一般使用webpack esbuild 主要特点速度很快,用go编写,可以并行处理。 对ast语法树操作能力不太强, 老项目升级用esbuild 开发使用esbuild构建编译,生产打包使用成熟的rollup 接下来我们使用先使用rollup搭建一个本地环境 环境搭建 新建一个vue3的文件夹,然后安装rollup yarn add rollup --dev 目录搭建 --packages # 因为Vue3是基于模块化来设计的,我们设计包文件的时候也分开构建,所以packages目录下都有会自己的项目文件 --reactivity # 响应式实现包 --dist --node_modules --src index.ts package.json pnpm-lock.yaml --shared # 公共库 --dist --src index.ts package.json --scripts build.js dev.js .npmrc package.json pnpm-lock.yaml rollup.config.js tsconfig.json 基本配置 rollup.config.js i…… 阅读全文

前端提升5:手撸vue2响应式+渲染

2025-03-29 16:26:46

摘要:阅读vue(2.6)的源码,data响应式大概有如下4个过程: 数据代理:core/instance/state.js---vue函数---initMixin---initState---数据遍历---observer/index.js---Observer--- defineReactive---defineProperty 数据装载:$mount---装载template---compileToFunctions---mountComponet---创建【渲染Watcher】---Watcher.get()---Watcher.get()依赖收集---Dep.target就是当前的Watcher(data中的属性—dep-----watcher 形成双向引用) 数据相应式:需要修改data属性---触发setter回调执行---通知dep上的watcher更新dep.notify()---遍历所有的watcher并调用watcher的update方法---调用run方法---调用get()方法实现页面渲染 数据渲染:vm.__patch__---createPatchFunction---patchVnode---双方都有孩子节点updateChildrendiff代理 以下我们参考vue的源码,记录实现data响应式的全过程 一、数据劫持 收先我们混入一个方法,给Vue对象添加一个内部_init方法,我们在这个内部方法中去实现需要的功能 //index.js import { initMixin } from ./init; function Vue(options){ // vue2 配置项 console.log(my vue 6666) this._init(options); // vue 内部约定 私有的方法或属性 一般是以 $ _ 开头 } initMixin(Vue); // 一执行,Vue就有_init方法 export default Vue //init.js 初始化 import { initState } from ./state; // 混入 类似于 对象语言的继承 // 在不改变这个函数的前提下,给这个函数增加方法 增强功能 // 原理是在prototype上添加方…… 阅读全文

前端提升4:Vue全家桶

2025-03-22 14:44:23

摘要:一、Vue3项目搭建 Node.js:是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O 模型,让JavaScript 运行在服务端的开发平台; 版本要求=12.0.0; npm:Nodejs下的包管理器;版本要求 6.x yarn:包管理器; yarn 包管理器是 npm 的一个替代方案,由Facebook于2016年10月发布。 Vite:是一个 web 开发构建工具,使用 Vite 可以快速构建 VUE 项目比webpack打包更加快速 快速的冷启动 即时的模块热更新 真正的按需编译 创建vite3项目:npm init vite,输入项目名称 安装依赖 cd vite-project 进入项目 依赖安装 npm install 或 cnmp i 运行vite项目:npm run dev 访问:http://localhost:5173 包管理工具Yarn的使用 yarn create vite:输入项目名称 cd vite-d2 安装依赖:yarn 项目启动:yarn dev 二、Vue3.2新特性 1. createApp 在 Vue 3 中,改变全局 Vue 行为的 API 现在被移动到了由新的 createApp 方法所创建的应用实例上。 import { createApp } from 'vue' const app = createApp({}) 该实例提供了一个应用上下文,由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法 import { createApp } from 'vue' import App from './App.vue' import router from './router' import store from './store' const app = createApp(App); app.use(store) app.use(router) app.mount('#app'); //合并之后的代码: createApp(App).use(store).use(router).mount('#app') 2. setup函数 setup函数是vue3中专门为组件提供的新属性。 创建组件实例,然后初…… 阅读全文

前端提升2:ES

2025-03-08 15:14:23

摘要:一、let与const let用来声明变量,它的用法类似于 var 不存在变量提升 同一个作用域内不能重复定义同一个名称 有着严格的作用域 const 声明一个只读的常量。一旦声明,常量的值就不能改变。 保持let的不存在变量提升,同一个作用域内不能重复定义同一个名称,有着严格的作用域 const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动 window.onload = function () { // let 和var的不同 // 1、不存在变量提升 // console.log(a); // var a = 100; // //解析过程 // //预解析 // var a; // //逐行解析 // console.log(a); // a = 100; // // // console.log(a); //Cannot access 'a' before initialization // let a = 100; //2、同一个作用域内不能重复定义同一个名称 // var a = 10; // var a = 100; // console.log(a); //100 // var a = 10; // let a = 100; // console.log(a); //Identifier 'a' has already been declared // let a = 10; // let a = 100; // let a = 10; // a = 100; // console.log(a); //100 //3、有着严格的作用域 // function fn(){ // var a = 'a'; // if(true){ //块级作用域 // let a = 'b' // }; // console.log(a) //'a' // }; // fn(); …… 阅读全文

前端提升1:JS

2025-03-01 16:56:47

摘要:一、JS数据结构 js的数据定义与检查 var str = 'abc'; var num = 123; var bool = true; var und = undefined; var n = null; var arr=['x','y','z']; var obj = {}; var fun = function() {}; console.log(typeof str); //string console.log(typeof num); //number console.log(typeof bool); //boolean console.log(typeof und); //undefined console.log(typeof n); //object console.log(typeof arr); //object console.log(typeof obj); //object console.log(typeof fun); //function 1. 字符串 window.onload = function () { // 字符串常用的属性和方法 // charAt() 方法可返回指定位置的字符。 // concat() 方法用于连接两个或多个字符串。 // indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。 // lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置 // includes() 方法用于判断字符串是否包含指定的子字符串 // replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串 // split() 方法用于把一个字符串分割成字符串数组 // substr() 方法可在字符串中抽取从开始下标开始的指定数目的字符 // substring() 方法用于提取字符串中介于两个指定下标之间的字符 // slice(start, end) 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分 // toLowerCase() 方法用于把字符串转换为小写 // toUpperCase() 方法用于把字…… 阅读全文

ABP成长系列7:数据访问

2024-06-01 16:01:56

摘要:一、仓储 仓储模式是ABP框架数据访问层的核心抽象,它提供了一种统一的方式来访问数据源,无论底层使用何种数据库技术(EF Core、MongoDB等)。 接口抽象:框架定义了一系列通用的仓储接口,如 IRepositoryTEntity, TKey。你的领域层和应用层只依赖于这些接口,而不是具体的实现,这严格遵循了DDD的持久化无关原则。 默认实现:ABP为EF、MongoDB和Dapper提供了这些仓储接口的开箱即用的实现。这意味着对于大多数标准的CRUD操作,无需编写任何仓储实现代码。 自定义仓储:对于复杂的查询或特定操作,可以定义自定义的仓储接口(如 ICustomRepository),并在基础设施层(如EntityFrameworkCore项目)中实现它。ABP的依赖注入系统会自动将其注册到容器中。 类关系图 1. 仓储接口体系 ABP定义了一套完整的仓储接口体系,位于Volo.Abp.Domain.Repositories命名空间: //IRepository.cs public interface IRepository { } public interface IRepositoryTEntity : IReadOnlyRepositoryTEntity, IBasicRepositoryTEntity where TEntity : class, IEntity { TaskTEntity FindAsync([NotNull] ExpressionFuncTEntity, bool predicate, bool includeDetails = true, CancellationToken cancellationToken = default); TaskTEntity GetAsync([NotNull] ExpressionFuncTEntity, bool predicate, bool includeDetails = true, CancellationToken cancellationToken = default); Task DeleteAsync([NotNull] ExpressionFuncTEntity, bool predicate, bool autoSave =…… 阅读全文

ABP成长系列6:DDD

2024-05-25 11:56:40

摘要:ABP是一个面向DDD的项目框架,接下来的内容将学习如何利用ABP来落地DDD的项目,我们今天先来总结一下DDD的核心思想。 一、什么是领域驱动设计 1. 传统软件开发 业务梳理 == 软件设计 == 开发 初期-简单-迭代-复杂-冗杂-屎山代码-牵一发而动全身-重构系统-演进 示例:订单服务(查询订单、创建订单、订单评价、支付……) 项目流程:讨论需求==数据库建模==项目开发==迭代数据库的设计==上线 2. 领域驱动开发 根据领域知识一步步驱动软件设计的过程就是领域驱动设计(DDD,Domain-Driven Design) 领域驱动设计(DDD)是一种处理高度复杂领域的设计思想 设计思想:通过分离技术实现的复杂性,并围绕业务概念构建领域模型来控制业务的复杂性 项目流程:领域模型=数据库设计 3. 战略设计和战术设计 领域驱动设计包括战略设计和战术设计两部分: 战略设计:从业务视角出发=》业务领域模型=》边界=》通用语言的限界上下文 战术设计:从技术视角出发=》技术实现=》实体、聚合根、值对象、领域服务…… 二、领域驱动设计的基础概念 1. 领域和子域 领域(业务问题域)具体指一种特定的范围或区域,就是用来确定范围的,范围就是边界 细分-限定-领域模型-代码实现 领域越大业务范围就越大 领域可以进一步划分为子领域(子域 更小的) 子域对应一个更小的范围 我们来看一张经典的图 给桃树建立领域知识的步骤: 确定研究对象 对研究对象进行细分 对子对象再次进行细分 细分到最小单元 再来看一个电商项目的领域划分的例子: 电商领域可以分成:商品子域、销售子域、订单子域、物流子域 物流子域又可以分成:拣货子域、发货子域、派送子域 领域建模的过程和方法其核心思想就是将问题域逐步分解 降低业务理解和系统实现的复杂度 2. 核心域、通用域和支撑域 核心域:产品核心业务功能 通用域:被多个子域使用的通用功能(认证、授权、日志) 支撑域:既不包含业务核心功能,也不包含通用功能 电商平台中:销售子域是核心域,物流子域是支撑销售业务的,所以它的支撑域 植物研究领域中,需要根据不同情况来划分核心域 如果是在果园:果实就是核心域。为了让果实更饱满,果农可能会裁剪一些枝和叶 如果是在公园:花就是核心域 3. 通用语言 通过团队交流达成共识的,能够简…… 阅读全文

ABP成长系列4:认证授权

2024-05-11 11:49:34

摘要:ABP框架并不重新发明轮子去实现认证,而是完美集成并简化了上述ASP.NET Core的认证流程。 模块化封装:当你使用ABP的启动模板时,认证的配置通常已经在模块中预先配置好,你只需要在appsettings.json中提供必要的参数(如JWT的签发者、密钥等)。 依赖注入集成:ABP通过ICurrentUser提供了对当前登录用户ID (UserId) 和租户ID (TenantId) 的便捷访问。这个接口的背后实现正是基于HttpContext.User及其声明(Claims)。 多租户支持:ABP的认证系统天然支持多租户,可以正确处理不同租户下的用户登录和会话管理。 ABP的主要价值在于整合与简化,它让你在使用强大的ASP.NET Core认证机制的同时,享受到ABP模块化和约定优先开发模式带来的便捷。 要学习好ABP的认证授权模块,我们来看一下ASP.NET Core的认证授权。 一、ASP.NET Core认证授权 1. 基本流程 UseAuthentication + AddAuthentication UseAuthorization + AddAuthorization(.net源码内置) [Authorize] [AllowAnonymous] 未登陆—访问—登陆—访问—退出 2. 理解认证 认证就是鉴别是张三----解读请求携带的用户信息 信息位置:怎么传递的凭证?Cookie,JWT,Other 信息格式:凭证是什么格式,加密问题 信息有效性:token过期了、签名不对 认证后信息保存:保存到context.User里面 特殊情况处理:没登陆、没权限、没xxx,这些就是认证需要知道的,需要干的活儿 登陆是怎么配合的?HttpContext.SignInAsync完成用户信息的写入(如:Cookie) 3. 理解授权 授权:就是检测下用户到底有没有权限访问某个方法 认证和授权的关系? 没有直接关系,认证获取用户信息保存到context.User,授权去使用 授权的时候,会用Scheme去认证一下,还有异常处理 检测凭据: 标记特性[Authorize] [AllowAnonymous]—就做授权检测 ASP.NET Core提供了灵活且强大的授权策略模型,主要包括: 基于角色的授权 ([Authorize(Roles =…… 阅读全文

ABP成长系列3:DI

2024-05-04 11:03:40

摘要:前面重点介绍了ABP.vNext的模块化,以及模块化带来的核心价值动态API,今天我们开看一下ABP DI的扩展。 一、ABP DI功能介绍 1. 组件自动注册 SkipAutoServiceRegistration AddAssemblyOf AddAssembly public class BlogModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { SkipAutoServiceRegistration = true; } public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAssemblyOfBlogModule(); } } 2. 默认的注册 模块类注册为singleton MVC控制器(继承Controller或AbpController)被注册为transient MVC页面模型(继承PageModel或AbpPageModel)被注册为transient MVC视图组件(继承ViewComponent或AbpViewComponent)被注册为transient 应用程序服务(实现IApplicationService接口或继承ApplicationService类)注册为transient 存储库(实现IRepository接口)注册为transient 域服务(实现IDomainService接口)注册为transient 3. 依赖接口 ITransientDependency 注册为transient生命周期 ISingletonDependency 注册为singleton生命周期 IScopedDependency 注册为scoped生命周期 4. 特性 DependencyAttribute:控制服务的注册行为和生命周期 ExposeServicesAttribute:控制服务以哪些类型注册到容器中 [ExposeServices(typeof(…… 阅读全文