前端 富文本编辑器原理——从javascript、html、css开始入门

news2024/10/6 5:54:52

文章目录

    • ⭐前言
    • ⭐html的contenteditable属性
      • 💖 输入的光标位置(浏览器获取selection)
        • ⭐使用Selection.toString () 返回指定的文本
        • ⭐getRangeAt 获取指定索引范围
      • 💖 修改光标位置
      • 💖 设置选取range
    • ⭐总结
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于前端 富文本编辑器原理——从javascript、html、css开始。
富文本编辑器
富文本编辑器是指具有格式化文本和图像编辑功能的文本编辑器

参考文档:https://w3c.github.io/selection-api/#abstract

⭐html的contenteditable属性

全局属性 contenteditable 是一个枚举属性,表示元素是否可被用户编辑。如果可以,浏览器会修改元素的组件以允许编辑。

  • contenteditable boolean (false | true) 默认false
    简单理解,加上contenteditable ,html可以编辑具有input 输入的基本功能,所见即所得。
    例:
    html demo 标签配置contenteditable
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>富文本编辑器</title>
	</head>
	<style>
		blockquote {
		  background: #eee;
		  border-radius: 5px;
		  margin: 16px 0;
		}
		
		blockquote p {
		  padding: 15px;
		}
		
		cite {
		  margin: 16px 32px;
		  font-weight: bold;
		}
		
		blockquote p::before {
		  content: '\201C';
		}
		
		blockquote p::after {
		  content: '\201D';
		}
		
		[contenteditable='true'] {
		  caret-color: red;
		}

	</style>
	<body>
		<blockquote contenteditable="true">
		  <p>Edit this content to add your own quote</p>
		</blockquote>
		
		<cite contenteditable="true">-- Write your own name here</cite>

	</body>
</html>

效果如下,可以输入编辑html元素:
rich-text

💖 输入的光标位置(浏览器获取selection)

getSelection() method
GetSelection ()方法返回一个 Selection 对象,该对象表示用户选择的文本范围或插入符号的当前位置。

⭐使用Selection.toString () 返回指定的文本

例:

<body>
	<blockquote contenteditable="true">
	  <p>Edit this content to add your own quote</p>
	</blockquote>
	
	<cite contenteditable="true">-- Write your own name here</cite>
	<button onclick="printSelection()">console.log(getSelection)</button>

</body>
<script type="text/javascript">
	const printSelection=()=>{
		const selection=window.getSelection()
		console.log('selection',selection)
		console.log('selection.toString()',selection.toString())
	}
</script>

效果如下:
selection.toString

⭐getRangeAt 获取指定索引范围

函数接受一个索引值
返回,其中
结束的索引值,endOffset
开始的索引值,startOffset
效果如下图:
getRangeAt

💖 修改光标位置

调用 setStart() 和 setEnd() 方法,来修改一个光标的位置或拖蓝范围
Range.setStart()
Range.setStart() 方法用于设置 Range的开始位置。

如果起始节点类型是 Text、Comment 或 CDATASection之一,那么 startOffset 指的是从起始节点算起字符的偏移量。对于其他 Node 类型节点,startOffset 是指从起始结点开始算起子节点的偏移量。

如果设置的起始位点在结束点之下(在文档中的位置),将会导致选区折叠,起始点和结束点都会被设置为指定的起始位置。
startNode
startNode 用于设定 Range的起始位置。

startOffset
必须为不小于 0 的整数。表示从startNode的开始位置算起的偏移量。
Range.setEnd()
Range.setEnd()
方法用于设置 Range的结束位置。

如果结束节点类型是 Text、Comment 或 CDATASection之一,那么 endOffset 指的是从结束节点算起字符的偏移量。对于其他 Node 类型节点,endOffset 是指从结束结点开始算起子节点的偏移量。

如果设置的结束点在起始点之上(在文档中的位置),将会导致选区折叠,起始点和结束点都会被设置为指定的结束位置。
endNode
endNode用于设定 Range的结束位置。

endOffset
必须为不小于 0 的整数。表示从endNode的结束位置算起的偏移量。
语法

range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);

例:
点击不失去焦点跳转开始和结束,避免失去焦点使用preventDefault

<body>
	<blockquote contenteditable="true">
		<p>Edit this content to add your own quote</p>
	</blockquote>

	<cite contenteditable="true">-- Write your own name here</cite>
	<button onclick="printSelection()">console.log(getSelection)</button>
	<button id='start-id'>jumpt start</button>
	<button id='end-id'>jumpt end</button>


