详解C#之WinForm版利用RichTextBox 制作文本编辑器【附源码】

news2024/11/19 3:23:33

在Windows应用程序开发中,刚刚介绍了WPF版的利用RichTextBox实现文本编辑器,今天继续推出WinForm版的利用RichTextBox实现文本编辑器。本文利用一个简单的小例子,简述如何在WinForm开发中,利用RichTextBox开发文本编辑器,以及RichTextBox的用法,仅供学习分享使用,如有不足之处,还请指正。

图片

Windows窗体中的RichTextBox控件用于显示,输入和操作格式化的文本,RichTextBox除了拥有TextBox控件的所有功能外,还可以显示字体,颜色,链接,从文件中读取和加载图像,以及查找指定的字符。RichTextBox控件通常用于提供类似字体处理程序(如Microsoft Word)的文本操作和显示功能。RichTextBox控件可以显示滚动条,且默认根据需要进行显示。

涉及知识点

在本示例中,涉及知识点如下所示:

  • SelectionFont 获取或设置当前选定文本或插入点的字体。

  • FontStyle 指定应用到文本的字形信息。

  • SelectionAlignment  获取或设置应用到当前选定内容或插入点的对齐方式。

  • SelectionIndent 获取或设置所选内容开始行的缩进距离(以像素为单位)。

  • SelectionCharOffset 获取或设置控件中的文本是显示在基线上、作为上标还是作为基线下方的下标。

  • SelectionColor 获取或设置当前选定文本或插入点的文本颜色。

  • SelectionBackColor   获取或设置在 System.Windows.Forms.RichTextBox 控件中选中文本时文本的颜色。

  • SelectionBullet 获取或设置一个值,通过该值指示项目符号样式是否应用到当前选定内容或插入点。

  • Clipboard Paste 粘贴指定剪贴板格式的剪贴板内容【插入图片时使用】。

  • Find 在对搜索应用特定选项的情况下,在 System.Windows.Forms.RichTextBox 控件的文本中搜索位于控件内特定位置的字符串。

核心代码

1. 定义接口

为了规范和统一,定义实现样式接口IRichFormat,如下所示:

namespace DemoRichText.Model
{
    /// <summary>
    /// 富文本框格式
    /// </summary>
    public interface IRichFormat
    {
        void SetFormat(RichTextBox rtbInfo);
    }
}

2. 实现样式基类

定义一个接口的默认实现基类BaseRichFormat,此基类是抽象类,如下所示:

namespace DemoRichText.Model
{
    public abstract class BaseRichFormat : IRichFormat
    {
        public abstract void SetFormat(RichTextBox rtbInfo);
    }
}

3. 具体实现方法

具体到每一个功能样式设置,均继承自BaseRichFormat,如下所示:

