【问题标题】:Convert Pell.js to Vue component for Customizing将 Pell.js 转换为 Vue 组件以进行自定义
【发布时间】:2021-04-27 19:50:58
【问题描述】:

我正在尝试从 pell 富文本编辑器转换为 vue 组件。我已经下载了 pell.js 并将其转换为 vue 组件,但我现在遇到了一些问题。 我将所有数据和方法从 pell 转移到 vue 组件。

我在 created() 方法中调用了 this.init 函数。它表明在 datas() 中定义的 this.defaultActions 没有在 init 函数中定义。

请给我任何建议。谢谢..

这是我的 vue 组件

<template>
    <div class="content">
      <h1>pell</h1>
      <div id="editor" class="pell"></div>
      <div style="margin-top:20px;">
        <h3>Text output:</h3>
        <div id="text-output"></div>
      </div>
      <div style="margin-top:20px;">
        <h3>HTML output:</h3>
        <pre id="html-output"></pre>
      </div>
    </div>
</template>

<script>

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
export default {
    data: ()=> ({
        defaultParagraphSeparatorString : 'defaultParagraphSeparator',
        formatBlock : 'formatBlock',
        defaultActions: {
            bold: {
                icon: '<b>B</b>',
                title: 'Bold',
                state: function state() {
                    return this.queryCommandState('bold');
                },
                result: function result() {
                    return this.exec('bold');
                }
            },
            italic: {
                icon: '<i>I</i>',
                title: 'Italic',
                state: function state() {
                    return this.queryCommandState('italic');
                },
                result: function result() {
                    return this.exec('italic');
                }
            },
            underline: {
                icon: '<u>U</u>',
                title: 'Underline',
                state: function state() {
                    return this.queryCommandState('underline');
                },
                result: function result() {
                    return this.exec('underline');
                }
            },
            strikethrough: {
                icon: '<strike>S</strike>',
                title: 'Strike-through',
                state: function state() {
                return this.queryCommandState('strikeThrough');
                },
                result: function result() {
                return this.exec('strikeThrough');
                }
            },
            heading1: {
                icon: '<b>H<sub>1</sub></b>',
                title: 'Heading 1',
                result: function result() {
                return this.exec('formatBlock', '<h1>');
                }
            },
            heading2: {
                icon: '<b>H<sub>2</sub></b>',
                title: 'Heading 2',
                result: function result() {
                return this.exec('formatBlock', '<h2>');
                }
            },
            paragraph: {
                icon: '&#182;',
                title: 'Paragraph',
                result: function result() {
                return this.exec('formatBlock', '<p>');
                }
            },
            quote: {
                icon: '&#8220; &#8221;',
                title: 'Quote',
                result: function result() {
                return this.exec('formatBlock', '<blockquote>');
                }
            },
            olist: {
                icon: '&#35;',
                title: 'Ordered List',
                result: function result() {
                return this.exec('insertOrderedList');
                }
            },
            ulist: {
                icon: '&#8226;',
                title: 'Unordered List',
                result: function result() {
                return this.exec('insertUnorderedList');
                }
            },
            code: {
                icon: '&lt;/&gt;',
                title: 'Code',
                result: function result() {
                return this.exec('formatBlock', '<pre>');
                }
            },
            line: {
                icon: '&#8213;',
                title: 'Horizontal Line',
                result: function result() {
                return this.exec('insertHorizontalRule');
                }
            },
            link: {
                icon: '&#128279;',
                title: 'Link',
                result: function result() {
                var url = window.prompt('Enter the link URL');
                if (url) this.exec('createLink', url);
                }
            },
            image: {
                icon: '&#128247;',
                title: 'Image',
                result: function result() {
                var url = window.prompt('Enter the image URL');
                if (url) this.exec('insertImage', url);
                }
            }
        },

        defaultClasses: {
            actionbar: 'pell-actionbar',
            button: 'pell-button',
            content: 'pell-content',
            selected: 'pell-button-selected'
        },
    }),

    created(){
        console.log("this.defaultActions", this.defaultActions);
        this.init(
            {   
                element: document.getElementById('editor'),
                defaultParagraphSeparator: 'p',
                // actions: [
                //     'bold',
                //     'italic',
                //     'underline',
                //     'strikethrough'
                // ],
                onChange: function (html) {
                    document.getElementById('text-output').innerHTML = html
                    document.getElementById('html-output').textContent = html
                }
            }
        );
    },

    methods:{
        addEventListener(parent, type, listener) {
            return parent.addEventListener(type, listener);
        },
        appendChild(parent, child) {
            return parent.appendChild(child);
        },
        createElement(tag) {
            return document.createElement(tag);
        },
        queryCommandState(command) {
            return document.queryCommandState(command);
        },
        queryCommandValue(command) {
            return document.queryCommandValue(command);
        },
        exec(command) {
            var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
            return document.execCommand(command, false, value);
        },

        init(settings){
            Object.keys(this.defaultActions).map(function (action) {
                console.log("action", action)
            });
            var actions = settings.actions ? settings.actions.map(function (action) {
                if (typeof action === 'string') return this.defaultActions[action];
                else if (this.defaultActions[action.name]) return _extends({}, this.defaultActions[action.name], action);
                return action;
            }) : Object.keys(this.defaultActions).map(function (action) {
                console.log("action", action)
                console.log("sss", this.defaultActions)
                // return this.defaultActions[action];
            });

            var classes = _extends({}, this.defaultClasses, settings.classes);

            var defaultParagraphSeparator = settings[this.defaultParagraphSeparatorString] || 'div';

            var actionbar = this.createElement('div');
            actionbar.className = classes.actionbar;
            this.appendChild(settings.element, actionbar);

            var content = settings.element.content = this.createElement('div');
            content.contentEditable = true;
            content.className = classes.content;
            content.oninput = function (_ref) {
                var firstChild = _ref.target.firstChild;

                if (firstChild && firstChild.nodeType === 3) this.exec(this.formatBlock, '<' + defaultParagraphSeparator + '>');else if (content.innerHTML === '<br>') content.innerHTML = '';
                settings.onChange(content.innerHTML);
            };
            content.onkeydown = function (event) {
                if (event.key === 'Enter' && this.queryCommandValue(this.formatBlock) === 'blockquote') {
                setTimeout(function () {
                    return this.exec(this.formatBlock, '<' + defaultParagraphSeparator + '>');
                }, 0);
                }
            };
            this.appendChild(settings.element, content);

            actions.forEach(function (action) {
                var button = this.createElement('button');
                button.className = classes.button;
                button.innerHTML = action.icon;
                button.title = action.title;
                button.setAttribute('type', 'button');
                button.onclick = function () {
                return action.result() && content.focus();
                };

                if (action.state) {
                var handler = function handler() {
                    return button.classList[action.state() ? 'add' : 'remove'](classes.selected);
                };
                this.addEventListener(content, 'keyup', handler);
                this.addEventListener(content, 'mouseup', handler);
                this.addEventListener(button, 'click', handler);
                }

                this.appendChild(actionbar, button);
            });

            if (settings.styleWithCSS) this.exec('styleWithCSS');
            this.exec(this.defaultParagraphSeparatorString, defaultParagraphSeparator);

            return settings.element;
        }
    }
}
</script>
    
