VueJS和tinyMCE,自定义指令
我一直在努力让VueJS和TinyMCE一起工作。我得出的结论是,使用指令将是最佳选择。
I've been struggling hard with getting VueJS and TinyMCE to work together. I've come to the conclusion that using directives would be the way to go.
到目前为止,我已经能够将主体作为指令参数传入,并且tinyMCE设置内容。但是,我不能让双向绑定工作。基于tinyMCE api,我也害怕我做错了。
So far I've been able to pass in the body as a directive parameter, and tinyMCE sets the content. However, I can't get the two way binding to work. I'm also afraid that I'm doing things completely wrong based on the tinyMCE api.
我认为相关的tinyMCE函数将是:
The relevant tinyMCE functions I assume would be:
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
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
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'
}
})
小提琴
https://jsfiddle.net/nf3ftm8f/
使用Vue.js 2.0,指令仅用于应用低级直接DOM操作。他们不再有这个
对Vue实例数据的引用。 (参考: https://vuejs.org/v2/guide/migration .html #Custom-Directives-simplified )
With Vue.js 2.0, the directives are only used for applying low-level direct DOM manipulations. They don't have this
reference to Vue instance data anymore. (Ref: https://vuejs.org/v2/guide/migration.html#Custom-Directives-simplified)
因此我建议改用 Component
。 / p>
TinymceComponent:
Hence I recommend to use Component
instead.
// 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实例(简化)
Vue Instance (simplified)
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视图)
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>
流量
The flows
- 首先,数据通过远程资源加载,即AJAX。已设置
说明
。 -
说明
传递给组件通过props:initValue
。 - 安装组件时,
tinymce
使用初始描述进行初始化。 - 它还会在模糊事件上设置
以获取更新的内容。
- 每当用户失去对编辑器的关注时,就会捕获一个新内容,并且该组件会发出一个事件
content-updated
,让父母知道某些事情已经发生了发生了。 - 在Html上你有
v-on:content-updated
。由于父级正在侦听内容更新
事件,因此在事件发生时将调用父方法updateDescription
。
- First the data is loaded through remote resources, i.e., AJAX. The
description
got set. - The
description
got passed down to the component viaprops: initValue
. - When the component is mounted, the
tinymce
is initialized with the initial description. - It also sets up the
on blur
event to get the updated content. - Whenever the user loses focus on the editor, a new content is captured and the component emits an event
content-updated
, letting the parent know that something has happened. - On Html you have
v-on:content-updated
. Since the parent is listening to thecontent-updated
event, the parent methodupdateDescription
will be called when the event is emited.
!!情侣重要提示!!
- 按照设计,组件具有从父到组件的单向绑定。因此,当从Vue实例更新
description
时,组件的initValue
属性也应该自动更新。 - 如果我们可以将
tinymce
编辑器中的任何用户类型传递回父Vue实例,那将是很好的但是不应该有2种方式绑定。那时你需要使用$ emit
来启动事件并通过组件通知父母。 - 你不必定义一个父项中的函数并执行
v-on:content-updated =updateDescription
。您可以通过v-on:content-updated =description = $ event
直接更新数据。$ event
具有为组件内部函数定义的参数 -newContent
参数。 - By design, the component has 1 way binding, from parent to component. So when the
description
gets updated from Vue instance, the component'sinitValue
property should be updated as well, automatically. - It would be nice if we can pass whatever the user types in
tinymce
editor back to the parent Vue instance but 2 ways bindings is not supposed. That's when you need to use$emit
to fire up events and notify parents from components. - You don't have to define a function in parent and do
v-on:content-updated="updateDescription"
. You can just directly update the data by doingv-on:content-updated="description = $event"
. The$event
has the parameter you defined for the function inside the component - thenewContent
parameter.
!!Couple Important Notes!!
希望我能清楚地解释一下。这整件事花了我两个星期的时间来弄明白!!
Hope I explained things clearly. This whole thing took me 2 weeks to figure it out!!