wangEditor配置首行缩进包括缩进及取消缩进功能

wangEditor缩进采用的是padding-left:2em,没有首行缩进功能,因此个人根据官方说明配置了一下,移除了原来的缩进改成了首行缩进。

普通粘贴时基本好用,但是无格式文本粘贴还是只能是全局缩进。

希望大家也能帮助优化一下。

// 引入 wangEditor
import WangEditor from 'wangeditor'
const { $, DropListMenu } = WangEditor

// 第一,菜单 class ,Button 菜单继承 BtnMenu class
class AlertMenu extends DropListMenu {
    constructor (editor) {
      // data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
        const $elem = $(
          '<div class="w-e-menu" data-title="首行缩进"><i class="w-e-icon-indent-increase"></i></div>'
        )
        // droplist 配置
        const dropListConf = {
            width: 100,
            title: '首行缩进',
            type: 'list',
            list: [
                { $elem: $('<p><i class="w-e-icon-indent-increase w-e-drop-list-item"></i>增加缩进</p>'), value: '2em' },
                { $elem: $('<p><i class="w-e-icon-indent-decrease w-e-drop-list-item"></i>减少缩进</p>'), value: '' }
            ],
            // droplist 每个 item 的点击事件
            clickHandler: (value) => {
                // value 参数即 dropListConf.list 中配置的 value
                this.command(value)
            }
        }
        super($elem, editor, dropListConf)
    }

    command (value) {
        // 设置标题
        // 判断是否有子元素 有一个官方提供的结束节点不准确的Bug
        if (this.editor.selection.getSelectionContainerElem().elems[0].children.length > 0) {
          // 无格式文本父元素是p,要把第一行单独拿出来缩进
          let fir = 0
          // 判断是否进入选区
          var start = false
          // 提前算出<br>标签的个数
          let isAllBr = 0
          // 判断是否全部是<br> 即无格式文本
          let isVali = false
          // 提前算出<br>标签的个数
          for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
            if (e.tagName === 'BR') {
              isAllBr++
            }
          }
          // 如果选区内子元素的个数与<br>元素个数相同即可判断为无格式文本
          if (isAllBr === this.editor.selection.getSelectionContainerElem().elems[0].children.length) isVali = true
          // 对无格式文本进行缩进处理
          if (isVali) {
            for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
              if (e.tagName === "BR") {
                if (value === '2em') {
                  fir += 1
                  if (fir === 1) {
                    this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
                  }
                  // 先把<br>换成span元素并增加缩进 再在span元素前再加上<br> indentP是因为原来用的是P元素
                  const indentP = document.createElement("span")
                  indentP.style.display = "inline-block"
                  indentP.style.width = value
                  indentP.className = 'indentP'
                  const theBr = document.createElement("br")
                  this.editor.selection.getSelectionContainerElem().elems[0].replaceChild(indentP, e)
                  this.editor.selection.getSelectionContainerElem().elems[0].insertBefore(theBr, indentP)
                }
              }
            }
          } else {
            let elseIndex = 0
            // 正常文本 以及无格式文本取消缩进逻辑
            for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
              // 如果是无格式文本
              if (e.className === "indentP") {
                elseIndex++
                if (elseIndex === 1) {
                  this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
                }
                this.editor.selection.getSelectionContainerElem().elems[0].removeChild(e)
                continue
              }
              // 如果是普通文本 选区的开始节点
              if (e === this.editor.selection.getSelectionStartElem().elems[0]) {
                start = true
              }
              // 如果已是选中节点,则开始进行缩进
              if (start) {
                e.style.textIndent = value
              }
              // 选区的结束节点 跳出循环
              if (e === this.editor.selection.getSelectionEndElem().elems[0]) {
                break
              }
            }
          }
        } else {
          this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
        }
    }

    // 删除这段代码会报错
    tryChangeActive () {
        // const reg = /^h/i
        // const cmdValue = this.editor.cmd.queryCommandValue('indent')
        // if (reg.test(cmdValue)) {
        //     // 选区处于标题内,激活菜单
        //     this.active()
        // } else {
        //     // 否则,取消激活
        //     this.unActive()
        // }
        // this.active()
    }
}
// 菜单 key ,各个菜单不能重复
const menuKey = 'alertMenuKey'
// 注册菜单
WangEditor.registerMenu(menuKey, AlertMenu)

