专题:一个自制代码生成器(嵌入式脚本语言)之应用实例

news/2024/4/19 14:57:39/文章来源:https://blog.csdn.net/2301_77171572/article/details/137064454

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


专题:一个自制代码生成器(嵌入式脚本语言)之总述-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之对象模型-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之堆栈结构和总入口-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之核心逻辑-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之辅助逻辑-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之应用实例-CSDN博客(本篇)

专题:一个自制代码生成器(嵌入式脚本语言)之模型开发-CSDN博客

专题:一个自制代码生成器(嵌入式脚本语言)之代码模板详解-CSDN博客


目录

一、数据库模型

二、应用实例

2.1 创建模型

2.2 生成代码

2.3 生成的代码

三、如何创建模型


一、数据库模型

        数据库模型是根据数据库定义生成数据库操作相关代码的模型,生成的代码是静态代码,具有静态代码的编译时检查和运行效率。

        数据库模型支持表定义、主键、定制的DML操作。对于C++客户代码,所有操作都是基于函数的,函数名和参数清晰地表达了函数的功能。

        下面我们先了解一个应用实例,然后再研究如何编写模型。

二、应用实例

2.1 创建模型

bool Rooster_AddAllTable(CCTModel_UniversalDB* pCTM)
{CCTModel_UniversalDB::table* p;//资源类型,预定义的数值p = pCTM->AddNewTable("RESOURCE_TYPE_D", "资源类型");if (NULL == p)return false;p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");p->AddMember("COMMENT", "string", "备注");p->SetPK("RESOURCE_TYPE_ID");p->AddDML("InsertNewResourceType", "insert", "RESOURCE_TYPE_ID,COMMENT", "", "插入新资源类型");//资源使用类型,预定义的数值p = pCTM->AddNewTable("RESOURCE_USE_TYPE_D", "资源使用类型");if (NULL == p)return false;p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");p->AddMember("COMMENT", "string", "备注");p->SetPK("RESOURCE_USE_TYPE_ID");p->AddDML("InsertNewResourceUseType", "insert", "RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新资源使用类型");//资源p = pCTM->AddNewTable("RESOURCE_D", "资源");if (NULL == p)return false;p->AddMember("RESOURCE_ID", "long", "资源ID");p->AddMember("RESOURCE_NAME", "string", "资源名称");p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");p->AddMember("RESOURCE_WITH_SYS", "long", "资源是否区分sys/sys2");p->AddMember("COMMENT", "string", "备注");p->SetPK("RESOURCE_ID");p->AddDML("InsertNewResource", "insert", "*", "", "插入新资源");p->AddDML("GetAllResource", "select", "*", "", "获得全部");//任务定义p = pCTM->AddNewTable("TASK_D", "任务");if (NULL == p)return false;p->AddMember("TASK_ID", "long", "任务ID");p->AddMember("TASK_NAME", "string", "任务名称");p->AddMember("TASK_MULTIPLE", "long", "0非多开1多开");p->AddMember("TASK_WITH_SYS", "long", "是否区分sys/sys2");p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先");p->AddMember("TASK_PLAN_TIME", "string", "执行时间,‘2,8-16’,时间点或时间段");p->AddMember("TASK_PLAN_INTERVAL", "long", "执行时间段的执行间隔(分钟0-59)");p->AddMember("TASK_START_CMD", "string", "启动命令");p->AddMember("COMMENT", "string", "备注");p->SetPK("TASK_ID");p->AddDML("InsertNewTaskDefine", "insert", "*", "", "插入新任务定义");p->AddDML("GetAllTask", "select", "*", "", "获得全部");//任务资源使用定义p = pCTM->AddNewTable("TASK_RESOURCE_USE_D", "任务资源使用");if (NULL == p)return false;p->AddMember("TASK_ID", "long", "任务ID");p->AddMember("RESOURCE_ID", "long", "资源ID");p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");p->AddMember("COMMENT", "string", "备注");p->SetPK("TASK_ID,RESOURCE_ID");p->AddDML("InsertNewTaskResurceUseDefine", "insert", "TASK_ID,RESOURCE_ID,RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新任务资源使用定义");p->AddDML("GetAllTaskResourceUse", "select", "*", "", "获得全部");//任务队列表p = pCTM->AddNewTable("TASK_QUEUE", "待执行的任务队列");if (NULL == p)return false;p->AddMember("TASK_ID", "long", "任务ID");p->AddMember("SYS", "long", "维度1");p->AddMember("SYS2", "long", "维度2");p->AddMember("TASK_NAME", "string", "任务名称(参考)");p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先(参考)");p->AddMember("COMMENT", "string", "备注(参考)");p->AddMember("INSERT_TIME", "time", "开始时间", "", "TIME_LOG");p->SetPK("TASK_ID,SYS,SYS2");p->AddDML("InsertNewTaskQueue", "insert", "TASK_ID,SYS,SYS2,TASK_NAME,TASK_PRIORITY,COMMENT,INSERT_TIME", "", "插入新任务队列");p->AddDML("DeleteTaskQueue", "delete", "", "TASK_ID,SYS,SYS2", "删除任务队列");p->AddDML("GetAllTaskQueue", "select", "*", "", "获取全部任务队列");p->AddDML("GetTaskQueue", "select", "*", "TASK_ID,SYS,SYS2", "获取任务队列");//任务执行表p = pCTM->AddNewTable("TASK_LOG", "任务日志");if (NULL == p)return false;p->AddMember("TASK_LOG_ID", "long", "任务执行序列号SEQ_TASK_LOG");p->AddMember("TASK_ID", "long", "任务ID");p->AddMember("SYS", "long", "维度1");p->AddMember("SYS2", "long", "维度2");p->AddMember("PID", "long", "任务所在的进程,客户方写入");p->AddMember("START_TIME", "time", "开始时间", "", "TIME_LOG");p->AddMember("FINISH_TIME", "time", "结束时间", "", "TIME_LOG");p->AddMember("RETURN_VALUE", "long", "返回值 0成功 <0Rooster错误 >0任务错误");p->AddMember("UPDATE_TIME", "time", "记录更新时间", "", "TIME_LOG");p->SetPK("TASK_LOG_ID");p->AddDML("InsertNewTaskLog", "insert", "TASK_LOG_ID,TASK_ID,SYS,SYS2,START_TIME,UPDATE_TIME", "", "插入新任务日志");p->AddDML("UpdateTaskLog", "update", "PID,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");p->AddDML("FinishTaskLog", "update", "FINISH_TIME,RETURN_VALUE,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");p->AddDML("GetCurrentTask", "select", "*", "", "获取正在运行的任务", "finish_time=0");//序列if (NULL == pCTM->AddNewSequence("SEQ_TASK_LOG", "TASK日志序列", 0))return false;return true;
}

        这个代码创建了一组表和一个序列,每一行代码的功能都是显而易见的。

