VueJS 和 tinyMCE,自定义指令

Pis*_*hio 5 javascript tinymce vue.js

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

到目前为止,我已经能够将主体作为指令参数传入,并且 tinyMCE 设置内容。但是,我无法让两种方式绑定工作。我也担心基于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);
Run Code Online (Sandbox Code Playgroud)

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

// Get content of a specific editor:
tinymce.get('content id').getContent()
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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'
    }
})
Run Code Online (Sandbox Code Playgroud)

小提琴

https://jsfiddle.net/nf3ftm8f/

Dav*_*ang 6

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

因此我建议改为使用Component

TinymceComponent:

// 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
    }
    ......
});
Run Code Online (Sandbox Code Playgroud)

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();
    }
});
Run Code Online (Sandbox Code Playgroud)

HTML(MVC 视图)

<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>
Run Code Online (Sandbox Code Playgroud)

流量

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

!!几个重要的注意事项!!

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

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