namespace DemoRichText.Model
{
    public class DefaultRickFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {

        }
    }

    /// <summary>
    /// 加粗格式
    /// </summary>
    public class BoldRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            Font oldFont = rtbInfo.SelectionFont;
            Font newFont;
            if (oldFont.Bold)
            {
                newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Bold);//支持位于运算
            }
            else
            {
                newFont = new Font(oldFont, oldFont.Style | FontStyle.Bold);
            }
            rtbInfo.SelectionFont = newFont;
        }
    }

    /// <summary>
    /// 斜体
    /// </summary>
    public class ItalicRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            Font oldFont = rtbInfo.SelectionFont;
            Font newFont;
            if (oldFont.Italic)
            {
                newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Italic);
            }
            else
            {
                newFont = new Font(oldFont, oldFont.Style | FontStyle.Italic);
            }
            rtbInfo.SelectionFont = newFont;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 下划线
    /// </summary>
    public class UnderLineRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            Font oldFont = rtbInfo.SelectionFont;
            Font newFont;
            if (oldFont.Underline)
            {
                newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Underline);
            }
            else
            {
                newFont = new Font(oldFont, oldFont.Style | FontStyle.Underline);
            }
            rtbInfo.SelectionFont = newFont;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 删除线
    /// </summary>
    public class StrikeLineRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            Font oldFont = rtbInfo.SelectionFont;
            Font newFont;
            if (oldFont.Underline)
            {
                newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Strikeout);
            }
            else
            {
                newFont = new Font(oldFont, oldFont.Style | FontStyle.Strikeout);
            }
            rtbInfo.SelectionFont = newFont;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 左对齐
    /// </summary>
    public class LeftRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            rtbInfo.SelectionAlignment = HorizontalAlignment.Left;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 居中对齐
    /// </summary>
    public class CenterRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            if (rtbInfo.SelectionAlignment == HorizontalAlignment.Center)
            {
                rtbInfo.SelectionAlignment = HorizontalAlignment.Left;
            }
            else
            {
                rtbInfo.SelectionAlignment = HorizontalAlignment.Center;
            }

            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 右对齐
    /// </summary>
    public class RightRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            if (rtbInfo.SelectionAlignment == HorizontalAlignment.Right)
            {
                rtbInfo.SelectionAlignment = HorizontalAlignment.Left;
            }
            else
            {
                rtbInfo.SelectionAlignment = HorizontalAlignment.Right;
            }

            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 缩进对齐
    /// </summary>
    public class IndentRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            //每次以10个像素进行缩进
            rtbInfo.SelectionIndent = rtbInfo.SelectionIndent + 10;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 缩进对齐
    /// </summary>
    public class OutIndentRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            //每次以10个像素进行缩进
            rtbInfo.SelectionIndent = rtbInfo.SelectionIndent - 10;
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 下标
    /// </summary>
    public class SubScriptRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            if (rtbInfo.SelectionCharOffset < 0)
            {
                rtbInfo.SelectionCharOffset = 0;
            }
            else {
                rtbInfo.SelectionCharOffset = -5;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 上标
    /// </summary>
    public class SuperScriptRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            if (rtbInfo.SelectionCharOffset > 0)
            {
                rtbInfo.SelectionCharOffset = 0;
            }
            else {
                rtbInfo.SelectionCharOffset = 5;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 字体
    /// </summary>
    public class FontRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            FontDialog f = new FontDialog();
            if (f.ShowDialog() == DialogResult.OK)
            {
                FontFamily family = f.Font.FontFamily;
                rtbInfo.SelectionFont = new Font(family, rtbInfo.SelectionFont.Size, rtbInfo.SelectionFont.Style);
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 文本颜色
    /// </summary>
    public class ForeColorRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            ColorDialog f = new ColorDialog();
            if (f.ShowDialog() == DialogResult.OK)
            {

                rtbInfo.SelectionColor = f.Color;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 文本背景颜色
    /// </summary>
    public class BgColorRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            ColorDialog f = new ColorDialog();
            if (f.ShowDialog() == DialogResult.OK)
            {

                rtbInfo.SelectionBackColor = f.Color;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// UL列表,项目符号样式
    /// </summary>
    public class UlRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            if (rtbInfo.SelectionBullet)
            {
                rtbInfo.SelectionBullet = false;
            }
            else {
                rtbInfo.SelectionBullet = true;
                rtbInfo.BulletIndent = 10;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 图片插入
    /// </summary>
    public class PicRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            OpenFileDialog o = new OpenFileDialog();
            o.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
            o.Title = "请选择图片";
            o.Filter = "jpeg|*.jpeg|jpg|*.jpg|png|*.png|gif|*.gif";
            if (o.ShowDialog() == DialogResult.OK) {
                string fileName = o.FileName;
                try
                {
                   Image bmp = Image.FromFile(fileName);
                   Clipboard.SetDataObject(bmp);

                    DataFormats.Format dataFormat = DataFormats.GetFormat(DataFormats.Bitmap);
                    if (rtbInfo.CanPaste(dataFormat))
                    {
                        rtbInfo.Paste(dataFormat);
                    }

                }
                catch (Exception exc)
                {
                    MessageBox.Show("图片插入失败。" + exc.Message, "提示",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 删除
    /// </summary>
    public class DelRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            rtbInfo.SelectedText = "";
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 查找
    /// </summary>
    public class SearchRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            string find = rtbInfo.Tag.ToString();
            int index=  rtbInfo.Find(find, 0,RichTextBoxFinds.None);
            int startPos = index;
            int nextIndex = 0;
            while (nextIndex != startPos)//循环查找字符串,并用蓝色加粗12号Times New Roman标记之
            {
                rtbInfo.SelectionStart = index;
                rtbInfo.SelectionLength = find.Length;
                rtbInfo.SelectionColor = Color.Blue;
                rtbInfo.SelectionFont = new Font("Times New Roman", (float)12, FontStyle.Bold);
                rtbInfo.Focus();
                nextIndex = rtbInfo.Find(find, index + find.Length, RichTextBoxFinds.None);
                if (nextIndex == -1)//若查到文件末尾,则充值nextIndex为初始位置的值,使其达到初始位置,顺利结束循环,否则会有异常。
                {
                    nextIndex = startPos;
                }
                index = nextIndex;
            }
            rtbInfo.Focus();
        }
    }

    /// <summary>
    /// 打印
    /// </summary>
    public class PrintRichFormat : BaseRichFormat
    {
        private RichTextBox richTextbox;

        public override void SetFormat(RichTextBox rtbInfo)
        {
            this.richTextbox = rtbInfo;
            PrintDocument pd = new PrintDocument();
            pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
            // 打印文档
            pd.Print();
        }

        private void pd_PrintPage(object sender, PrintPageEventArgs ev)
        {
            //ev.Graphics.DrawString(richTextbox.Text);
            //ev.HasMorePages = true;
        }
    }

    /// <summary>
    /// 字体大小
    /// </summary>
    public class FontSizeRichFormat : BaseRichFormat
    {
        public override void SetFormat(RichTextBox rtbInfo)
        {
            string fontSize = rtbInfo.Tag.ToString();
            float fsize = 0.0f;
            if (float.TryParse(fontSize, out fsize)) {
                rtbInfo.SelectionFont = new Font(rtbInfo.Font.FontFamily, fsize, rtbInfo.SelectionFont.Style);
            }
            rtbInfo.Focus();
        }
    }
}

4. 实现工厂模式

因为所有实现都基于同一个接口,所以进一步封装样式设置的实现类,如下所示:

​​​​​​​

namespace DemoRichText.Model
{
    public class RichFormatFactory
    {
        public static IRichFormat CreateRichFormat(BTNType btnType)
        {
            IRichFormat richFormat;
            switch (btnType)
            {
                case BTNType.Bold:
                    richFormat = new BoldRichFormat();
                    break;
                case BTNType.BGColor:
                    richFormat = new BgColorRichFormat();
                    break;
                case BTNType.Center:
                    richFormat = new CenterRichFormat();
                    break;
                case BTNType.Del:
                    richFormat = new DelRichFormat();
                    break;
                case BTNType.Font:
                    richFormat = new FontRichFormat();
                    break;
                case BTNType.ForeColor:
                    richFormat = new ForeColorRichFormat();
                    break;
                case BTNType.FontSize:
                    richFormat = new FontSizeRichFormat();
                    break;
                case BTNType.Indent:
                    richFormat = new IndentRichFormat();
                    break;
                case BTNType.Italic:
                    richFormat = new ItalicRichFormat();
                    break;
                case BTNType.Left:
                    richFormat = new LeftRichFormat();
                    break;
                case BTNType.OutIndent:
                    richFormat = new OutIndentRichFormat();
                    break;
                case BTNType.Pic:
                    richFormat = new PicRichFormat();
                    break;
                case BTNType.Print:
                    richFormat = new PrintRichFormat();
                    break;
                case BTNType.Right:
                    richFormat = new RightRichFormat();
                    break;
                case BTNType.Search:
                    richFormat = new SearchRichFormat();
                    break;
                case BTNType.StrikeLine:
                    richFormat = new StrikeLineRichFormat();
                    break;
                case BTNType.SubScript:
                    richFormat = new SubScriptRichFormat();
                    break;
                case BTNType.SuperScript:
                    richFormat = new SuperScriptRichFormat();
                    break;
                case BTNType.Ul:
                    richFormat = new UlRichFormat();
                    break;
                case BTNType.UnderLine:
                    richFormat = new UnderLineRichFormat();
                    break;
                default:
                    richFormat = new DefaultRickFormat();
                    break;

            }
            return richFormat;
        }
    }
}

5. UI页面代码

由于实现了代码封装,所有页面代码较少,如下所示:

namespace DemoRichText
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }


        public void btnButtonClick(object sender, EventArgs e) {
            Button btn = (Button)sender;
            BTNType btnType;
            if (Enum.TryParse<BTNType>(btn.Tag.ToString(), out btnType)) {
                if (btnType == BTNType.Search) {
                    if (!string.IsNullOrEmpty(this.txtSearch.Text.Trim()))
                    {
                        this.rtbInfo.Tag = this.txtSearch.Text.Trim();
                    }
                    else {
                        return;
                    }

                }
                IRichFormat richFomat = RichFormatFactory.CreateRichFormat(btnType);
                richFomat.SetFormat(this.rtbInfo);
            }
        }

        private void combFontSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            float fsize = 12.0f;
            if (combFontSize.SelectedIndex > -1) {
                if (float.TryParse(combFontSize.SelectedItem.ToString(), out fsize)) {
                    rtbInfo.Tag = fsize.ToString();
                    IRichFormat richFomat = RichFormatFactory.CreateRichFormat(BTNType.FontSize);
                    richFomat.SetFormat(this.rtbInfo);
                }
                return;
            }
        }
    }
}

示例效果图

设置文本对应的格式,具体如下所示:

图片

源码下载

关于源码下载,可关注公众号,并回复关键字WINRICH即可,如下所示:

图片

以上就是【详解C#之WinForm版利用RichTextBox 制作文本编辑器】的全部内容,关于更多详细内容,可参考官方文档。希望能够一起学习,共同进步。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据传输的同步技术包含哪些?如何高效安全传输数据?

在数字化时代&#xff0c;数据传输的同步技术对于确保信息的一致性和通信质量至关重要。本文将探讨数据传输同步技术的种类、如何实现高效安全的数据传输&#xff0c;以及企业在数据迁移中常用的几种方式。最后&#xff0c;我们将重点介绍镭速大数据迁移工具的优势。 数据传输同…

论文:万卡集群训练大模型(by字节跳动)

论文&#xff1a;MegaScale: Scaling Large Language Model Training to More Than 10,000 GPUs&#xff08;https://arxiv.org/pdf/2402.15627.pdf&#xff09; 结论&#xff1a; 1&#xff0c;字节跳动提出了万卡集群大模型训练架构MegaScale&#xff0c;并在12288个GPU上训练…

118页Vue面试题总结,就是这么简单

问&#xff1a;BFC 与 IFC 区别 BFC 是块级格式上下文&#xff0c;IFC 是行内格式上下文&#xff1a; 内部的 Box 会水平放置水平的间距由 margin&#xff0c;padding&#xff0c;border 决定 问&#xff1a;BFC会与float元素相互覆盖吗&#xff1f;为什么&#xff1f;举例说…

人事档案转出需要注意哪些方面

人事档案转出是指将员工的人事档案从一个部门、公司或组织转移到另一个部门、公司或组织的过程。这个过程需要注意以下几个方面&#xff1a; 1.法律合规&#xff1a;在进行人事档案转出前&#xff0c;要确保遵守相关的法律法规和公司内部规定。例如&#xff0c;要确保有合法的授…

web组态--新一代全流程低代码物联网平台

先上图&#xff0c;实际完成效果&#xff1a; 1.添加应用图纸 登录by组态后台&#xff1a;http://www.byzt.net:90 ​ 点击组态管理-画面管理&#xff0c;先新建一个组态画面&#xff0c;填写画面名称&#xff0c;保存&#xff0c;进入组态画面。 ​ 选择画面管理&#xff…

Linux——网络基础

计算机网络背景 网络发展 独立模式: 计算机之间相互独立 在早期的时候&#xff0c;计算机之间是相互独立的&#xff0c;此时如果多个计算机要协同完成某种业务&#xff0c;那么就只能等一台计算机处理完后再将数据传递给下一台计算机&#xff0c;然后下一台计算机再进行相应…

《 前端 vs. 后端:挑战与机遇的对决》

前言 前端开发和后端开发是构建网站、应用程序和其他软件的两个主要方面。它们各自负责不同的任务和功能。 前端开发: 定义:前端开发是指构建用户直接与之交互的网站或应用程序的过程。前端开发主要关注于用户界面和用户体验。技术栈:前端开发通常涉及使用 HTML、CSS 和 Ja…

基于带时间窗口的电动汽车路由问题的精英对立学习的多群PSO(2022)

英文&#xff1a;Multi-swarm PSO based on Elite Opposite Learning on Electric Vehicle Routing Problem with Time Window 摘要&#xff1a; 带时间窗口的电动汽车路由问题&#xff08;EVRPTW&#xff09;是交通领域的一个新问题&#xff0c;用传统的精确求解方法很难解决…

电商网站数据采集配合socks5代理ip怎么进行?

电商网站数据采集是一项重要的任务&#xff0c;可以帮助企业了解市场需求、竞品分析、用户行为等方面。在进行电商网站数据采集时&#xff0c;有时需要配合使用socks5代理IP。本文将介绍如何进行电商网站数据采集配合socks5代理IP。 一、代理IP介绍 代理IP是一种可以隐藏用户真…

大模型笔记:RAG(Retrieval Augmented Generation,检索增强生成)

1 大模型知识更新的困境 大模型的知识更新是很困难的&#xff0c;主要原因在于&#xff1a; 训练数据集固定,一旦训练完成就很难再通过继续训练来更新其知识参数量巨大,随时进行fine-tuning需要消耗大量的资源&#xff0c;并且需要相当长的时间LLM的知识是编码在数百亿个参数中…

95页初级前端模块笔记分享,开发web前端学习

简历 首先肯定是要准备一份自己的简历&#xff0c;简历经常是给面试官的第一印象。 简历一般包括个人基础信息&#xff0c;专业技能&#xff0c;项目经验&#xff0c;其他模块。 个人基础信息模块就不说了&#xff0c;太基础。 **专业 戳这里领取完整开源项目&#xff1a;【…

UE5 C++ TPS开发 学习记录(九

p20 首先我们现在有一个多人游戏的系统类MultiplayerSessionsSubsystem 在这个系统内提供了很多会话系统的接口SessionInterface 当现在我们有一些SessionInterfaceDelegates的委托,这个委托的来源是SessionInterface,所以我们使用的委托可以接收到来自SessionInterface的消息(…

自动化测试环境搭建--Linux内网环境【实操经验】

环境信息 Python版本3.6.8 Jenkins版本2.346.3 Allure版本 2.13.2 环境准备 一、Python需要安装库 allure-pytest (2.13.2) pytest (7.0.1) jsonpath (0.82.2) pytest-html (3.2.0) pytest-ordering (0.6) …

工具函数模板题(蓝桥杯 C++ 代码 注解)

目录 一、Vector容器&#xff1a; 二、Queue队列 三、Map映射 四、题目&#xff08;快递分拣 vector&#xff09;&#xff1a; 代码&#xff1a; 五、题目&#xff08;CLZ银行问题 queue&#xff09;&#xff1a; 代码&#xff1a; 六、题目&#xff08;费里的语言 map&…

基于springboot+vue的酒店管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

xss.haozi.me:0x0A

https://www.segmentfault.com.haozi.me/j.js

猜数字小游戏

目录 java&#xff1a; c语言&#xff1a; java编写&#xff1a; 首先我们要获取随机数 java帮我们写好了一个类叫Random&#xff0c;这个类就可以生成一个随机数 那我们该如何使用Random类呢&#xff1f; 1、导包———Random这个类在哪呢&#xff08;导包必须出现在类定义…

算法学习02:高精度(c++)

算法学习02&#xff1a;高精度&#xff08;c&#xff09; 文章目录 算法学习02&#xff1a;高精度&#xff08;c&#xff09;前言一、高精度1.高 高2.高 - 高3.高 * 低4.高 / 低 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff1a; 一、高精度 1.高 高 add函数…

Android使用陀螺仪

Android使用陀螺仪 陀螺仪基础运用与理解 在Android应用中使用陀螺仪可以帮助实现各种功能&#xff0c;比如游戏控制、虚拟现实体验、运动追踪等。以下是使用Android陀螺仪的基本步骤&#xff1a; 获取传感器服务&#xff1a; 首先&#xff0c;需要获取设备上的陀螺仪传感器服…

vue3基础教程(2)——创建vue3+vite项目

博主个人微信小程序已经上线&#xff1a;【中二少年工具箱】。欢迎搜索试用 正文开始 专栏简介1. 前言2.node版本检测3.创建vue项目 专栏简介 本系列文章由浅入深&#xff0c;从基础知识到实战开发&#xff0c;非常适合入门同学。 零基础读者也能成功由本系列文章入门&#x…