自己动手实现简易的div可编辑富文本框及按下tab键后增加4个空格功能

需求分析

最近需要制作一个简单的用户评论输入框,在网上找了一些富文本输入框,但是它们的功能太多,不适合自己的需求,于是决定自己动手实现一个简易的富文本输入框。

第一步:

想要实现富文本输入框并不是难事,在<div>标签内加入   contenteditable="true" ,这个div元素就可以编辑了,而且它的innerhtml 就是保留格式的html文本。

第二步:

只需要写一些css代码给div元素设计一些简单的样式,就可以让输入框变得美观。

实现按下tab键后增加四个空格的功能:

在不写额外代码的情况下,按下tab键,光标会离开编辑框,这是默认行为。所以需要监听按下tab的事件,在处理函数中取消浏览器的默认行为。

然后要想在光标处按下tab键,插入四个空格,就需要了解浏览器的光标对象。

在浏览器中,如果我们选中一片区域,就是看到的变蓝色的区域,这块区域是一个selection对象,selection在ff和chrome浏览器可以直接用 window.getSelection()获取,在HTML里面,selection只有一个的,它是有开始和结束的。现在在页面上随意选中一些元素,按F12,在console 中输入window.getSelection(); 就可以看到这个selection对象的全部成员。



其中anchorNode (baseNode)是选择区域的开始节点,focusNode (extendNode)是选择区域的结束节点,注意: 这里的开始表示按下鼠标的位置,结束指的是放开鼠标的位置,anchoNode不一定在focusNode的前面,因为有的区域可能是从后往前选的。

anchorOffset 返回一个数字,其表示的是选区起点在 anchorNode 中的位置偏移量。

focusOffset 返回一个数字,其表示的是选区终点在 focusNode 中的位置偏移量。

isCollapsed 返回一个布尔值,用于判断选区的起始点和终点是否在同一个位置。

rangeCount 返回该选区所包含的连续范围的数量。

从type可以看到selection的种类其实是range对象

具体的信息可以在 具体文档 中查看,基本包含所有信息。

只得到selection对象是不能对选区进行操作的,很多属性都是只读权限,要对选区进行修改,就需要获得选取的range对象,range提供了很多的函数,可与对选取进行修改。

对选取的修改有两种方式:

1、获取 range对象 是通过 window.getselection().getRangeAt(0) 获取的,然后调用range的成员函数进行修改

2、直接创建一个新的range对象,如下:range = document.createRange();

    然后对新建的range对象进行需要的修改,最后将selection的原有range删除,将新建的range对象加进去,替换掉原来的。

selection.removeAllRanges();
selection.addRange(range);

再来补充range的知识:


commonAncestorContainer 是选中元素共同的祖先元素

endContainer是结束元素 endOffset是在endContainer中的结束位置

startContainer是开始元素的位置     startOffset是 startContainer 中的开始点位置。

collapsed 是表示起始和终止是否在同一个位置,如果不再,表现的是选中的区域,如果在同一个位置,显示的就是输入光标。

具体的成员函数和变量的使用方法详见 传送门 

..........................................................................................................................................................................................................................................

我实现按下tab 增加4个空格的思路是 : 自己构造一个文本标签,里面的内容是4个 &nbsp ,将这个元素插入到光标之后,就可以实现四个空格的缩进。(前提是这个文本框是富文本编辑框)

以下我附上自己实现的富文本编辑框的全部代码,使用的vue,可以直接放在vue的一个组件里, 我实现的文本框还带有一些收缩展开的css动画。

<!--html部分-->
<template>
  <div class="edit-line">
    <div contenteditable="true" class="edit-content" placeholder="吐槽一下.." @focus="distransparent"
         @blur="transparent" ref="edit" @keydown.tab.stopdefault="tab"></div>
    <button @click="send" ref="send" style="opacity: 0.5">提交</button>
  </div>
</template>

以下是js部分,有详细的注释

实现按下tab进行缩进的是tab()函数 ,event是监听的原生的tab按键对象

<script>
  export default {
    name: 'editor',
    methods: {
      transparent () {
        this.$refs.send.$el.style = 'opacity:0.5;';
      },
      distransparent () {
        this.$refs.send.$el.style = 'opacity:1;';
      },
      tab (event) {
        // 阻止默认切换元素的行为
        if (event && event.preventDefault) {
          event.preventDefault()
        } else {
          window.event.returnValue = false
        }
        // 获取光标的range对象 event.view 是一个window对象
        let range = event.view.getSelection().getRangeAt(0);
        // 光标的偏移位置
        let offset = range.startOffset;
        // 新建一个span元素
        let span = document.createElement('span');
        // 四个 表示四个空格
        span.innerHTML = '    ';
        // 创建一个新的range对象
        let newrange = document.createRange();
        // 设置新的range的位置,也是插入元素的位置
        newrange.setStart(range.startContainer, offset);
        newrange.setEnd(range.startContainer, offset);
        newrange.collapse(true);
        newrange.insertNode(span);
        // 去掉旧的range对象,用新的range对象替换
        event.view.getSelection().removeAllRanges();
        event.view.getSelection().addRange(range);
        // 将光标的位置向后移动一个偏移量,放到加入的四个空格后面
        range.setStart(span, 1);
        range.setEnd(span, 1);
      }
    }
  }
</script>
最后是css代码
<style scoped>
  .edit-line {
    width: 100%;
    height: 100%;
    line-height: 25px;
    display: flex;
    align-items: center;
  }

  .edit-content {
    transition: width 400ms ease-in;
    width: 80%;
    /*max-height: 45px;*/
    height: 100%;
    outline: 0;
    padding: 0 4%;
    border: 1px solid #dddddd;
    border-radius: 12px;
    margin: 0 2%;
    overflow: auto;
    background-color: rgba(255, 255, 255, 0.4);
    font-size: larger;
    /*!*保证只能写入文本信息,不能是富文本*!*/
    /*-webkit-user-modify: read-write-plaintext-only*/
  }

  .edit-content:empty {
    width: 35%;
    color: lightgray;
  }

  .edit-content:empty::before {
    content: attr(placeholder);
  }

  .edit-content:focus {
    background-color: white;
    width: 80%;
  }
</style>

通过了解selection对象和range对象,以后想要给自己的编辑器添加定制的功能,都是比较类似的用法了。



猜你喜欢

转载自blog.csdn.net/Clark_Fitz817/article/details/79316037