VueJS和tinyMCE,自定义指令

时间:2015-12-30 16:00:21

标签: javascript tinymce vue.js

我一直在努力让VueJS和TinyMCE一起工作。我得出的结论是,使用指令将是最佳选择。

到目前为止,我已经能够将身体作为指令参数传递,而tinyMCE设置内容。但是,我无法通过双向绑定工作。我也担心基于tinyMCE api做错事情。

我认为相关的tinyMCE函数将是:

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

select t.dt,qty,val from @t t 
left join @Claim t1 on 
year(t.dt)=year(t1.dt)
and 
month(t.dt)= month(t1.dt)

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

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

HTML

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

JS

<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>

小提琴

https://jsfiddle.net/nf3ftm8f/

4 个答案:

答案 0 :(得分:4)

使用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
    }
    ......
});

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视图)

<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)加载数据。 description已设置。
  2. description已通过props: initValue传递给组件。
  3. 安装组件时,会使用初始说明初始化tinymce
  4. 它还会设置on blur事件以获取更新的内容。
  5. 每当用户失去对编辑器的关注时,就会捕获一个新内容,并且组件会发出一个事件content-updated,让父母知道发生了什么事。
  6. 在Html上,您有v-on:content-updated。由于父级正在侦听content-updated事件,因此将在事件发生时调用父方法updateDescription
  7. !!情侣重要提示!!

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

    希望我能清楚地解释清楚。这整件事花了我两个星期才弄明白!!

答案 1 :(得分:2)

这是Vue的Tinymce组件。 http://jsbin.com/pucubol/edit?html,js,output

了解v模型和自定义输入组件也很好: http://vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events

Vue.component('tinymce', {
	props: ['value'],
	template: `<div><textarea rows="10" v-bind:value="value"></textarea></div>`,
	methods: {
		updateValue: function (value) {
          console.log(value);
			this.$emit('input', value.trim());
		}
	},
    mounted: function(){
      var component = this;
      tinymce.init({ 
        target: this.$el.children[0],
        setup: function (editor) {
          editor.on('Change', function (e) {
            component.updateValue(editor.getContent());
          })
        }
      });
    }
});
<tinymce v-model="whatever"></tinymce>

答案 2 :(得分:0)

试试这个:

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

  bind: function () {
    tinyMCE.get('editor').setContent(this.params.body);
    var that = this;
    tinyMCE.get('editor').on('change', function(e) {
      that.vm.body = this.getContent();
    });
  }
});

诀窍是将指令存储在临时变量“that”中,以便您可以在change事件回调中访问它。

答案 3 :(得分:0)

现在有一个npm package,它是TinyMCE的薄包装,可以更轻松地在Vue应用程序中使用。

它是开放源代码,代码在GitHub上。

安装:

$ npm install @tinymce/tinymce-vue

用法:

 import Editor from '@tinymce/tinyme-vue';

模板:

<editor api-key="API_KEY" :init="{plugins: 'wordcount'}"></editor>

其中API_KEY是您来自tiny的API密钥。 init部分与默认init语句相同,只不过您不需要选择器。有关示例,请参见documentation