javascript - VueJS 和 tinyMCE,自定义指令

标签 javascript tinymce vue.js

我一直在努力让 VueJS 和 TinyMCE 一起工作。我得出的结论是使用指令是可行的方法。

到目前为止,我已经能够将主体作为指令参数传递,tinyMCE 设置内容。但是,我无法使两种方式绑定(bind)工作。我也担心我基于 tinyMCE api 做的事情完全错误。

我假设相关的 tinyMCE 函数是:

http://community.tinymce.com/wiki.php/api4:method.tinymce.Editor.setContent

// Sets the content of a specific editor (my_editor in this example)
tinymce.get('my_editor').setContent(data);

http://community.tinymce.com/wiki.php/api4:method.tinymce.Editor.getContent

// Get content of a specific editor:
tinymce.get('content id').getContent()

HTML

<div id="app">
  <h3>This is the tinyMCE editor</h3>
  <textarea id="editor" v-editor :body="body"></textarea>

  <hr>
  <p>This input field is properly binded</p>
  <input v-model="body">

  <hr>
  <pre>data binding: {{ body }} </pre>
</div>

JS

tinymce.init({
    selector:'#editor',
});

Vue.directive('editor', {
    twoWay: true,
    params: ['body'],

    bind: function () {
        tinyMCE.get('editor').setContent(this.params.body);
        tinyMCE.get('editor').on('change', function(e) {
            alert("changed");
        });
    },
    update: function (value) {
        $(this.el).val(value).trigger('change')
    },
});

var editor = new Vue({
    el: '#app',
    data: {
        body: 'The message'
    }
})

fiddle

https://jsfiddle.net/nf3ftm8f/

最佳答案

在 Vue.js 2.0 中,指令仅用于应用低级直接 DOM 操作。他们不再有对 Vue 实例数据的 this 引用。 (引用:https://v2.vuejs.org/v2/guide/migration.html#Custom-Directives-simplified)

因此我建议改用Component

Tinymce组件:

// Use JSPM to load dependencies: vue.js 2.1.4, tinymce: 4.5.0
import Vue from 'vue/dist/vue';
import tinymce from 'tinymce';

// Local component
var TinymceComponent = {
    template: `<textarea class="form-control">{{ initValue }}</textarea>`,
    props: [ 'initValue', 'disabled' ],
    mounted: function() {
        var vm = this,
            tinymceDict = '/lib/jspm_packages/github/tinymce/tinymce-dist@4.5.1/';

        // Init tinymce
        tinymce.init({
            selector: '#' + vm.$el.id,
            menubar: false,
            toolbar: 'bold italic underline | bullist numlist',
            theme_url: tinymceDict + 'themes/modern/theme.js,
            skin_url: tinymceDict + 'skins/lightgray',
            setup: function(editor) {
                // If the Vue model is disabled, we want to set the Tinymce readonly
                editor.settings.readonly = vm.disabled;

                if (!vm.disabled) {
                    editor.on('blur', function() {
                        var newContent = editor.getContent();

                        // Fire an event to let its parent know
                        vm.$emit('content-updated', newContent);
                    });
                }
            }
        });
    },
    updated: function() {
        // Since we're using Ajax to load data, hence we have to use this hook because when parent's data got loaded, it will fire this hook.
        // Depends on your use case, you might not need this
        var vm = this;

        if (vm.initValue) {
            var editor = tinymce.get(vm.$el.id);
            editor.setContent(vm.initValue);
        }
    }
};

// Vue instance
new Vue({
    ......
    components: {
        'tinymce': TinymceComponent
    }
    ......
});

Vue实例(简体)

new Vue({
    el: '#some-id',
    data: {
        ......
        description: null
        ......
    },
    components: {
        'tinymce': TinymceComponent
    },
    methods: {
        ......
        updateDescription: function(newContent) {
            this.description = newContent;
        },
        load: function() {
            ......
            this.description = "Oh yeah";
            ......
        }
        ......
    },
    mounted: function() {
        this.load();
    }
});

HTML(MVC View )

<form id="some-id">
    ......
    <div class="form-group">
        <tinymce :init-value="description"
                 v-on:content-updated="updateDescription"
                 :id="description-tinymce"
                 :disabled="false">
        </tinymce>
    </div>
    ......
</form>

流程

  1. 首先通过远程资源加载数据,即 AJAX。 描述已设置。
  2. 描述 通过 props: initValue 传递给组件。
  3. 安装组件时,tinymce 会使用初始描述进行初始化。
  4. 它还设置了 on blur 事件来获取更新的内容。
  5. 每当用户失去对编辑器的关注时,就会捕获新内容,并且组件会发出事件 content-updated,让家长知道发生了什么事。
  6. 在 Html 上你有 v-on:content-updated。由于父级正在监听 content-updated 事件,因此当事件发出时将调用父级方法 updateDescription

!!几个重要说明!!

  • 根据设计,组件具有从父组件到组件的 1 种绑定(bind)方式。因此,当 description 从 Vue 实例更新时,组件的 initValue 属性也应该自动更新。
  • 如果我们可以将用户在 tinymce 编辑器中键入的任何内容传递回父 Vue 实例,那将是很好的,但不应该使用 2 种绑定(bind)方式。这就是您需要使用 $emit 来触发事件并从组件通知 parent 的时候。
  • 您不必在父级中定义函数并执行 v-on:content-updated="updateDescription"。您可以通过 v-on:content-updated="description = $event" 直接更新数据。 $event 具有您为组件内的函数定义的参数 - newContent 参数。

希望我解释清楚了。这整件事花了我 2 周的时间才弄明白!!

关于javascript - VueJS 和 tinyMCE,自定义指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34532847/

相关文章:

javascript - 在发送到 IBM Watson Assistant 之前删除 Node.js 应用程序中的上下文变量

vue.js - Vue/Nuxt : How to define a global method accessible to all components?

javascript - 控制台警告 : component lists rendered with v-for should have explicit keys

javascript - 如何使用 Javascript 将 HTML/CSS 转换为 PDF?

javascript - Web Worker 不与 React 组件通信

jquery - 未捕获的类型错误 : Object #<HTMLLIElement> has no method 'find' in Chrome

javascript - 在tinymce编辑器中加载html文件作为初始内容

jquery - tinymce 删除文本空格和换行符

vue.js - VueJS : router. 解决问题

javascript - 格式化从 url 中提取的数据