VueJS 和 tinyMCE,自定义指令
VueJS and tinyMCE, custom directives
我一直在努力让 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);
和
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
试试这个:
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" 中,以便您可以从更改事件回调中访问它。
在 Vue.js 2.0 中,指令仅用于应用 low-level 直接 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>
流量
- 首先通过远程资源加载数据,即AJAX。
description
已设置。
description
通过 props: initValue
传递给组件。
- 安装组件时,
tinymce
使用初始描述进行初始化。
- 它还设置了
on blur
事件来获取更新的内容。
- 只要用户在编辑器上失去焦点,就会捕获新内容并且组件会发出事件
content-updated
,让 parent 知道发生了什么事。
- 在 Html 你有
v-on:content-updated
。由于 parent 正在监听 content-updated
事件,因此 parent 方法 updateDescription
将在事件发出时被调用。
!!重要说明!!
- 根据设计,组件有 1 种绑定方式,从 parent 到组件。因此,当
description
从 Vue 实例更新时,组件的 initValue
属性 也应该自动更新。
- 如果我们可以将用户在
tinymce
编辑器中键入的任何内容传递回 parent Vue 实例,那就太好了,但是不应该有 2 种绑定方式。那时您需要使用 $emit
来启动事件并从组件通知 parents。
- 您不必在 parent 中定义函数并执行
v-on:content-updated="updateDescription"
。您可以通过 v-on:content-updated="description = $event"
直接更新数据。 $event
具有您为组件内的函数定义的参数 - newContent
参数。
希望我解释清楚了。这整件事花了我 2 周的时间才弄明白!!
这是 Vue 的 Tinymce 组件。
http://jsbin.com/pucubol/edit?html,js,output
了解 v-model 和自定义输入组件也很好:
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>
现在有一个 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. The init section is the same as the default init statement except you do not need the selector. For an example see the documentation 的 API 密钥。
我一直在努力让 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);
和
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
试试这个:
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" 中,以便您可以从更改事件回调中访问它。
在 Vue.js 2.0 中,指令仅用于应用 low-level 直接 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>
流量
- 首先通过远程资源加载数据,即AJAX。
description
已设置。 description
通过props: initValue
传递给组件。- 安装组件时,
tinymce
使用初始描述进行初始化。 - 它还设置了
on blur
事件来获取更新的内容。 - 只要用户在编辑器上失去焦点,就会捕获新内容并且组件会发出事件
content-updated
,让 parent 知道发生了什么事。 - 在 Html 你有
v-on:content-updated
。由于 parent 正在监听content-updated
事件,因此 parent 方法updateDescription
将在事件发出时被调用。
!!重要说明!!
- 根据设计,组件有 1 种绑定方式,从 parent 到组件。因此,当
description
从 Vue 实例更新时,组件的initValue
属性 也应该自动更新。 - 如果我们可以将用户在
tinymce
编辑器中键入的任何内容传递回 parent Vue 实例,那就太好了,但是不应该有 2 种绑定方式。那时您需要使用$emit
来启动事件并从组件通知 parents。 - 您不必在 parent 中定义函数并执行
v-on:content-updated="updateDescription"
。您可以通过v-on:content-updated="description = $event"
直接更新数据。$event
具有您为组件内的函数定义的参数 -newContent
参数。
希望我解释清楚了。这整件事花了我 2 周的时间才弄明白!!
这是 Vue 的 Tinymce 组件。 http://jsbin.com/pucubol/edit?html,js,output
了解 v-model 和自定义输入组件也很好: 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>
现在有一个 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. The init section is the same as the default init statement except you do not need the selector. For an example see the documentation 的 API 密钥。