vue 中使用 WangeEditor 时自定义首行缩进菜单

创建 textIndent.js,自定义首行缩进方法

import E from 'wangeditor'
// const E = window.wangEditor // CDN 引入的方式

// 获取必要的变量,这些在下文中都会用到
const { $, BtnMenu, DropListMenu, PanelMenu, DropList, Panel, Tooltip } = E

const SPECIAL_NODE_LIST = ['LI']
const SPECIAL_TOP_NODE_LIST = ['BLOCKQUOTE']

// 标题菜单的 class ,可作为 DropList 菜单的参考代码
class Textindent extends DropListMenu {
  constructor(editor) {
    // 菜单栏中,标题菜单的 DOM 元素
    // 注意,这里的 $ 不是 jQuery ,是 E.$ (wangEditor 自带的 DOM 操作工具,类似于 jQuery)
    // 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>0</p>'), value: '0em' },
        { $elem: $('<p>1</p>'), value: '1em' },
        { $elem: $('<p>1.5</p>'), value: '1.5em' },
        { $elem: $('<p>2</p>'), value: '2em' },
        { $elem: $('<p>2.2</p>'), value: '2.2em' },
        { $elem: $('<p>2.4</p>'), value: '2.4em' },
        { $elem: $('<p>2.6</p>'), value: '2.6em' },
        { $elem: $('<p>2.8</p>'), value: '2.8em' },
        { $elem: $('<p>3</p>'), value: '3em' },
      ],
      // droplist 每个 item 的点击事件
      clickHandler: (value) => {
        // console.log('clickHandler --> ', value);
        // value 参数即 dropListConf.list 中配置的 value
        // console.log(this.command)
        this.command(value)
      },
    }

    super($elem, editor, dropListConf)
  }

  command(value) {
    // // 设置标题
    // this.editor.cmd.do('formatBlock', `<div style="text-indent: ${value}">`);

    const editor = this.editor
    const selection = editor.selection
    const $selectionElem = selection.getSelectionContainerElem()

    // 保存选区
    selection.saveRange()

    // 获取顶级元素
    const $elems = editor.selection.getSelectionRangeTopNodes()
    if ($selectionElem?.length) {
      // list 在chrome下默认多包裹一个 p,导致不能通过顶层元素判断,所以单独加个判断
      if (this.isSpecialNode($selectionElem, $elems[0]) || this.isSpecialTopNode($elems[0])) {
        const el = this.getSpecialNodeUntilTop($selectionElem, $elems[0])
        if (el == null) return

        $(el).css('text-indent', value)
      } else {
        $elems.forEach(el => {
          el.css('text-indent', value)
        })
      }
    }
    //恢复选区
    selection.restoreSelection()
  }

  isSpecialNode(el, topEl) {
    // 如果以后有类似的元素要这样处理,直接修改这个数组即可
    const parentNode = this.getSpecialNodeUntilTop(el, topEl)

    if (parentNode == null) return false

    return SPECIAL_NODE_LIST.indexOf(parentNode.nodeName) !== -1
  }

  isSpecialTopNode(topEl) {
    if (topEl == null) return false

    return SPECIAL_TOP_NODE_LIST.indexOf(topEl.elems[0]?.nodeName) !== -1
  }

  getSpecialNodeUntilTop(el, topEl) {
    let parentNode = el.elems[0]
    const topNode = topEl.elems[0]
    // 可能出现嵌套的情况,所以一级一级向上找,是否是特殊元素
    while (parentNode != null) {
      if (SPECIAL_NODE_LIST.indexOf(parentNode?.nodeName) !== -1) {
        return parentNode
      }
      // 如果再到 top 元素之前还没找到特殊元素,直接返回元素
      if (parentNode.parentNode === topNode) {
        return parentNode
      }
      parentNode = parentNode.parentNode
    }
    return parentNode
  }

  // 菜单是否需要激活
  tryChangeActive() {
    const reg = /^h/i
    const cmdValue = this.editor.cmd.queryCommandValue('formatBlock')
    if (reg.test(cmdValue)) {
      // 选区处于标题内,激活菜单
      this.active()
    } else {
      // 否则,取消激活
      this.unActive()
    }
  }
}

export default Textindent;

index.vue 引入自定义的首行缩进 (setMenu 方法)

import TextindentMenu from './textIndent';


export default{
    name: 'editor',
    data(){
        return {
            // 默认菜单
      defaultMeanus: [
        'head',
        'bold',
        'fontSize',
        'fontName',
        'italic',
        'underline',
        'strikeThrough',
        // 'indent',
        'lineHeight',
        'foreColor',
        'backColor',
        'link',
        'list',
        'justify',
        'quote',
        'emoticon',
        'image',
        'video',
        'table',
        'code',
        'splitLine',
        'undo',
        'redo',
      ],
      editor: '',
        }
    },
    ...
    mounted(){
        this.init();
    },
    methods: {
        ...
        init() {
      const _this = this;
      this.editor = new E(this.$refs.editor);
      _this.$nextTick(function () {
        _this.editor.txt.html(this.value);
      });
      // this.editor.config.uploadImgShowBase64 = true; // 使用 base64 保存图片
      // this.editor.config.uploadImgMaxSize = 2 * 1024 * 1024; // 2M
      this.editor.config.uploadImgMaxLength = 1;
      this.setMenus(); //设置菜单
      this.editor.config.onchange = (html) => {
        _this.$emit('change', html); // 将内容同步到父组件中
      };
      this.editor.create(); //创建编辑器
    },
    setMenus(){
      // 设置菜单
      this.editor.config.menus = this.defaultMeanus;
      const menuKey = 'textindentMenuKey';
      // 注册菜单
      this.editor.menus.extend(menuKey, TextindentMenu)

      // 将菜单加入到 editor.config.menus 中    const menuKey = 'alertMenuKey'
      // 也可以通过配置 menus 调整菜单的顺序,参考【配置菜单】部分的文档   editor.config.menus.push(menuKey)      
      this.editor.config.menus.splice(7, 0, menuKey);
    },
        ...
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值