基于 uni-app 和 Vue3 开发的汉字书写练习应用
基于 uni-app 和 Vue3 开发的汉字书写练习应用
前言
本文介绍了如何使用 uni-app + Vue3 + uview-plus 开发一个汉字书写练习应用。该应用支持笔画演示、书写练习、进度保存等功能,可以帮助用户学习汉字书写。
在线演示
演示地址: http://demo.xiyueta.com/case/web20250222/#/pagesa/xiehaizi/index
测试账号: demo
测试密码: 123456
使用效果
写汉字

技术栈
- uni-app:跨平台开发框架
- Vue3:前端框架
- uview-plus:UI组件库
- Canvas:绘图API
- localStorage:本地存储
功能特点
- 笔画演示:动态展示汉字笔画书写过程
- 书写练习:支持手写输入和笔画匹配
- 关卡系统:支持多个汉字练习,自动保存进度
- 界面美观:采用现代化UI设计,交互流畅
开发过程
1. 项目初始化
首先创建 uni-app 项目并集成 uview-plus:
# 创建项目
vue create -p dcloudio/uni-preset-vue hanzi-practice# 安装依赖
npm install uview-plus
2. 页面结构设计
页面主要分为三个部分:
- 顶部导航:显示当前关卡和拼音
- 中间画布:用于展示和练习汉字
- 底部按钮:控制功能切换
3. 核心功能实现
3.1 笔画演示功能
使用 Canvas 绘制汉字,通过定时器实现动画效果:
const startStrokeAnimation = () => {let currentStroke = 0let currentPoint = 0const animateStroke = () => {if (!isAnimating.value) returnif (currentStroke < currentHanziData.strokes.length) {const median = currentHanziData.medians[currentStroke]if (currentPoint < median.length) {drawPartialStroke(currentStroke, currentPoint)currentPoint++animationTimer = setTimeout(animateStroke, animationSpeed)} else {// 完成当前笔画,进入下一个drawCompleteStroke(currentStroke)currentStroke++currentPoint = 0if (currentStroke < currentHanziData.strokes.length) {animationTimer = setTimeout(animateStroke, 500)}}}}animateStroke()
}
3.2 书写练习功能
实现手写输入和笔画匹配:
const checkUserStroke = () => {if (tempStroke.length < 2) returnconst currentMedian = currentHanziData.medians[currentStrokeIndex.value]const transformedUserStroke = transformUserStroke(tempStroke)const isMatch = simpleStrokeMatch(transformedUserStroke, currentMedian)if (isMatch) {currentStrokeIndex.value++if (currentStrokeIndex.value < currentHanziData.strokes.length) {drawHanziForPractice()} else {showCompleteCharacter()}}
}
3.3 进度保存功能
使用 localStorage 保存练习进度:
const STORAGE_KEY = 'CURRENT_LEVEL'const saveCurrentLevel = (level) => {try {uni.setStorageSync(STORAGE_KEY, level)} catch (e) {console.error('保存关卡失败:', e)}
}const restoreLevel = () => {try {const savedLevel = uni.getStorageSync(STORAGE_KEY)if (savedLevel) {currentLevel.value = parseInt(savedLevel)return true}} catch (e) {console.error('恢复关卡失败:', e)}return false
}
遇到的问题和解决方案
1. Canvas 坐标转换问题
问题:用户手写输入的坐标系与汉字数据的坐标系不一致。
解决方案:实现坐标转换函数:
const transformUserStroke = (userStroke) => {const centerX = canvasWidth.value / 2const centerY = canvasHeight.value / 2 - 35const size = Math.min(canvasWidth.value, canvasHeight.value) * 0.9return userStroke.map(point => ({x: ((point.x - centerX) / (size / 1024)) + 512,y: 1024 - (((point.y - centerY) / (size / 1024)) + 512)}))
}
2. 笔画动画控制问题
问题:动画状态管理复杂,需要处理暂停、继续等状态。
解决方案:使用 Vue3 的 ref 实现响应式状态管理:
const isAnimating = ref(false)const toggleStrokeAnimation = () => {if (isAnimating.value) {clearTimeout(animationTimer)animationTimer = nullisAnimating.value = falsedrawHanzi(currentHanziData)} else {isAnimating.value = truestartStrokeAnimation()}
}
3. 界面适配问题
问题:不同设备上画布大小和按钮布局需要适配。
解决方案:使用 rpx 单位和 flex 布局:
.hanzi-canvas {width: calc(100% - 60rpx);height: 60vh;margin: 30rpx auto;
}.bottom-section {width: calc(100% - 60rpx);margin: 0 auto;.control-buttons {display: flex;justify-content: space-between;gap: 30rpx;}
}
开发技巧
-
组件化设计:将功能模块拆分为独立组件,提高代码复用性
-
状态管理:使用 Vue3 的 Composition API 管理状态
-
性能优化:
- 使用 requestAnimationFrame 优化动画
- 合理使用 Canvas 缓存
- 防抖处理用户输入
-
用户体验:
- 添加过渡动画
- 提供清晰的视觉反馈
- 保存用户进度
总结
本项目展示了如何使用现代前端技术栈开发一个实用的教育类应用。通过合理的架构设计和性能优化,实现了流畅的用户体验。项目中的许多技术点和解决方案都可以应用到其他同类项目中。
参考资料
- uni-app 官方文档
- Vue3 官方文档
- uview-plus 组件库
- Canvas API 参考
作者信息
如果本文章对您有所帮助,欢迎交流和探讨技术问题。
QQ: 313801120
更多文章: www.xiyueta.com
希望能一起成长,共同探索更多开发技巧!
相关文章:
基于 uni-app 和 Vue3 开发的汉字书写练习应用
基于 uni-app 和 Vue3 开发的汉字书写练习应用 前言 本文介绍了如何使用 uni-app Vue3 uview-plus 开发一个汉字书写练习应用。该应用支持笔画演示、书写练习、进度保存等功能,可以帮助用户学习汉字书写。 在线演示 演示地址: http://demo.xiyueta.com/case/w…...
每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet
本文重点 ResNet大名鼎鼎,它是由何恺明团队设计的,它获取了2015年ImageNet冠军,它很好的解决了当神经网络层数过多出现的难以训练的问题,它创造性的设计了跳跃连接的方式,使得卷积神经网络的层数出现了大幅度提升,设置可以达到上千层,可以说resnet对于网络模型的设计具…...
electron + vue3 + vite 主进程到渲染进程的单向通信
用示例讲解下主进程到渲染进程的单向通信 初始版本项目结构可参考项目:https://github.com/ylpxzx/electron-forge-project/tree/init_project 主进程到渲染进程(单向) 以Electron官方文档给出的”主进程主动触发动作,发送内容给渲…...
《白帽子讲 Web 安全》之身份认证
目录 引言 一、概述 二、密码安全性 三、认证方式 (一)HTTP 认证 (二)表单登录 (三)客户端证书 (四)一次性密码(OTP) (五)多因…...
postgrel
首先按照惯例,肯定是需要对PostgreSQL数据库进行一系列信息收集的,常用的命令有以下这些:-- 版本信息select version();show server_version;select pg_read_file(PG_VERSION, 0, 200);-- 数字版本信息包括小版号SHOW server_version_num;SEL…...
Java基础——java8+新特性——方法引用(::)
1. 什么是方法引用? 定义:Java 8 引入的语法糖,用于 简化 Lambda 表达式,直接引用已有的方法。 符号:使用 :: 双冒号操作符。 本质:将方法作为函数式接口的实例传。 2. 方法引用的四种类型 类型 语法 …...
基于SpringBoot的商城管理系统(源码+部署教程)
运行环境 数据库:MySql 编译器:Intellij IDEA 前端运行环境:node.js v12.13.0 JAVA版本:JDK 1.8 主要功能 基于Springboot的商城管理系统包含管理端和用户端两个部分,主要功能有: 管理端 首页商品列…...
uniapp实现的个人中心页面(仿小红书)
采用 uniapp 实现的一款仿小红书个人中心页面模板,支持vue2、vue3, 同时适配H5、小程序等多端多应用。 简约美观大方 可到插件市场下载尝试: https://ext.dcloud.net.cn/plugin?id22516 示例...
K8s面试题总结(十一)
1.如何优化docker镜像的大小? 使用多阶段构建(multi-stage build)选择更小的基础镜像(如alpine)减少镜像层数,合并RUN命令 2.请解释Docker中的网络模式(如bridge,host,none) Bridgeÿ…...
用CMake编译glfw进行OpenGL配置,在Visual Studio上运行
Visual Studio的下载 Visual Studio 2022 C 编程环境 GLFW库安装 GLFW官网地址 GLFW官网地址:https://www.glfw.org下载相应版本,如下图: CMake软件进行编译安装 下载CMake 下载的如果是源码包,需要下载CMake软件进行编译安装…...
仿12306项目(4)
基本预定车票功能的开发 对于乘客购票来说,需要有每一个车次的余票信息,展示给乘客,供乘客选择,因此首个功能是余票的初始化,之后是余票查询,这两个都是控台端。对于会员端的购票,需要有余票查询…...
【GPT入门】第9课 思维树概念与原理
【GPT入门】第9课 思维树概念与原理 1.思维树概念与原理2. 算24游戏的方法 1.思维树概念与原理 思维树(Tree of Thought,ToT )是一种大模型推理框架,旨在解决更加复杂的多步骤推理任务,让大模型能够探索多种可能的解决…...
uniapp登录用户名在其他页面都能响应
使用全局变量 1、在APP.vue中定义一个全局变量,然后在需要的地方引用它; <script>export default {onLaunch: function() {console.log(App Launch)this.globalData { userInfo: {} };},onShow: function() {console.log(App Show)},onHide: fu…...
一周热点-OpenAI 推出了 GPT-4.5,这可能是其最后一个非推理模型
在人工智能领域,大型语言模型一直是研究的热点。OpenAI 的 GPT 系列模型在自然语言处理方面取得了显著成就。GPT-4.5 是 OpenAI 在这一领域的又一力作,它在多个方面进行了升级和优化。 1 新模型的出现 GPT-4.5 目前作为研究预览版发布。与 OpenAI 最近的 o1 和 o3 模型不同,…...
Linux基础--用户管理
目录 查看用户 使用命令: id 创建用户 使用命令: useradd 编辑 为用户设置密码 使用命令: passwd 编辑 删除用户 使用命令: userdel 创建用户组 使用命令: groupadd 删除用户组 使用命令: groupdel 用户设置 使用命令: usermod 将用户从组中去除 使用…...
软件测试的基础入门(二)
文章目录 一、软件(开发)的生命周期什么是生命周期软件(开发)的生命周期需求分析计划设计编码测试运行维护 二、常见的开发模型瀑布模型流程优点缺点适应的场景 螺旋模型流程优点缺点适应的场景 增量模型和迭代模型流程适应的场景…...
【SpringMVC】深入解析@ RequestMapping 注解的概念及使用和 MVC 介绍
Spring Web MVC入门 1. Spring Web MVC 什么是 Spring Web MVC? MVC官方文档介绍 Spring Web MVC是Spring框架中的一个用来做网站开发的部分,它是基于Servlet技术的。 虽然它的正式名字叫“Spring Web MVC”,但大家一般都简称它“SpringMVC”…...
YOLOv8 自定义目标检测
一、引言 YOLOv8 不仅支持预训练模型的推理,还允许用户将其应用于自定义对象检测。本文将详细介绍如何使用 YOLOv8 训练一个新的模型,并在自定义数据集上进行对象检测。 二、数据集准备 1. 数据集格式 YOLOv8 支持多种数据集格式,包括 CO…...
抓包分析工具介绍
什么是抓包分析工具? 抓包分析工具,也称为网络数据包嗅探器或协议分析器,用于捕获和检查网络上传输的数据包。这些数据包包含了网络通信的详细信息,例如请求的资源、服务器的响应、HTTP 头信息、传输的数据内容等等。通过分析这些…...
计算机毕业设计SpringBoot+Vue.js爱心捐赠项目推荐系统 慈善大数据(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