完整代码 组件editor.vue

<template>
  <div class="editor">
    <div id="demo1"></div>
  </div>
</template>

<script>
// 引入 wangEditor
import WangEditor from 'wangeditor'
const { $, DropListMenu } = WangEditor

// 第一,菜单 class ,Button 菜单继承 BtnMenu class
class AlertMenu extends DropListMenu {
    constructor (editor) {
      // data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
        const $elem = $(
          '<div class="w-e-menu" data-title="首行缩进"><i class="w-e-icon-indent-increase"></i></div>'
        )
        // droplist 配置
        const dropListConf = {
            width: 100,
            title: '首行缩进',
            type: 'list',
            list: [
                { $elem: $('<p><i class="w-e-icon-indent-increase w-e-drop-list-item"></i>增加缩进</p>'), value: '2em' },
                { $elem: $('<p><i class="w-e-icon-indent-decrease w-e-drop-list-item"></i>减少缩进</p>'), value: '' }
            ],
            // droplist 每个 item 的点击事件
            clickHandler: (value) => {
                // value 参数即 dropListConf.list 中配置的 value
                this.command(value)
            }
        }
        super($elem, editor, dropListConf)
    }

    command (value) {
        // 设置标题
        // 判断是否有子元素 有一个官方提供的结束节点不准确的Bug
        if (this.editor.selection.getSelectionContainerElem().elems[0].children.length > 0) {
          let fir = 0
          var start = false
          let isAllBr = 0
          let isVali = false
          // 判断是否全部是BR 即无格式文本
          for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
            if (e.tagName === 'BR') {
              isAllBr++
            }
          }
          if (isAllBr === this.editor.selection.getSelectionContainerElem().elems[0].children.length) isVali = true
          // 对无格式文本进行缩进处理
          // 如果是<br>
          // 选中节点无法选到br 进行和取消的逻辑
          // 判断是否已是选中节点
          if (isVali) {
            for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
              if (e.tagName === "BR") {
                if (value === '2em') {
                  fir += 1
                  if (fir === 1) {
                    this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
                  }
                  const indentP = document.createElement("span")
                  indentP.style.display = "inline-block"
                  indentP.style.width = value
                  indentP.className = 'indentP'
                  const theBr = document.createElement("br")
                  this.editor.selection.getSelectionContainerElem().elems[0].replaceChild(indentP, e)
                  this.editor.selection.getSelectionContainerElem().elems[0].insertBefore(theBr, indentP)
                }
              }
            }
          } else {
            let elseIndex = 0
            // 正常文本 以及无格式文本取消缩进逻辑
            for (let e of this.editor.selection.getSelectionContainerElem().elems[0].children) {
              // 如果是无格式文本
              if (e.className === "indentP") {
                elseIndex++
                if (elseIndex === 1) {
                  this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
                }
                this.editor.selection.getSelectionContainerElem().elems[0].removeChild(e)
                continue
              }
              // 选区的开始节点
              if (e === this.editor.selection.getSelectionStartElem().elems[0]) {
                start = true
              }
              // 如果已是选中节点,则开始进行缩进
              if (start) {
                e.style.textIndent = value
              }
              // 选区的结束节点 跳出循环
              if (e === this.editor.selection.getSelectionEndElem().elems[0]) {
                break
              }
            }
          }
        } else {
          this.editor.selection.getSelectionContainerElem().elems[0].style.textIndent = value
        }
    }

    // 删除这段代码会报错
    tryChangeActive () {
        // const reg = /^h/i
        // const cmdValue = this.editor.cmd.queryCommandValue('indent')
        // if (reg.test(cmdValue)) {
        //     // 选区处于标题内,激活菜单
        //     this.active()
        // } else {
        //     // 否则,取消激活
        //     this.unActive()
        // }
        // this.active()
    }
}
// 菜单 key ,各个菜单不能重复
const menuKey = 'alertMenuKey'
// 注册菜单
WangEditor.registerMenu(menuKey, AlertMenu)
export default {
  name: 'editor',
  data () {
    return {
      editor: null,
      editorData: ''
    }
  },
  model: {
      prop: 'content',
      event: 'change'
  },
  props: {
      content: {
          type: String,
          default: ''
      }
  },
  mounted () {
    const editor = new WangEditor(`#demo1`)
    // 配置 onchange 回调函数,将数据同步到 vue 中
    editor.config.onchange = (newHtml) => {
      this.editorData = newHtml
      this.$emit('change', newHtml)
    }
    editor.config.excludeMenus = [
      'code',
      'indent'
    ]
    editor.config.pasteFilter = true
    editor.config.pasteText = true
    editor.config.pasteIgnoreImg = true
    editor.config.uploadImgMaxSize = 2 * 1024 * 1024 //  限制大小为2M
    editor.config.zIndex = 1
    editor.config.height = 466
    editor.config.showLinkImg = false
    editor.config.showLinkVideo = false
    editor.config.uploadFileName = 'file'
    editor.config.uploadImgServer = this.baseURL + 'CommonPage/FileUploadHandler.ashx?m=' + Math.random()
    editor.config.uploadVideoServer = this.baseURL + 'CommonPage/FileUploadHandler.ashx?m=' + Math.random()
    editor.config.uploadVideoMaxSize = 1 * 1024 * 1024 * 1024 // 1024m
    editor.config.uploadVideoAccept = ['mp4']
    editor.config.uploadImgHooks = {
      // 图片上传并返回结果,但图片插入错误时触发
      fail: function (xhr, editor, result) {
        // console.log(result)
      },
      success: function (xhr) {
        // 图片上传并返回结果,图片插入成功之后触发
      },
      customInsert: function (insertImg, result) {
        // 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!)
        // insertImg 是插入图片的函数,editor 是编辑器对象,result 是服务器端返回的结果
        // 举例:假如上传图片成功后,服务器端返回的是 {url:'....'} 这种格式,即可这样插入图片:
          let url = '../' + result.ResPath
          insertImg(url)
          // result 必须是一个 JSON 格式字符串!!!否则报错
      }
    }
    editor.config.uploadVideoHooks = {
      fail: function (xhr, editor, result) {
        // console.log(result)
      },
      success: function (xhr) {
        // 图片上传并返回结果,图片插入成功之后触发
      },
      customInsert: function (insertVideoFn, result) {
        // 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!)
        // insertImg 是插入图片的函数,editor 是编辑器对象,result 是服务器端返回的结果
        // 举例:假如上传图片成功后,服务器端返回的是 {url:'....'} 这种格式,即可这样插入图片:
          let url = '../' + result.ResPath
          insertVideoFn(url)
          // result 必须是一个 JSON 格式字符串!!!否则报错
      }
    }
    editor.config.customAlert = function (s, t) {
      switch (t) {
        case 'success':
          this.$message.success(s)
          break
        case 'info':
          this.$message.info(s)
          break
        case 'warning':
          this.$message.warning(s)
          break
        case 'error':
          this.$message.error(s)
          break
        default:
          this.$message.info(s)
          break
      }
    }

    // 创建编辑器
    editor.create()
    this.editor = editor
  },
  methods: {
    getEditorData () {
		// 通过代码获取编辑器内容
		// let data = this.editor.txt.html()
    },
    clearContent () {
      this.editor.txt.clear()
    },
    beforeDestroy () {
      // 调用销毁 API 对当前编辑器实例进行销毁
      this.editor.destroy()
      this.editor = null
    },
    setHtml (content) {
      this.editor.txt.html(content)
    }
  },
  beforeDestroy () {
    // 销毁编辑器
    this.editor.destroy()
    this.editor = null
  }
}
</script>

<style lang="less" >
  .editor {
    font-size: 1em;
    width: 100%;
    margin: auto;
    tr, table td, table th {
      height: 2em;
      // min-height: 30px;
    }
    // table {
    //   border-top: 1px solid #ccc;
    //   border-left: 1px solid #ccc;
    // }
    // table td,
    // table th {
    //   border-bottom: 1px solid #ccc;
    //   border-right: 1px solid #ccc;
    //   padding: 3px 5px;
    // }
    // table th {
    //   border-bottom: 2px solid #ccc;
    //   text-align: center;
    // }
    .w-e-text::-webkit-scrollbar {
      width: 6px !important;
      height: 6px !important;
    }
    .w-e-text::-webkit-scrollbar-thumb {
      border-radius: 5px !important;
      box-shadow:  0 0 2px #fff !important;
      background-color: #ddd !important;
    }
    .w-e-text::-webkit-scrollbar-track{
      border-radius: 0;
      box-shadow: inset 0 0 2px #fff;
    }
  }
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值