</body>
<script type="text/javascript">
	function printSelection() {
		const selection = window.getSelection()
		console.log('selection', selection)
		console.log('selection.toString()', selection.toString())
		console.log('selection.getRangeAt(0)', selection.getRangeAt(0))
	}

	function jumpStart() {
		let range = window.getSelection().getRangeAt(0);
		let textEle = range.commonAncestorContainer;
		range.setStart(range.startContainer, 0);
		range.setEnd(range.startContainer, 0);
	}

	function jumpEnd() {
		let range = window.getSelection().getRangeAt(0);
		let textEle = range.commonAncestorContainer;
		range.setStart(range.startContainer, textEle.length);
		range.setEnd(range.endContainer, textEle.length);
	}
	window.onload = function() {
		document.getElementById('start-id').addEventListener('click', function(e) {
			jumpStart()
		})
		document.getElementById('start-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})
		
		document.getElementById('end-id').addEventListener('click', function(e) {
			jumpEnd()
		})
		document.getElementById('end-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})
	}
</script>

效果如下图:
riche-editor-positon

💖 设置选取range

Selection.addRange()
概述
向选区(Selection)中添加一个区域(Range)。

语法

sel.addRange(range)

例子:
失去焦点之后恢复选区

<body>
	<blockquote contenteditable="true">
		<p>Edit this content to add your own quote</p>
		<b>yma16</b>
	</blockquote>

	<cite contenteditable="true">-- Write your own name here</cite>
	<br>
	<button id='print-id'>console.log(getSelection)</button>
	<br>
	<br>
	<button id='start-id'>jump start</button>
	<button id='end-id'>jump end</button>
	<button id='focus-id'>focus content</button>


</body>
<script type="text/javascript">
	const config = {
		selection: null
	}

	function printSelection() {
		const selection = window.getSelection()

		range = document.getSelection().getRangeAt(0).cloneRange();
		config.cloneRange = range;
		console.log('selection', selection)
		// console.log('selection.toString()', selection.toString())
		// console.log('selection.getRangeAt(0)', selection.getRangeAt(0))
	}

	function jumpStart() {
		let range = window.getSelection().getRangeAt(0);
		let textEle = range.commonAncestorContainer;
		range.setStart(range.startContainer, 0);
		range.setEnd(range.startContainer, 0);
		range = document.getSelection().getRangeAt(0).cloneRange();
		config.cloneRange = range;
	}

	function jumpEnd() {
		let range = window.getSelection().getRangeAt(0);
		let textEle = range.commonAncestorContainer;
		range.setStart(range.startContainer, textEle.length);
		range.setEnd(range.endContainer, textEle.length);
		range = document.getSelection().getRangeAt(textEle.length).cloneRange();
		config.cloneRange = range;
	}

	function focusContent() {
		document.getSelection().removeAllRanges(); //把没用的Ranges删除
		console.log('config.cloneRange',config.cloneRange)
		document.getSelection().addRange(config.cloneRange); //恢复Range
	}
	window.onload = function() {
		document.getElementById('print-id').addEventListener('click', function(e) {
			printSelection()
		})
		document.getElementById('print-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})
		document.getElementById('start-id').addEventListener('click', function(e) {
			jumpStart()
		})
		document.getElementById('start-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})

		document.getElementById('end-id').addEventListener('click', function(e) {
			jumpEnd()
		})
		document.getElementById('end-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})
		document.getElementById('focus-id').addEventListener('click', function(e) {
			focusContent()
		})
		document.getElementById('focus-id').addEventListener('mousedown', function(e) {
			e.preventDefault()
		})
	}
</script>

效果如下:
focus-content

⭐总结

Contenteditable属性
Contenteditable是一种HTML属性,用于指定页面中的元素是否可以编辑。以下是Contenteditable的总结:

  1. Contenteditable属性可以应用于HTML元素上,如div、span、p、h1等等。

  2. 当Contenteditable属性设置为true时,用户可以编辑元素内的文本、图像等内容。

  3. Contenteditable属性的取值包括true和false,分别表示可编辑和不可编辑。

  4. Contenteditable属性可以通过JavaScript来动态修改。

  5. Contenteditable属性的兼容性很好,支持大多数现代浏览器。

  6. 虽然Contenteditable属性很方便,但也存在一些潜在的安全问题,因此应该谨慎使用。

富文本编辑器

富文本编辑器是一种允许用户编辑带有样式和格式的文本的编辑器。它与普通文本编辑器的区别在于,它允许用户使用各种字体、颜色、大小、加粗、斜体、下划线、超链接、图片等来设计和呈现文本内容。其原理主要包括以下几个方面:

  • DOM操作:富文本编辑器通过操作DOM树来实现文本样式和格式的改变。当用户在编辑器中输入或选择文本时,编辑器会将文本转换为DOM节点,并将节点添加到DOM树中。通过对DOM节点的增删改查,实现对文本样式和格式的修改操作。

  • 事件监听:通常情况下,富文本编辑器会监听用户的输入事件、鼠标点击事件和键盘事件等,以便及时捕捉用户的操作并做出相应的反应。

  • 样式和格式化:富文本编辑器通常内置了样式和格式化工具,比如字体、颜色、大小、加粗、斜体、下划线、超链接等,可以通过这些工具来控制文本的样式和格式。

  • 插件和组件:富文本编辑器可以通过插件和组件来扩展其功能,比如图片上传组件、表格插件、代码高亮插件等,可以让编辑器满足更多的需求。

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
scene

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 感谢你的阅读!

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

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

相关文章

私有云盘:lamp部署nextcloud+高可用集群

目录 一、实验准备&#xff1a; 二、配置mariadb主从复制 三台主机下载mariadb 1&#xff09;主的操作 2&#xff09;从的操作 3&#xff09;测试数据是否同步 三、配置nfs让web服务挂载 1、安装 2、配置nfs服务器 3、配置web服务的httpd 4、测试 四、web 服务器 配…

Linux——指令初识

Linux下基本指令 前言一、 ls 指令二、 pwd命令三、cd 指令四、 touch指令五、mkdir指令六、rmdir指令 && rm 指令七、man指令八、cp指令九、mv指令十、cat指令十一、.more指令十二、less指令十三、head指令十四、tail指令总结 前言 linux的学习开始啦&#xff01; 今…

MyBatisPlus(十二)排序查询:orderBy

说明 排序查询&#xff0c;对应SQL语句中的 orderBy 语句&#xff0c;对查询结果按照指定字段排序。 升序&#xff1a;orderByAsc /*** 查询用户列表&#xff0c; 查询条件&#xff1a;按照 年龄 升序排列*/Testvoid orderByAsc() {LambdaQueryWrapper<User> wrapper …

OpenCV实现人脸检测(Haar特征)

学习目标 原理 实现 import cv2 as cv print(cv.__file__) 路径&#xff1a;E:\Anaconda3\envs\test_py3.6\Lib\site-packages\cv2\data 代码实现 import cv2 as cv import matplotlib.pyplot as plt from pylab import mplmpl.rcParams[font.sans-serif] [SimHei] #1&#x…

小程序中如何开启分销

小程序共享微信生态&#xff0c;商家可以通过小程序来快速扩大自己的销售渠道&#xff0c;其中一个非常受重要的功能就是分销。通过开启分销功能&#xff0c;商家可以让更多的人参与到销售中来&#xff0c;从而提高销售额。那么&#xff0c;在小程序中如何开启设置分销呢&#…

【Blender实景合成】会跳舞的神里绫华

效果预览 本文将介绍Blender用于实景合成的工作流程。 先看效果&#xff1a; 神里绫华爬上了我的办公桌 模型和动作资源准备 角色模型 本次主要使用的是原神游戏中&#xff0c;神里绫华的角色模型&#xff0c;该模型米哈游在模之屋网站上进行开源。 下载地址&#xff1a;ht…

不同数据类型在单片机内存中占多少字节?

文章目录 前言一、不同编译器二、C51* 指针型 三、sizeof结构体联合体 前言 在C语言中&#xff0c;数据类型指的是用于声明不同类型的变量或者函数的一个广泛的系统。变量的类型决定了变量存储占用的空间 一、不同编译器 类型16位编译器大小32位编译器大小64位编译器大小char…

1801_codesys产品主样本了解

全部学习汇总&#xff1a; GreyZhang/g_codesys: some codesys learning notes (github.com) 有些技术、学术的成长&#xff0c;氛围也是很重要的。我觉得工业控制&#xff0c;德国做得算是世界上很突出的。而这个巴伐利亚&#xff0c;更是突出中的佼佼者了。从这里的介绍看&am…

React核心原理与实际开发

学习目标 React是啥&#xff1f; 官方定义&#xff1a;将前端请求获取到的数据渲染为HTML视图的JavaScript库。 一、React入门 1、React项目创建 直接创建react&#xff0c;使用初始化会创建package.json npm init -y再安装 2、React基本使用 使用纯JS创建ReactDOM&#…

C语言数据结构2 1.2 算法

算法的基本概念 算法的定义 算法是对特定问题求解步骤的一种描述&#xff0c;它是指定的有限序列&#xff0c;其中的每条指令表示一个或多个操作。 例、 算法的特性 &#xff08;5个&#xff09; 1.有穷性 一个算法总在执行有穷步之后结束&#xff0c;且每一步都可以在有穷…

医疗器械标准目录汇编2022版共178页(文中附下载链接!)

为便于更好地应用医疗器械标准&#xff0c;国家药监局医疗器械标准管理中心组织对现行1851项医疗器械国家和行业标准按技术领域&#xff0c;编排形成《医疗器械标准目录汇编&#xff08;2022版&#xff09;》 该目录汇编分为通用技术领域和专业技术领域两大类&#xff0c;通用…

计算机网络 第三章数据链路层

文章目录 1、数据链路层概述 1、数据链路层概述

C语言:选择+编程(每日一练Day9)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;自除数 思路一&#xff1a; 题二&#xff1a;除自身以外数组的乘积 思路二&#xff1a; 本人实力有限可能对…

2.2.3 vim操作合集

1 vim VIM 是 Linux 系统上一款文本编辑器,学习 VIM 最好的文档,应该是阅读学习 VIM 的帮助文档,可以使用本地的帮助文件(vim--->:help),或者使用在线帮助文档。同时针对vim的使用,相应的相书籍也很多,如下 2 vim操作模式 命令模式:默认模式,该模式下可以移动光标…

ChatGPT付费创作系统V2.3.4独立版 +WEB端+ H5端 + 小程序最新前端

人类小徐提供的GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序&#xff0c;是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。当前全民热议ChatGPT&#xff0c;流量超级大&#xff0c;引流不要太简单&#xff01;一键下单即可拥有自己的GPT&#xff0…

LVGL_基础控件checkbox

LVGL_基础控件checkbox 1、创建checkbox /* 创建一个 checkbox 部件(对象) */ lv_obj_t * cb lv_checkbox_create(lv_scr_act()); // 创建一个 switch 部件(对象),他的父对象是活动屏幕对象 lv_checkbox_set_text(cb, "100ASK LVGL Tutorial" LV_SYMBOL_PLAY);…

qml保姆级教程四:按钮组件

&#x1f482; 个人主页:pp不会算法v &#x1f91f; 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 QML系列教程 QML教程一&#xff1a;布局组件 文章目录 AbstractButton…

汽车类、TPS7B8225QDGNRQ1、TPS7B8233EPWPRQ1、TPS7B8601QKVURQ1 40V、低压降 (LDO) 线性稳压器

一、TPS7B82-Q1 汽车类 300mA、高压、超低 IQ 低压降稳压器 &#xff08;介绍&#xff09;在汽车电池连接应用中&#xff0c;低静态电流 (IQ) 对于省电和延长电池寿命而言至关重要。对于始终开启的系统&#xff0c;必须要实现超低 IQ。 TPS7B82-Q1 是一款旨在在 3V 至 40V&…

Java毕业设计 SpringBoot 网上体育商城系统 商城系统

Java毕业设计 SpringBoot 网上体育商城系统 商城系统 SpringBoot 网上体育商城系统 功能介绍 首页 图片轮播 搜索 用户登录注册 商品信息 商品分类 商品详情 收藏 评论 添加到购物车 立即购买 购物车 确认下单 公告信息 留言反馈 个人中心 修改个人信息 我的订单 退款 我的地…

地图资源下载工具2.0

一、简介 地图资源工具是一款用于GIS数据下载的工具&#xff0c;用于GIS数据矢量、遥感数据的查询、下载及浏览。下载数据包括&#xff1a;哨兵&#xff08;Sentinel&#xff09;系列&#xff0c;LANDSAT系列&#xff0c;MODIS系列、ASTER系列、GOES系列、OPENSTREETMAP数据…