<style>
    .content {
        box-sizing: border-box;
        margin: 0 auto;
        max-width: 600px;
        padding: 20px;
      }

      #html-output {
        white-space: pre-wrap;
      }
      .pell {
  border: 1px solid rgba(10, 10, 10, 0.1);
  box-sizing: border-box; }

.pell-content {
  box-sizing: border-box;
  height: 300px;
  outline: 0;
  overflow-y: auto;
  padding: 10px; }

.pell-actionbar {
  background-color: #FFF;
  border-bottom: 1px solid rgba(10, 10, 10, 0.1); }

.pell-button {
  background-color: transparent;
  border: none;
  cursor: pointer;
  height: 30px;
  outline: 0;
  width: 30px;
  vertical-align: bottom; }

.pell-button-selected {
  background-color: #F0F0F0; }

</style>

【问题讨论】:

标签: vue.js


【解决方案1】:

您应该在块映射操作中使用箭头函数,从周围的范围中保留this

var actions = settings.actions
  ? settings.actions.map(action => {                            // arrow function here
      if (typeof action === "string") return this.defaultActions[action];
      else if (this.defaultActions[action.name])
        return _extends({}, this.defaultActions[action.name], action);
      return action
    })
  : Object.keys(this.defaultActions).map(action => {            // arrow function here
      console.log("action", action)
      console.log("sss", this.defaultActions);
      // return this.defaultActions[action];
    });

【讨论】:

  • 谢谢......它就像魅力一样......请问,如果您没有问题,可以让我知道在数据中调用方法定义部分的方法吗?我现在卡住了这个问题。 :)
  • 是哪位?我看到的下一个问题是appendChild 方法。
  • 要解决这个问题,请将挂钩从 created() 更改为 mounted(),因为在元素存在之前您无法对其进行操作。
  • 好吧。是的。你说的对。 appendchild 函数有两个参数 - settings.element 和 content。并且 setting.element 为 null 因为在创建的生命周期中调用了 init 函数。我通过将其更改为mounted()来修复。
  • 下一个问题是actions.forEach(function(action) { 将其更改为actions.forEach(action =&gt; {,原因与原始问题相同。
【解决方案2】:

仅供参考,也可以使用pell repository中给出的示例Vue代码
(或其部分,例如样式)

<template>
  <div>
    <h6>Editor:</h6>
    <div id="pell" class="pell" />
    <h6>HTML Output:</h6>
    <pre id="pell-html-output"></pre>
  </div>
</template>

<script>
import pell from 'pell'

export default {
  methods: {
    ensureHTTP: str => /^https?:\/\//.test(str) && str || `http://${str}`
  },
  mounted () {
    pell.init({
      element: document.getElementById('pell'),
      onChange: html => {
        window.document.getElementById('pell-html-output').textContent = html
      },
      actions: [
        'bold', 'italic', 'underline', 'strikethrough', 'heading1', 'heading2',
        'paragraph', 'quote', 'olist', 'ulist', 'code', 'line',
        {
          name: 'image',
          result: () => {
            const url = window.prompt('Enter the image URL')
            if (url) pell.exec('insertImage', this.ensureHTTP(url))
          }
        },
        {
          name: 'link',
          result: () => {
            const url = window.prompt('Enter the link URL')
            if (url) pell.exec('createLink', this.ensureHTTP(url))
          }
        }
      ]
    })
  }
}
</script>

<style>
.pell {
  border: 2px solid #000;
  border-radius: 0;
  box-shadow: none;
}

#pell-html-output {
  margin: 0;
  white-space: pre-wrap;
}
</style>

【讨论】:

    猜你喜欢
    • 2010-12-01
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 2019-02-17
    • 2021-06-25
    • 1970-01-01
    相关资源
    最近更新 更多