文字添加样式以及鼠标插入显示样式(类office)

文字添加样式

思路:为每一个字添加一个span标签,然后通过js添加css,可能部分代码不需要可删除

代码:

const fontSet = (key, val) => {
      //key:css样式名  val:样式值
    const editableDiv = document.getElementById('editableDiv');
    const range = window.getSelection().getRangeAt(0);

    const selectedText = range.toString();
    if (selectedText.length === 0) {
      return;
    }
    // 创建一个文档片段来存储每个字符的新span元素
    const fragment = document.createDocumentFragment();
    // 遍历选中的文本中的所有文本节点
    const textNodes = [];
    (function getTextNodes(node) {
      if (node.nodeType === Node.TEXT_NODE) {
        textNodes.push(node);
      } else {
        for (let i = 0; i < node.childNodes.length; i++) {
          getTextNodes(node.childNodes[i]);
        }
      }
    })(range.cloneContents());
    // 为选中文本中的每个字符创建新的span元素,并设置样式
    for (const textNode of textNodes) {
      const parentElement = textNode.parentNode;
      // console.log(parentElement.style, 'parentElement');
      const hasParentElement = parentElement && parentElement.nodeType === Node.ELEMENT_NODE;
      const originalStyles = hasParentElement ? window.getComputedStyle(parentElement) : null;
      for (const char of textNode.textContent) {
        let newSpan;
        // 如果当前字符已经被包含在一个单独的span元素中
        if (textNode.parentNode.tagName === 'SPAN' && textNode.textContent.length === 1) {
          newSpan = textNode.parentNode;
          newSpan.style.removeProperty(key);
        } else {
          newSpan = document.createElement('span');
          // 如果有父元素标签,将原始样式复制到新的span元素
          newSpan.textContent = char; // 将新创建的span元素的文本内容设置为当前字符
        }
        // 应用新样式
        newSpan.style[key] = val;
        newSpan.style.display = 'inline-block';
        newSpan.style.userSelect = 'text';
        newSpan.textContent = char; // 将新创建的span元素的文本内容设置为当前字符
        fragment.appendChild(newSpan);
      }
    }
    // 将选中的文本替换为新的span元素
    range.deleteContents();
    range.insertNode(fragment);
    // 更新数据和视图
    function removeEmptyTags(element) {
      const childNodes = element.childNodes;
      for (let i = 0; i < childNodes.length; i++) {
        const child = childNodes[i];

        // 如果子元素是一个元素节点
        if (child.nodeType === 1) {
          // 检查是否为空或只包含空白字符
          if (/^\s*$/.test(child.innerHTML)) {
            // 删除空元素
            element.removeChild(child);
            // 更新循环索引
            i--;
          } else {
            // 递归处理子元素的子元素
            removeEmptyTags(child);
          }
        }
      }
    }
    // 调用函数,删除 editableDiv 中的空标签
    const editableDivContent = document.getElementById('editableDiv');
    removeEmptyTags(editableDivContent);
    window.getSelection().removeAllRanges();
  };

滑选

以上是添加样式效果

文字样式回显

思路:给想回显的标签添加点击事件绑定方法,获取到插入点前一个字的style,然后给编辑传值回显

代码:

getTextBeforeCursor = (node, position) => {
    // if (node.nodeType === Node.TEXT_NODE) {
    //   return node.nodeValue.substring(0, position);
    // }

    // let textBeforeCursor = '';
    // for (let i = 0; i < position; i++) {
    //   textBeforeCursor += node.childNodes[i].textContent;
    // }
    // return textBeforeCursor;
    if (node.nodeType === Node.TEXT_NODE) {
      return position > 0 ? node.nodeValue.substring(position - 1, position) : '';
    }

    let textBeforeCursor = '';
    for (let i = 0; i < position; i++) {
      textBeforeCursor += node.childNodes[i].textContent;
    }
    return textBeforeCursor.slice(-1);
  };
  Divchange = value => {
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const cursorPosition = range.startOffset;
    const node = range.startContainer;
    const textBeforeCursor = this.getTextBeforeCursor(node, cursorPosition);
    let element = node;
    while (element.nodeType !== Node.ELEMENT_NODE) {
      element = element.parentNode;
    }
    const computedStyle = window.getComputedStyle(element);
    const backgroundColor = computedStyle.getPropertyValue('background-color');
    const fontSize = computedStyle.getPropertyValue('font-size');
    const color = computedStyle.getPropertyValue('color');
    const fontFamily = computedStyle.getPropertyValue('font-family');
    const bold = computedStyle.getPropertyValue('font-weight');
    const italic = computedStyle.getPropertyValue('font-style');
    const textDecoration = computedStyle.getPropertyValue('text-decoration-line');
    const textDecorations = computedStyle.getPropertyValue('text-decoration-line');
    const verticalAlign = computedStyle.getPropertyValue('vertical-align');
    sessionStorage.setItem('verticalAlign', verticalAlign == 'super' ? 'super' : '');
    sessionStorage.setItem('verticalAligns', verticalAlign == 'sub' ? 'sub' : '');
    sessionStorage.setItem('bold', bold == '700' ? 'bolder' : '');
    sessionStorage.setItem('italic', italic == 'italic' ? 'italic' : '');
    sessionStorage.setItem('textDecoration', textDecoration == 'line-through' ? 'line-through' : '');
    sessionStorage.setItem('textDecorations', textDecorations == 'underline' ? 'underline' : '');
    sessionStorage.setItem('fontFamily', fontFamily);
    sessionStorage.setItem('backgroundColor', backgroundColor);
    sessionStorage.setItem('fontSize', fontSize);
    sessionStorage.setItem('color', color);
  };

效果:

回显

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值