2.2 生成代码

int main(int argc, char** argv)
{if (!InitActiveApp("CCTModel_UniversalDB", 1024 * 1024, argc, argv))exit(1);if (sizeof(long) != 8){thelog << "非64位程序!" << ende;}G_IS_DEBUG = true;CCTModel_UniversalDB ctm;if (!Rooster_AddAllTable(&ctm)){thelog << "执行失败" << ende;return __LINE__;}if (!ctm.CreateCode("ns_rooster_struct", "RoosterStruct", ".")){thelog << "执行失败" << ende;return __LINE__;}thelog << "程序退出" << endi;return 0;
}

        有用的就两句:Rooster_AddAllTable创建模型,CreateCode生成代码。

2.3 生成的代码

        生成的一组文件:

        总入口头文件是_cc_CRoosterStruct.h:

//_cc_CRoosterStruct.h 自动生成的代码
//
// Copyright (c) ct  All rights reserved.
// 版权所有 ct 保留所有权利
////警告:本文件由CT系统自动生成,不可手工修改#ifndef CTFC_RoosterStruct_H
#define CTFC_RoosterStruct_H 1//如果需要使用内存数据库直连功能,请在包含本头文件之前定义 CTFC_RoosterStruct_H_SHM_DB
//如果需要使用MariaDB功能,请在包含本头文件之前定义 CTFC_RoosterStruct_H_MARIA_DB
#include "_cc_RoosterStruct_RESOURCE_TYPE_D.h"
#include "_cc_RoosterStruct_RESOURCE_USE_TYPE_D.h"
#include "_cc_RoosterStruct_RESOURCE_D.h"
#include "_cc_RoosterStruct_TASK_D.h"
#include "_cc_RoosterStruct_TASK_RESOURCE_USE_D.h"
#include "_cc_RoosterStruct_TASK_QUEUE.h"
#include "_cc_RoosterStruct_TASK_LOG.h"
#include "_cc_RoosterStruct_SEQ_TASK_LOG.h"using namespace ns_my_std;namespace ns_rooster_struct
{class CShmDB_RoosterStruct{public://表CRoosterStruct_RESOURCE_TYPE_D m_RESOURCE_TYPE_D;//资源类型CRoosterStruct_RESOURCE_USE_TYPE_D m_RESOURCE_USE_TYPE_D;//资源使用类型CRoosterStruct_RESOURCE_D m_RESOURCE_D;//资源CRoosterStruct_TASK_D m_TASK_D;//任务CRoosterStruct_TASK_RESOURCE_USE_D m_TASK_RESOURCE_USE_D;//任务资源使用CRoosterStruct_TASK_QUEUE m_TASK_QUEUE;//待执行的任务队列CRoosterStruct_TASK_LOG m_TASK_LOG;//任务日志//序列CRoosterStruct_SEQ_TASK_LOG m_SEQ_TASK_LOG;//TASK日志序列public:
#ifdef CTFC_RoosterStruct_H_SHM_DB
#define CTFC_RoosterStruct_H_WITH_DBtypedef CShmDB T_DB;
#endif#ifdef CTFC_RoosterStruct_H_MARIA_DB
#define CTFC_RoosterStruct_H_WITH_DBtypedef CMariaDB T_DB;
#endifprivate:
#ifdef CTFC_RoosterStruct_H_WITH_DBT_DB m_ShmDB;T_DB * pDB;
#endifpublic:
#ifdef CTFC_RoosterStruct_H_WITH_DB//返回内部数据库对象T_DB * getDB(){return pDB;}//直连初始化bool DBInit(char const * db = nullptr){
#ifdef CTFC_RoosterStruct_H_SHM_DBCShmActiveObjects * p;p = m_ShmDB.GetCShmActiveObjects();if (!p->isConnected() && !p->Attach(false))
#endif
#ifdef CTFC_RoosterStruct_H_MARIA_DBif(!m_ShmDB.Connect(db))
#endif{thelog << "CRoosterStruct连接失败" << ende;return false;}DEBUG_LOG << "CRoosterStruct连接成功" << endi;pDB = &m_ShmDB;m_RESOURCE_TYPE_D.Init(pDB);m_RESOURCE_USE_TYPE_D.Init(pDB);m_RESOURCE_D.Init(pDB);m_TASK_D.Init(pDB);m_TASK_RESOURCE_USE_D.Init(pDB);m_TASK_QUEUE.Init(pDB);m_TASK_LOG.Init(pDB);m_SEQ_TASK_LOG.Init(pDB);return true;}//直连断开bool DBUnInit(){
#ifdef CTFC_RoosterStruct_H_SHM_DBCShmActiveObjects * p;p = m_ShmDB.GetCShmActiveObjects();if (p->isConnected())p->Detach();
#endif
#ifdef CTFC_RoosterStruct_H_MARIA_DBpDB->Close();
#endifpDB = NULL;return true;}//直连创建所有数据库对象bool DBCreateAllDBObject(){//创建表if(!m_RESOURCE_TYPE_D.CreateTable())return false;if(!m_RESOURCE_USE_TYPE_D.CreateTable())return false;if(!m_RESOURCE_D.CreateTable())return false;if(!m_TASK_D.CreateTable())return false;if(!m_TASK_RESOURCE_USE_D.CreateTable())return false;if(!m_TASK_QUEUE.CreateTable())return false;if(!m_TASK_LOG.CreateTable())return false;//创建序列if(!m_SEQ_TASK_LOG.CreateSequence())return false;return true;}//直连显示所有数据库对象bool DBShowAllDBObject(){//显示表if(!m_RESOURCE_TYPE_D.Show())return false;if(!m_RESOURCE_USE_TYPE_D.Show())return false;if(!m_RESOURCE_D.Show())return false;if(!m_TASK_D.Show())return false;if(!m_TASK_RESOURCE_USE_D.Show())return false;if(!m_TASK_QUEUE.Show())return false;if(!m_TASK_LOG.Show())return false;//显示序列thelog << "sequence:" << endl << "-------------------------" << endl;theLog<< "SEQ_TASK_LOG " << m_SEQ_TASK_LOG.GetSequenceValue() << endl;theLog << "-------------------------" << endi;return true;}
#endif};
}
#endif

        这个文件看起来和普通手写的文件没有任何区别,除了它真的是用代码模板生成的。

        再来看看生成这个文件的模板_t_UniversalDB.h.ct是什么样的:

//_cc_C${SYS}.h 自动生成的代码
//
// Copyright (c) ct  All rights reserved.
// 版权所有 ct 保留所有权利
////警告:本文件由CT系统自动生成,不可手工修改#ifndef CTFC_${SYS}_H
#define CTFC_${SYS}_H 1//如果需要使用内存数据库直连功能,请在包含本头文件之前定义 CTFC_${SYS}_H_SHM_DB
//如果需要使用MariaDB功能,请在包含本头文件之前定义 CTFC_${SYS}_H_MARIA_DB
<%foreach table in ${tables}%>
#include "_cc_${SYS}_${table}.h"
<%endforeach%>
<%foreach sequence in sequences%>
#include "_cc_${SYS}_${sequence}.h"
<%endforeach%>using namespace ns_my_std;namespace ${NAMESPACE}
{class CShmDB_${SYS}{public://表<%foreach table in tables%>C${SYS}_${table} m_${table};//${table.comment}<%endforeach%>//序列<%foreach sequence in sequences%>C${SYS}_${sequence} m_${sequence};//${sequence.comment}<%endforeach%>public:
#ifdef CTFC_${SYS}_H_SHM_DB
#define CTFC_${SYS}_H_WITH_DBtypedef CShmDB T_DB;
#endif#ifdef CTFC_${SYS}_H_MARIA_DB
#define CTFC_${SYS}_H_WITH_DBtypedef CMariaDB T_DB;
#endifprivate:
#ifdef CTFC_${SYS}_H_WITH_DBT_DB m_ShmDB;T_DB * pDB;
#endifpublic:
#ifdef CTFC_${SYS}_H_WITH_DB//返回内部数据库对象T_DB * getDB(){return pDB;}//直连初始化bool DBInit(char const * db = nullptr){
#ifdef CTFC_${SYS}_H_SHM_DBCShmActiveObjects * p;p = m_ShmDB.GetCShmActiveObjects();if (!p->isConnected() && !p->Attach(false))
#endif
#ifdef CTFC_${SYS}_H_MARIA_DBif(!m_ShmDB.Connect(db))
#endif{thelog << "C${SYS}连接失败" << ende;return false;}DEBUG_LOG << "C${SYS}连接成功" << endi;pDB = &m_ShmDB;<%foreach table in tables%>m_${table}.Init(pDB);<%endforeach%><%foreach sequence in sequences%>m_${sequence}.Init(pDB);<%endforeach%>return true;}//直连断开bool DBUnInit(){
#ifdef CTFC_${SYS}_H_SHM_DBCShmActiveObjects * p;p = m_ShmDB.GetCShmActiveObjects();if (p->isConnected())p->Detach();
#endif
#ifdef CTFC_${SYS}_H_MARIA_DBpDB->Close();
#endifpDB = NULL;return true;}//直连创建所有数据库对象bool DBCreateAllDBObject(){//创建表<%foreach table in tables%>if(!m_${table}.CreateTable())return false;<%endforeach%>//创建序列<%foreach sequence in sequences%>if(!m_${sequence}.CreateSequence())return false;<%endforeach%>return true;}//直连显示所有数据库对象bool DBShowAllDBObject(){//显示表<%foreach table in tables%>if(!m_${table}.Show())return false;<%endforeach%>//显示序列thelog << "sequence:" << endl << "-------------------------" << endl;<%foreach sequence in sequences%>theLog<< "${sequence} " << m_${sequence}.GetSequenceValue() << endl;<%endforeach%>theLog << "-------------------------" << endi;return true;}
#endif};
}
#endif

        这就是一个代码模板编写的典型例子,用到了大量的循环处理和变量替换。看起来像asp?嗯,就是模仿asp啊。

三、如何创建模型

        下一篇将详细解释这个模型(原则上,除了最终生成的的是这个脚本生成器要求的对象结构外模型和脚本生成器并没有更多关联)。


(这里是结束,但不是整个系列的结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1035567.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WMware虚拟机配置静态IP

注意&#xff1a;如果是克隆的虚拟机&#xff0c;需要先重新生成mac地址&#xff0c;如下图所示 修改配置文件 &#xff1a;/etc/sysconfig/network-scripts/ifcfg-ens33 注意&#xff1a;1. BOOTPROTO设置为static 2.将下面的IPADDR地址替换为你实际要设置的ip地址 3.NAT模式…

【Gitea的介绍】

&#x1f525;博主&#xff1a;程序员不想YY啊&#x1f525; &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f4ab; &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 &#x1f308;希望本文对您有所裨益&#xff0c;如有…

【Linux】详解动静态库的制作和使用动静态库在系统中的配置步骤

一、库的作用 1、提高开发效率&#xff0c;让开发者所有的函数实现不用从零开始。 2、隐藏源代码。 库其实就是所有的.o文件用特定的方式进行打包形成一个文件&#xff0c;各个.o文件包含了源代码中的机器语言指令。 二、动态库和静态库的制作和使用 2.1、静态库的制作和使用…

25+web技术站点,事半功倍,总有一个值得got

前言 收集一些有用的网站&#xff0c;为自己用&#xff0c;也分享一下&#xff0c;仅此而已。 ECMA 国际组织 各种文案 Ecma-262 - ECMAScript 规范Ecma-402&#xff0c; -国际化 API 规范Ecma-404 - JSON 数据交换语法ECMA-419 - 嵌入式系统 API 规范ECMA-414 规定了和 ECM…

一个页面实现两个滚动条【前端】

一个页面实现两个滚动条【前端】 前言版权推荐一个页面实现两个滚动条最后 前言 2024-4-2 12:54:46 以下内容源自《【前端】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是https://jsss-1.blog.csdn.net …

前端试题2#记录

1、介绍以下CSS的盒子模型 盒子模型分为两种&#xff1a; &#xff08;1&#xff09;第一种是W3c标准的盒子模型&#xff08;标准盒模型&#xff09; width和height&#xff1a;内容的宽度、高度&#xff08;不是盒子的宽度、高度&#xff09;。padding&#xff1a;内边距。…

iOS网络抓包工具解析与比较:选用最适合你的工具

摘要 本文将深入探讨iOS平台上常用的网络抓包工具&#xff0c;包括Charles、克魔助手、Thor和Http Catcher&#xff0c;以及通过SSH连接进行抓包的方法。此外&#xff0c;还介绍了克魔开发助手作为iOS应用开发的辅助工具&#xff0c;提供的全方面性能监控和调试功能。 在iOS应…

【C++第三阶段】模板类模板通用数组实现案例

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 模板怎么使用模板函数模板注意事项普通函数与函数模板的区别普通函数与函数模板调用规则函数模板限制 类模板类模板语法类模板与函数模板区别类模板中成员函数创建时机类模板对象做函…

GitHub推送远程仓库详细教程

一、在远程新建一个仓库 二、在工作区初始化并提交到版本库 三、连接到远程仓库地址进行推送 四、推送到其他分支 4.1 新建其他分支 4.2 新建文件进行提交 4.3 将文件推送到其他分支 4.4 推送成功演示 4.5 连接远程跟踪分支&#xff0c;方便提交 4.6 直接push展示 五、其他 5…

【项目实践day10】WebSocket介绍及入门实践

WebSocket介绍 基于 TCP 的一种新的网络协议实现了浏览器与服务器全双工通信 浏览器和服务器只需要完成一次握手两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输 浏览器可以向服务器传输数据&#xff0c;服务器可以主动向浏览器传输数据&#xff0c;他们之间是…

C语言——字符串函数

一.前言 我们在日常写代码的过程中&#xff0c;经常会对字符串进行处理的过程。而在C语言中的<string.h>中&#xff0c;包含了众多字符串函数&#xff0c;我们可以借助这些字符串函数来对其进行各种操作。 二.strlen函数 strlen函数的作用是求出所传字符串的长度。该函…

BUU UPLOAD COURSE 1 文件包含

1.页面是一个文件上传的接口&#xff0c;尝试上传一句话木马&#xff0c;上传成功&#xff0c;但是文件后缀被重命名。 ​​2.因为文件名被重命名就想到了使用%00截断&#xff0c;但是不行。就陷入了死区&#xff0c;老是在想怎么去改后缀。 3.注意到参数是file而且内容是一个…

milvus knowhere源码编译测试

简介 Knowhere 是 Milvus 的核心向量执行引擎&#xff0c;集成了Faiss、Hnswlib和Annoy等多个向量相似度搜索库。 编译环境 操作系统: Ubuntu 22.04.4 gcc/g:11.4.0 cmake: 3.27.7 安装依赖 apt install build-essential libopenblas-dev libaio-dev python3-dev python…

分享几个可以免费使用的GPT网站吧

1. ChatGAI ChatGAI是一个界面简洁的AI平台&#xff0c;提供App和网页版&#xff0c;每日均有免费使用机会。 2. ChatGPT 本网站向大家开放了ChatGPT 3.5和4.0版本的免费体验&#xff0c;特别适合新用户。每天都有免费次数&#xff0c;响应迅速&#xff0c;注册便捷&#xff0…

前端小白的学习之路(webpack)

提示&#xff1a;webpack简介&#xff0c;nvm,npm配置环境,常用命令&#xff0c;基本web项目构建 目录 webpack 1.配置环境 1)node.js node常用命令 2)nvm nvm常用命令&#xff1a; 3)npm npm常用命令 2.构建简易web项目 1)创建目录 2)安装webpack依赖 3)配置 webpac…

Linux使用Docker部署Nacos结合cpolar实现公网访问内网注册中心管理界面

文章目录 1. Docker 运行Nacos2. 本地访问Nacos3. Linux安装Cpolar4. 配置Nacos UI界面公网地址5. 远程访问 Nacos UI界面6. 固定Nacos UI界面公网地址7. 固定地址访问Plik Nacos是阿里开放的一款中间件,也是一款服务注册中心&#xff0c;它主要提供三种功能&#xff1a;持久化…

【Vue3源码学习】— CH2.6 effect.ts:详解

effect.ts&#xff1a;详解 1. 理解activeEffect1.1 定义1.2 通过一个例子来说明这个过程a. 副作用函数的初始化b. 执行副作用函数前c. 访问state.countd. get拦截器中的track调用e. 修改state.count时的set拦截器f. trigger函数中的依赖重新执行 1.3 实战应用1.4 activeEffect…

国外媒体推广软文宣发:促进海外宣发新风尚,迈向国际舞台

大舍传媒http://www.dashemeijie.com 序言 伴随全球经济一体化发展趋向&#xff0c;越来越多的中国企业希望在国际舞台上表现自己的总体水平。而国外媒体软文发稿作为一种全新的海外宣传方式&#xff0c;正逐渐成为促进海外宣发新风尚的主要常用工具。接下来我们就探讨国外媒…

前端跨页面通信方案介绍

在浏览器中&#xff0c;我们可以同时打开多个Tab页&#xff0c;每个Tab页可以粗略理解为一个“独立”的运行环境&#xff0c;即使是全局对象也不会在多个Tab间共享。然而有些时候&#xff0c;我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。这就是本文说说…

vue源码解析——vue如何将template转换为render函数

Vue 将模板&#xff08;template&#xff09;转换为渲染函数&#xff08;render function&#xff09;是 Vue 编译器的核心功能&#xff0c;它是 Vue 实现响应式和虚拟 DOM 的关键步骤。在 Vue 中&#xff0c;模板&#xff08;template&#xff09;是开发者编写的类似 HTML 的代…