项目重构老管理后台,使用vue作为前端框架,对于一直使用jsp+jquery开发管理后台的我还是挺头疼的… 之后在vue官网学习了一下基础知识外加向前端同事讨教,粗略了解了vue的使用,如果文中有错误地方请多多包涵。
由于不是专业的前端开发,所以并没有使用vue-cli
脚手架,只是用的原生vue。
下面是最终效果图:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
tinyMCE下载地址:https://www.tiny.cloud/get-tiny/self-hosted/
其中tinyMCE默认为英文,如需中文需要下载语言扩展包,下载地址:https://www.tiny.cloud/get-tiny/language-packages/ 。将zh_CN.js
文件复制到langs
文件夹下
tinyMCE集成了绝大多数功能,但是调整行高的功能并没有,我们需要额外下载该插件。忘记之前在哪里找到的了,直接放上行高插件,下载地址:tinyMCE富文本编辑器line-height行高插件
该插件默认是德语,我们可以直接修改plugin.min.js
文件源码改为中文提示,找到return{type
开头的内容,修改为return{type:"listbox",text:"行间距",tooltip:"行间距",...
工具栏的配置可以参考这篇文章,介绍的很详细:TinyMCE工具栏配置详解
代码如下:
其中valid_elements
、valid_style
是将合法标签以及属性加入白名单的,我这里写的是根据策划要求来的,因人而异。官方文档说明:valid_elements,valid_style
tinymce.init({
selector: '#mytextarea',
language: 'zh_CN',
menubar: false,
valid_elements :"p[style],span[style],ul,ol,li,strong/b,em,h1,h2,h3,h4,h5,h6",
valid_style:{
"*":"color,font_size,text-align,line-height"
},
plugins:"code,textcolor,lists,lineheight,fullscreen",
toolbar: [
'undo redo | formatselect | bold italic forecolor fontsizeselect | alignleft aligncenter alignright | bullist numlist lineheightselect | code fullscreen | removeformat '
]
});
之后在html里引入这个textarea就可以了
其中通过tinyMCE.activeEditor.getContent()
以及tinyMCE.activeEditor.setContent(val)
可以手动获取、设置tinyMCE的值
<div><textarea id="mytextarea" v-model="model.content"></textarea></div>
其中需要注意的小细节: 为了方便使用,我们使用vue component将tinyMCE组件化。同时为了满足实时监控富文本内容的需求,不能采用最后在ajax方法中手动get/set内容的策略了,需要用v-model实时双向绑定。 定义传入的字段 具体代码如下: getBookmark(type:Number, normalized:Boolean):Object moveToBookmark(bookmark:Object):Boolean 10.19更新 我最终的做法是加入一个 ok 大功告成!toolbar
中的|
是用来分割工具栏的,|
和工具栏的名称中间必须有空格
,否则无法识别该按钮。
外面一定要用
组件化tinyMCE并设置双向绑定
props: ['value']
,用来接收父组件的值,当编辑器检测到有变化时调用$emit(‘input’, value)将数据写出到父组件Vue.component('tinymce', {
props: ['value'],
watch:{
value(val){
tinyMCE.activeEditor.setContent(val);
}
},
mounted: function(){
var component = this;
tinymce.init({
target: this.$el.children[0],
language: "zh_CN",
menubar: false,
branding: false,
valid_elements: "p[style],span[style],ul,ol,li,strong/b,em,h1,h2,h3,h4,h5,h6",
valid_style: {
"*":"color,font_size,text-align,line-height"
},
plugins: "code,textcolor,lists,lineheight,fullscreen",
toolbar: [
'undo redo | formatselect | bold italic forecolor fontsizeselect | alignleft aligncenter alignright | bullist numlist lineheightselect | code fullscreen | removeformat '
],
setup: function(editor) {
editor.on('input change undo redo execCommand KeyUp', function(e) {
component.$emit('input', editor.getContent());
})
}
});
},
template: ``
});
解决光标移动问题(10.19更新,解决中文输入法无法输入问题)
虽然我们已经做到了tinyMCE展示并且可以双向绑定数据,但是输入的时候会发现光标一直回到最左侧。这是因为我们输入文字时触发$emit('input', editor.getContent())
修改了value,这样就又会进入watch
,从而再次调用tinyMCE.activeEditor.setContent(val)
。这里我参考了前端手札——vue组件vue-tinymce开发经验分享这篇文章,文中采用了这里解决办法是当前编辑不让触发editor.seContent()就不会导致光标更新
。作者定义了一个status
用来记录不同状态,但是我这里测试后不可以-.-,同时作者还提出了一种思路:(当然还有其他方法,比如记录光标位置)
。于是我就按照这种思路去解决光标跳动问题,感觉更简单一些,供大家参考。我们查阅tinyMCE的api文档,发现有一个BookmarkManager,它可以记录位置并移动。
Returns a bookmark location for the current selection. This bookmark object can then be used to restore the selection after some content modification to the document.
Restores the selection to the specified bookmark.其中getBookmark
的两个参数官方文档中并没有具体说明,但是经过试验,第一个参数必须使用2
才生效。其实也是google tinymce cursor jump 然后在stackoverflow上偶尔看见的,大家有兴趣可以具体了解下Preserve caret/bookmark position in tiny while using setContentvar bm=tinyMCE.activeEditor.selection.getBookmark(2);
tinyMCE.activeEditor.setContent(val);
tinyMCE.activeEditor.selection.moveToBookmark(bm);
这样整个tinyMCE的构建以及数据双向绑定就完成了,最后在需要使用tinyMCE的页面调用该组件就可以了。
之前考虑的采用bookmark防止光标移动策略还是会有问题,因为每次修改编辑器的值其实还是会触发watch
,从而调用tinyMCE.activeEditor.setContent(val)
,我只是在前后记录、移动了光标位置,保证输入时光标不会跳到最左侧。但在chrome浏览器下,输入中文时拼音会先填充在文本框里,如下图:
这样就会触发input
从而触发watch
里的tinyMCE.activeEditor.setContent(val)
,导致输入法消失。所以这样来看,我们在编辑器里操作时是就是不应该去触发tinyMCE.activeEditor.setContent(val)
!flag
标志,在编辑器触发input undo redo execCommand
事件时将flag
置为false
,watch
的时候只有flag
为true
时才调用tinyMCE.activeEditor.setContent(val)
,并且最终都置回true
ps:后来决定不监听change
是因为change
事件需要失去焦点并且文本变化时触发,这样会导致先触发input
再触发change
,而由于数据已经在input
事件中修改,所以change
不会调用watch
重新把flag
置为true
,所以这时候的flag
就定格在了false
。
这个方法应该也不是太好,但是我不能在这一个功能上再耗太多时间了,就先这样处理了,基本满足要求了。
完整代码
Vue.component('tinymce', {
props: ['value'],
data(){
return{
flag:true
}
},
watch:{
value(val){
if(this.flag){
tinyMCE.activeEditor.setContent(val);
}
this.flag=true;
}
},
mounted: function(){
var component = this;
tinymce.init({
target: this.$el.children[0],
language: "zh_CN",
menubar: false,
branding: false,
valid_elements: "p[style],span[style],ul,ol,li,strong/b,em,h1,h2,h3,h4,h5,h6",
valid_style: {
"*":"color,font_size,text-align,line-height"
},
plugins: "code,textcolor,lists,lineheight,fullscreen",
toolbar: [
'undo redo | formatselect | bold italic forecolor fontsizeselect | alignleft aligncenter alignright | bullist numlist lineheightselect | code fullscreen | removeformat '
],
setup: function(editor) {
editor.on('input undo redo execCommand', function(e) {
component.flag=false;
component.$emit('input', editor.getContent());
})
}
});
},
template: ``
});
......
<body>
<div id="test">
<tinymce v-model="content">tinymce>
div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script src="../plugins/tinymce/tinymce.min.js">script>
<script src="../js/tinymceTemplate.js">script>
<script>
new Vue({
el:"#test",
data(){
return{
content:""
}
},
mounted:function(){
//TODO
},
methods:{
//TODO
}
});
script>
body>
写在最后
对于一个后端开发接触vue以及一些插件的使用还是很有必要的,用了才发现比以前用jsp jquery方便多了,真香!不过毕竟还是小白,用的也是非常的基础,还需不断努力。
ps:使用vue时发现有一款集成在chrome上的vue开发插件,可以实时监测vue中的数据,并且可以手动修改,很方便。附上链接:https://github.com/vuejs/vue-devtools