原创

精简富文本组件


ls-textarea

精简富文本框 支持插入dom 如(表情符),高度自适应,未聚焦插入至末尾,支持v-modal

Build Setup

npm install ls-textarea --save

全局注册

//main.js中引入
import myPlugin from 'tlp_plugin_sum'
Vue.use(myPlugin);

局部注册

import LsTextarea from 'ls-textarea'
export default {
  components: {
    LsTextarea
  }
}

使用

<ls-textarea v-model="text" ref="rich_text"></ls-textarea>

方法 ref methods

设置内容

this.$refs.rich_text.setData("爱你么么哒")

获取内容

this.$refs.rich_text.getContent()

参数 params

v-modal 字符串

initType 字符串(text或html) 默认html、初次渲染的文本或者dom

initFocus 布尔值(true或false) 默认false,初次渲染完毕是否获取焦点

maxHeight 字符串 默认160px, 组件最大高度

主动设置内容不要直接改变v-modal的值,应该使用setData方法进行设置,编辑过程中内容会同步在v-modal

npm地址

https://www.npmjs.com/package/ls-textarea

git地址

https://gitee.com/yuan30/ls-textarea

核心代码

<template>
  <div class="area_box">
    <div class="area_content" ref="area_content" contenteditable="true" @focus="focusChange(true)" @blur="focusChange(false)"  @keyup="changeContent"></div>
  </div>
</template>

<script>
  export default {
    name: 'LsTextarea',
    props: {
      value: String,
      initType: String,
      initFocus: {
        type: Boolean,
        default: false
      }
    },
    data () {
      return {
        isFocus:false
      }
    },
    methods: {
      init(){
        let area = this.$refs.area_content;
        if (this.initType === 'text') {
          area.innerText = this.value;
        } else {
          area.innerHTML = this.value;
        }
        if (this.initFocus) {
          this.keepLastIndex(area)
        }
      },
      focusChange(focus) {
        setTimeout(() => {
          this.isFocus = focus
        }, 10)
      },
      setData(str) {
        let area = this.$refs.area_content;
        if (this.getSelectionText()){
          return this.replaceSelectionWithHtml(str)
        }
        function fC() {
          // 获得被选择的元素
          let selection = window.getSelection ? window.getSelection() : document.selection;
          // createRange()返回新创建的 Range 对象,两个边界点都被设置为文档的开头
          let range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);
          // ie
          if (!window.getSelection) {
            selection = window.getSelection ? window.getSelection() : document.selection;
            range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);
            range.pasteHTML(str);
            range.collapse(false);
            range.select();
          } else {
            // range.collapse(false);//true 折叠到 Range 的 start 节点,false 折叠到 end 节点。如果省略,则默认为 false
            let ctf = range.createContextualFragment(str);
            let ctfLastChild = ctf.lastChild;
            while (ctfLastChild && ctfLastChild.nodeName.toLowerCase() === 'br' && ctfLastChild.previousSibling && ctfLastChild.previousSibling.nodeName.toLowerCase() === 'br') {
              let e = ctfLastChild;
              ctfLastChild = ctfLastChild.previousSibling;
              ctf.removeChild(e)
            }
            range.insertNode(ctf);
            if (ctfLastChild) {
              range.setEndAfter(ctfLastChild);
              range.setStartAfter(ctfLastChild)
            }
            selection.removeAllRanges();
            selection.addRange(range)
          }
        }

        if (!this.isFocus) {
          area.focus();
          setTimeout(() => {
            this.keepLastIndex(area)
            fC()
          }, 5)
        } else {
          fC()
        }
      },
      // 设置光标在最后 没有光标的情况下
      keepLastIndex(area) {
        if (window.getSelection) { //ie11 10 9 ff safari
          area.focus(); //解决ff不获取焦点无法定位问题
          let range = window.getSelection(); //创建range
          range.selectAllChildren(area); //range 选择area下所有子内容
          range.collapseToEnd(); //光标移至最后
        } else if (document.selection) { //ie10 9 8 7 6 5
          let range = document.selection.createRange(); //创建选择对象
          range.moveToElementText(area); //range定位到area
          range.collapse(false); //光标移至最后
          range.select();
        }
      },
      // 获取选中的html内容
      getSelectionText() {
        var html = '';
        if (typeof window.getSelection !== 'undefined') {
          let sel = window.getSelection();
          if (sel.rangeCount) {
            let container = document.createElement('div');
            for (let i = 0, len = sel.rangeCount; i < len; ++i) {
              container.appendChild(sel.getRangeAt(i).cloneContents());
            }
            html = container.innerHTML;
          }
        } else if (typeof document.selection !== 'undefined') {
          if (document.selection.type === 'Text') {
            html = document.selection.createRange().htmlText;
          }
        }
        return html
      },
      // 替换选中区域
      replaceSelectionWithHtml(html) {
        var range;
        if (window.getSelection && window.getSelection().getRangeAt) {
          range = window.getSelection().getRangeAt(0);
          range.deleteContents();
          let div = document.createElement('div');
          div.innerHTML = html;
          let frag = document.createDocumentFragment(), child;
          // eslint-disable-next-line no-cond-assign
          while (child = div.firstChild) {
            frag.appendChild(child);
          }
          range.insertNode(frag);
        } else if (document.selection && document.selection.createRange) {
          range = document.selection.createRange();
          range.pasteHTML(html);
        }
      },
      // 获取内容
      getContent(){
        return this.$refs.area_content.innerHTML
      },
      changeContent(){
        this.$emit('input',this.getContent())
      }
    },
    mounted() {
      if (this.initType || this.value !== '') {
        this.init()
      }
    }
  }
</script>

<style scoped>
  .area_box{
    min-height: 30px;
    background: #f5f2f0;
    border-radius: 20px;
  }
  .area_content{
    width:100%;
    height:100%;
    padding: 5px;
    box-sizing: border-box;
    font-size: 16px;
    line-height: 1.5em;
  }
</style>
组件
vue
  • 作者:零三(联系作者)
  • 最后更新时间:2020-07-30 17:24
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 转载声明:来源地址 https://web03.cn