你敢信!贪吃蛇游戏居然能插入到富文本编辑器里!

image

所有的大人都曾经是小孩子,虽然,只有少数的人记得。 ——《小王子》

引言

突然想起来前段时间看过的对半同学写的贪吃蛇游戏,据说对半同学只花了一个小时就写出来了。

《canvas 300行代码实现一个贪吃蛇 》

当时我正躺在床上刷手机,看到对半同学的这篇文章,立马坐了起来,认真看完之后立马点了赞,并且评论了。

虽然这篇文章没有火起来,但并不影响这是一篇好文。

于是我在想

能不能把这个贪吃蛇游戏插入到编辑中呢?

大家在日常工作中有遇到往编辑器里插入什么奇葩内容呢?

欢迎在评论区讨论。

依然是插入自定义内容

不多啰嗦了,直接参考之前的文章:

《Quill富文本编辑器的实践》

按照以下四个步骤来就行:

  • 第一步:自定义工具栏按钮
  • 第二步:自定义Blot内容
  • 第三步:在Quill注册自定义Blot
  • 第四步:调用Quill的API插入自定义内容

第一步:自定义工具栏按钮

这个非常简单:

const TOOLBAR_CONFIG = [[{ header: ['1', '2', '3', false] }],['bold', 'italic', 'underline', 'link'],[{ list: 'ordered' }, { list: 'bullet' }],['clean'],['card', 'divider', 'emoji', 'file', 'tag'],['dragon', 'snake'], // 新增的
];

自定义工具栏按钮图标:

const snakeIcon = `<svg>...</svg>`;
const icons = Quill.import('ui/icons');
icons.snake = snakeIcon;

增加工具栏按钮事件:

