0


前端——原生Selection api操作选中文本 样式、取消样式(解决标签的无限嵌套问题)

文章目录

⭐前言

大家好,我是yma16,本文分享 前端——Selection api操作选中文本 样式、取消样式(解决标签的无限嵌套问题)
Selection API

Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。

node系列往期文章
node_windows环境变量配置
node_npm发布包
linux_配置node
node_nvm安装配置
node笔记_http服务搭建(渲染html、json)
node笔记_读文件
node笔记_写文件
node笔记_连接mysql实现crud
node笔记_formidable实现前后端联调的文件上传
node笔记_koa框架介绍
node_koa路由
node_生成目录
node_读写excel
node笔记_读取目录的文件
node笔记——调用免费qq的smtp发送html格式邮箱
node实战——搭建带swagger接口文档的后端koa项目(node后端就业储备知识)
node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)
node实战——koa给邮件发送验证码并缓存到redis服务(node后端储备知识)

koa系列项目文章
前端vite+vue3结合后端node+koa——实现代码模板展示平台(支持模糊搜索+分页查询)
node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查
node+vue3+mysql前后分离开发范式——实现视频文件上传并渲染

koa-vue性能监控到封装sdk系列文章
性能监控系统搭建——node_koa实现性能监控数据上报(第一章)
性能监控系统搭建——vue3实现性能监控数据展示(第二章)
性能监控计算——封装带性能计算并上报的npm包(第三章)
canvas系列文章
web canvas系列——快速入门上手绘制二维空间点、线、面
webgl canvas系列——快速加背景、抠图、加水印并下载图片
webgl canvas系列——animation中基本旋转、平移、缩放(模拟冒泡排序过程)
前端vue系列文章
vue3 + fastapi 实现选择目录所有文件自定义上传到服务器
前端vue2、vue3去掉url路由“ # ”号——nginx配置
csdn新星计划vue3+ts+antd赛道——利用inscode搭建vue3(ts)+antd前端模板
认识vite_vue3 初始化项目到打包
python_selenuim获取csdn新星赛道选手所在城市用echarts地图显示
让大模型分析csdn文章质量 —— 提取csdn博客评论在文心一言分析评论区内容
前端vue3——html2canvas给网站截图生成宣传海报
前端——html拖拽原理
前端 富文本编辑器原理——从javascript、html、css开始入门
前端老古董execCommand——操作 选中文本 样式
前端如何在30秒内实现吸管拾色器?

⭐Selection获取选区

通过document.getSelection()获取选中的选区
通过onselectionchange 监听 选区变化

  document.onselectionchange=function(){
    console.log('New selection made');
    selection = document.getSelection();
    console.log('selection', selection);
    console.log('type', selection.type);
    console.log('content', selection.toString())};

在控制台打印选区的内容
selection-log

✏️EyeDropper拾色器api给选区加颜色

使用EyeDropper对象获取唤起拾色器api

if(!window.EyeDropper){
      message.warning("你的浏览器不支持 EyeDropper API")return;}const eyeDropper =newEyeDropper();

    eyeDropper
      .open().then((result)=>{
        console.log('result.sRGBHex',result.sRGBHex)}).catch((e)=>{
        console.error(e)});

✏️selection insertNode 插入html字符串并渲染

使用insertNode api

functioninsertHTML(value){const sel = document.getSelection();if(sel && sel.rangeCount){const node = document.createElement('div');const range = sel.getRangeAt(0);
    range.deleteContents();if(value){
      node.innerHTML = value;}elseif(value){
      node.appendChild(value);}Array.prototype.slice.call(node.childNodes).forEach(nd=>{
      range.insertNode(nd);});

    sel.removeAllRanges();
    sel.addRange(range);}}

添加成功
add-color
查看div下的span节点
在这里插入图片描述

✏️selection insertNode清空内容再写入内容再清除样式

先删除选区再添加选区

functionclearStyle(){const sel = document.getSelection();const text=sel.toString()
  console.log('text',text)if(sel && sel.rangeCount){const node = document.createElement('span');
    node.value=text
    const range = sel.getRangeAt(0);
    range.deleteContents();
    node.innerHTML=text

    Array.prototype.slice.call(node.childNodes).forEach(nd=>{
      console.log('nd',nd)
      range.insertNode(nd);});

    sel.removeAllRanges();
    sel.addRange(range);}}

带来的问题:遗留空节点标签
del-style

✏️selection insertNode带来的空节点和冗余父级节点问题

使用selection 插入 节点和样式带来,如下无限嵌套问题

<spanstyle='red'><spanstyle='red'><spanstyle='red'>修改文字</span></span></span>

空节点问题

<spanstyle='red'></span><spanstyle='red'>修改文字</span>

思路:

  1. 每次修改选区时刻进行整体向下内容校验,合并嵌套的标签,删除无效标签(父节点查找子节点)
  2. 每次修改选区时刻进行从选区内容往父级节点查找内容校验,合并嵌套的标签,删除无效标签(子节点查找父节点)

整体修改内容清除冗余嵌套标签
逻辑实现(参考)

/**
     * 
     * @param node 合并节点样式
     * @returns {*}
     */functionmergeTag(node){
        console.log('node',node)
        console.log('node.textContent',node.textContent)if(node.nodeType === Node.ELEMENT_NODE){const nodeStyle=node.getAttribute('style')// 如果是 span 标签,递归处理其子节点for(let child of node.childNodes){
                console.log('child',child)
                console.log('node.innerText',node.textContent)
                console.log('child.innerText',child.textContent)if(child.textContent ===node.textContent ){// 内容一样的子节点忽略 获取styleconst childStyle=child.getAttribute('style')if(childStyle){const nodeStyleConfig={}if(nodeStyle){
                            nodeStyle.split(';').map(item=>{const key=item.split(':')[0]const value=item.split(':')[1]if(key){
                                    nodeStyleConfig[key]=value
                                }})}// 子节点样式覆盖
                        childStyle.split(';').map(item=>{const key=item.split(':')[0]const value=item.split(':')[1]if(key){
                                nodeStyleConfig[key]=value
                            }})
                        console.log('nodeStyleConfig',nodeStyleConfig)// console.log('nodeStyleConfig.entries()',nodeStyleConfig.entries())let style=[]
                        Object.keys(nodeStyleConfig).forEach(key=>{
                            style.push(key+':'+nodeStyleConfig[key])})
                        console.log('style',style)
                        node.setAttribute('style',style.join(';'))// 合并 nodeStyle 和  childStyle (childStyle 优先级高)}//  节点变成文本 创建一个新的文本节点并替换它const textNode = document.createTextNode(child.textContent);
                    child.parentNode.replaceChild(textNode, child);}elseif(!child.textContent){// 删除 空节点
                    child.remove()}else{mergeTag(child);}}}return node
    }

⭐结束

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

sence

👍 点赞,是我创作的动力!

⭐️ 收藏,是我努力的方向!

✏️ 评论,是我进步的财富!

💖 最后,感谢你的阅读!

标签: 1024程序员节

本文转载自: https://blog.csdn.net/qq_38870145/article/details/143199359
版权归原作者 yma16 所有, 如有侵权,请联系我们删除。

“前端——原生Selection api操作选中文本 样式、取消样式(解决标签的无限嵌套问题)”的评论:

还没有评论