const quill = new Quill('#editor', {theme: 'snow',modules: {toolbar: {container: TOOLBAR_CONFIG,handlers: {...// 增加一个空的事件snake(value): void {console.log('snake~~');},},}},
});

第二步:自定义Blot内容 SnakeBlot

不再啰嗦,参考之前的文章直接写就好:

《如何将龙插入到编辑器中? 》

《Quill富文本编辑器的实践》

snake.ts

import Quill from 'quill';
import GreedySnake from '../../shared/greedy-snake';const BlockEmbed = Quill.import('blots/block/embed');class SnakeBlot extends BlockEmbed {static blotName = 'snake';static tagName = 'canvas';static create(value): any {const node = super.create(value);const { id, width, height } = value;node.setAttribute('id', id || SnakeBlot.blotName);if (width !== undefined) {node.setAttribute('width', width);}if (height !== undefined) {node.setAttribute('height', height);}// 绘制贪吃蛇游戏的代码参考对半同学的文章:https://juejin.cn/post/6959789039566192654new GreedySnake(node).start();return node;}
}export default SnakeBlot;

绘制贪吃蛇

由于对半同学花一个小时写出来的代码实在非常优雅,忍不住将其代码贴出来了(侵删),文章源码来源于对半同学的文章:

canvas 300行代码实现一个贪吃蛇

greedy-snake.ts

// 大小为64 * 40
export default class GreedySnake {canvas;ctx;maxX;maxY;itemWidth;direction;speed;isStop;isOver;isStart;score;timer;j;canChange;grid;snake;food;// mask;// scoreDom;constructor(container) {this.canvas = typeof container === 'string' ? document.querySelector(container) : container;this.canvas.setAttribute('width', 640);this.canvas.setAttribute('height', 400);this.canvas.setAttribute('style', 'border: solid 2px #ddd');this.ctx = this.canvas.getContext('2d');this.maxX = 64;          // 最大行this.maxY = 40;          // 最大列this.itemWidth = 10;     // 每个点的大小this.direction = 'right'; // up down right left 方向this.speed = 150;        // ms 速度this.isStop = false;     // 是否暂停this.isOver = false;     // 是否结束this.isStart = false;    // 是否开始this.score = 0;          // 分数this.timer = null;       // 移动定时器this.j = 1;this.canChange = true;this.grid = new Array();// this.scoreDom = document.querySelector('#score');// this.mask = document.querySelector('#mask');for (let i = 0; i < this.maxX; i++) {for (let j = 0; j < this.maxY; j++) {this.grid.push([i, j]);}}this.drawGridLine();this.getDirection();document.addEventListener('keydown', (event) => {if (event.keyCode === 13) {if (!this.isStart) return;this.start();}});}// 开始start(): void {if (this.timer) {clearTimeout(this.timer);}if (!this.isStart) {this.isStart = true;}this.score = 0;this.speed = 150;this.isStop = false;this.isOver = false;this.direction = 'right';this.createSnake();this.createFood();this.draw();this.move();// this.mask.style.display = 'none';}// 创建蛇主体createSnake(): void {this.snake = [[4, 25],[3, 25],[2, 25],[1, 25],[0, 25]];}// 移动move(): void {if (this.isStop) {return;}let [x, y] = this.snake[0];switch (this.direction) {case 'left':x--;break;case 'right':x++;break;case 'up':y--;break;case 'down':y++;break;}// 如果下一步不是食物的位置if (x !== this.food[0] || y !== this.food[1]) {this.snake.pop();} else {this.createFood();}if (this.over([x, y])) {this.isOver = true;// this.mask.style.display = 'block';// this.mask.innerHTML = '结束';return;}if (this.completed()) {// this.mask.style.display = 'block';// this.mask.innerHTML = '恭喜您,游戏通关';return;}this.snake.unshift([x, y]);this.draw();this.canChange = true;this.timer = setTimeout(() => this.move(), this.speed);}// 暂停游戏stop(): void {if (this.isOver) {return;}this.isStop = true;// this.mask.style.display = 'block';// this.mask.innerHTML = '暂停';}// 继续游戏continue(): void {if (this.isOver) {return;}this.isStop = false;this.move();// this.mask.style.display = 'none';}getDirection(): void {// 上38 下40 左37 右39 不能往相反的方向走document.onkeydown = (e) => {// 在贪吃蛇移动的间隔内不能连续改变两次方向if (!this.canChange) {return;}switch (e.keyCode) {case 37:if (this.direction !== 'right') {this.direction = 'left';this.canChange = false;}break;case 38:if (this.direction !== 'down') {this.direction = 'up';this.canChange = false;}break;case 39:if (this.direction !== 'left') {this.direction = 'right';this.canChange = false;}break;case 40:if (this.direction !== 'up') {this.direction = 'down';this.canChange = false;}break;case 32:// 空格暂停与继续if (!this.isStop) {this.stop();} else {this.continue();}break;}};}createPos(): any {// tslint:disable-next-line: no-bitwiseconst [x, y] = this.grid[(Math.random() * this.grid.length) | 0];for (const item of this.snake) {if (item[0] === x && item[1] === y) {return this.createPos();}}// for (let i = 0; i < this.snake.length; i++) {//   if (this.snake[i][0] === x && this.snake[i][1] === y) {//     return this.createPos();//   }// }return [x, y];}// 生成食物createFood(): void {this.food = this.createPos();// 更新分数// this.scoreDom.innerHTML = 'Score: ' + this.score++;if (this.speed > 50) {this.speed--;}}// 结束over([x, y]): boolean {if (x < 0 || x >= this.maxX || y < 0 || y >= this.maxY) {return true;}if (this.snake.some(v => v[0] === x && v[1] === y)) {return true;}}// 完成completed(): boolean {if (this.snake.length === this.maxX * this.maxY) {return true;}}// 网格线drawGridLine(): void {for (let i = 1; i < this.maxY; i++) {this.ctx.moveTo(0, i * this.itemWidth);this.ctx.lineTo(this.canvas.width, i * this.itemWidth);}for (let i = 1; i < this.maxX; i++) {this.ctx.moveTo(i * this.itemWidth, 0);this.ctx.lineTo(i * this.itemWidth, this.canvas.height);}this.ctx.lineWidth = 1;this.ctx.strokeStyle = '#ddd';this.ctx.stroke();}// 绘制draw(): void {// 清空画布this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);this.drawGridLine();this.ctx.fillStyle = '#000';this.ctx.fillRect(this.food[0] * this.itemWidth + this.j,this.food[1] * this.itemWidth + this.j,this.itemWidth - this.j * 2,this.itemWidth - + this.j * 2);// tslint:disable-next-line: no-bitwisethis.j ^= 1;this.ctx.fillStyle = 'green';this.ctx.fillRect(this.snake[0][0] * this.itemWidth + 0.5,this.snake[0][1] * this.itemWidth + 0.5,this.itemWidth - 1,this.itemWidth - 1);this.ctx.fillStyle = 'red';for (let i = 1; i < this.snake.length; i++) {this.ctx.fillRect(this.snake[i][0] * this.itemWidth + 0.5,this.snake[i][1] * this.itemWidth + 0.5,this.itemWidth - 1,this.itemWidth - 1);}}
}

第三步:在Quill注册自定义Blot

有了 SnakeBlot,还需要将其注册到 Quill 中才能使用:

import SnakeBlot from './formats/snake';
Quill.register('formats/snake', SnakeBlot);

第四步:调用Quill的API插入自定义内容

调用完API就可以玩贪吃蛇游戏啦,开心到飞起!

const quill = new Quill('#editor', {theme: 'snow',modules: {toolbar: {container: TOOLBAR_CONFIG,handlers: {...snake(value): void {console.log('snake~~');const index = this.quill.getSelection().index;// 插入自定义内容this.quill.insertEmbed(index, 'snake', {id: 'canvas-snake',});},},}},
});

效果图:

贪吃蛇.gif

永远保持童心,保持对世界的好奇,你就是上帝带给这个世界最好的礼物。

祝曾经是小孩子的你儿童节快乐!

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

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

相关文章

数据结构——链式二叉树

前言&#xff1a;哈喽小伙伴们&#xff0c;上篇文章我们讲述了一个特殊的二叉树——使用数组实现的堆的基本知识之后呢&#xff0c;从这篇文章开始&#xff0c;我们就正式进入普通二叉树的介绍啦&#xff0c;二叉树真正的难点——递归&#xff0c;即将来临&#xff0c;小伙伴们…

unity旋转选中效果

代码和预制体 函数PlayAnim&#xff08;&#xff09;中的角度要根据按钮数量手动填好 using System; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options; using UnityEngine;// Token: 0x0200001B RID: 27 public class BtnParentScript : Base…

QT5.4.1无法打开文件

问题描述&#xff1a;起初是在QT代码中运行打开文件代码&#xff1a; QString gFilename QFileDialog::getOpenFileName(this,"open File",path,"*", nullptr,QFileDialog::DontUseNativeDialog);时&#xff0c;出现了堵塞情况&#xff0c;经过多次实验一…

海鹰数据虾皮:为Shopee卖家提供的完美数据分析工具

在如今的电子商务领域中&#xff0c;如何更好地了解市场动态、优化商品策略以提高运营效果成为了卖家们关注的重要问题。而海鹰数据&#xff08;Haiying Data&#xff09;作为一款专为Shopee平台设计的数据分析工具&#xff0c;为卖家们提供了市场趋势、商品分析、关键词优化、…

改善男性生理健康,缓解前列腺问题

前列腺是男性生殖系统中非常重要的一部分&#xff0c;它对男性的生理健康都着至关重要的作用。但是随着年龄的增长&#xff0c;前列腺问题也越来越普遍&#xff0c;给男性带来了很大的困扰。前列宝是Mission Hill推出的一款番茄红素多效复合胶囊&#xff0c;主要针对男性前列腺…

11 款顶级的免费 iPhone 数据恢复软件

iPhone 拥有巨大的存储容量。您可以在 iPhone 设备上存储图像、文档和视频等数据。有时&#xff0c;您的 iPhone 会发生许多意外事件&#xff0c;例如意外删除&#xff0c;从而导致数据丢失。这里有 11 个最好的免费 iPhone 数据恢复软件&#xff0c;您可以免费下载&#xff0c…

喜报!MIAOYUN入选成都高新区“瞪羚企业”

近日&#xff0c;成都高新区科技创新局公示了《2022年领先科技园区政策拟支持企业&#xff08;机构&#xff09;名单&#xff08;第二批次&#xff09;》&#xff0c;即最新一批的高新区“瞪羚企业”名单。成都元来云志科技有限公司&#xff08;简称“MIAOYUN”&#xff09;以其…

JVM 类加载机制(七)

1.加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化 ​ JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;下面我们就分别来看一下这五个过程。 1.1. 加载 ​ 加载是类加…

Spring Cloud Stream 4.0.4 rabbitmq 发送消息多function

使用 idea 创建 Springboot 项目 添加 Spring cloud stream 和 rabbitmq 依赖 pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchem…

学生信息管理系统

摘 要 学生成绩管理系统是典型的信息管理系统(MIS)&#xff0c;其开发主要包括后台数据库的建立和维护以及前端应用程序的开发两个方面。经过分析&#xff0c;我们使用Microsoft公司的C语言开发工具&#xff0c;将与C语言技术与数据库SQL2008相结合进行设计。首先&#xff0c;…

【多线程】线程的三种常见创建方式

文章目录 线程创建方式1——Thread线程创建方式2——Runnable线程创建方式2——匿名内部类线程创建方式3——Callable、FutureTask,带返回值 线程其实是程序中的一条执行路径。 那怎样的程序才是多线程程序呢&#xff1f; 例如12306网站就是支持多线程的&#xff0c;因为同时可…

一下午终于配好:如何用vs code连接远程主机jupyter server(notebook/lab)

因为教研室的机器有2060&#xff0c;笔记本只有集成显卡&#xff0c;虽然也可用浏览器访问&#xff0c;但是vs code不论从界面还是扩展功能来说&#xff0c;都有更好的编程体验&#xff0c;所以想通过vs code远程连接jupyter server。 要实现该需求总体需要三个步骤&#xff1…

Python推导式详细讲解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;推导式是一种简洁而强大的语法特性&#xff0c;可以用来创建列表、集合、字典等数据结构。本文将深入探讨Python中的三种推导式&#xff1a;列表推导式、集合推导式和字典推导式&#xff…

喜讯:麦田(苏州)医学科技有限公司立项项目获得2024年度浙江省医药卫生科技计划资助的公告

喜讯&#xff1a;麦田&#xff08;苏州&#xff09;医学科技有限公司立项项目获得2024年度浙江省医药卫生科技计划资助的公告 我们麦田&#xff08;苏州&#xff09;医学科技有限公司非常荣幸地宣布&#xff0c;由我们联合浙江省人民医院、杭州市红十字会医院、杭州师范大学共同…

Docker-多容器应用

一、概述 到目前为止&#xff0c;你一直在使用单个容器应用。但是&#xff0c;现在您将 MySQL 添加到 应用程序堆栈。经常会出现以下问题 - “MySQL将在哪里运行&#xff1f;将其安装在同一个 容器还是单独运行&#xff1f;一般来说&#xff0c;每个容器都应该做一件事&#x…

强化学习——简单解释

一、说明 最近 OpenAI 上关于 Q-star 的热议激起了我温习强化学习知识的兴趣。这是为强化学习 (RL) 新手提供的复习内容。 二、强化学习的定义 强化学习是人类和其他动物用来学习的学习类型。即&#xff0c;通过阅读房间来学习。&#xff08;从反馈中学习&#xff09;。让我解…

基于深度学习CRNN的水表读数识别系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着科技的不断发展&#xff0c;深度学习技术在各个领域都取得了显著的成果。其中&#xff0c;基于深度学习的图像识别技术在计算机视觉领域具有重要的应用价值。…

Linux环境搭建(Ubuntu22.04)+ 配置共享文件夹(Samba)

Linux开发环境准备 搭建Linux开发环境所需要的软件如下&#xff1a; VMware虚拟机&#xff1a;用于运行Linux操作系统的虚拟机软件之一&#xff0c;VMware下载安装在文章中不做说明&#xff0c;可自行百度谢谢Ubuntu光盘镜像&#xff1a;用于源代码编译&#xff0c;有闲置计算…

maven生命周期回顾

目录 文章目录 **目录**两种最常用打包方法&#xff1a;生命周期&#xff1a; 两种最常用打包方法&#xff1a; 1.先 clean&#xff0c;然后 package2.先 clean&#xff0c;然后install 生命周期&#xff1a; 根据maven生命周期&#xff0c;当你执行mvn install时&#xff0c…

大数据Hadoop-HDFS_架构、读写流程

大数据Hadoop-HDFS 基本系统架构 HDFS架构包含三个部分&#xff1a;NameNode&#xff0c;DataNode&#xff0c;Client。 NameNode&#xff1a;NameNode用于存储、生成文件系统的元数据。运行一个实例。 DataNode&#xff1a;DataNode用于存储实际的数据&#xff0c;将自己管理…