内容简介:前端手札——vue组件vue-tinymce开发经验分享
唠叨
最近公司在开发一个社交管理后台,看一遍线框图后发现需要富文本编辑器我便找会上两年开发的 vue-tinymce 组件,可惜的是组件支持还是vue1,所以这个组件需要升级支持vue2。然后有朋友问我为何不用现有的?因为看一圈回来发觉比较不靠谱的啊,全部都需要赋予id值(明明可以内部处理的为何要外部传入?),实在看不下去结果还是完善自己写的这个没多少收藏的库吧:)
关于 vue-tinymce
vue-tinymce 只是基于tinymce封装的vue组件,让用vue的同学能快速使用tinymce富文本编辑器。
过程
从tinymce开始
接下来分享一些开发过程中的一些问题,首先要学会 初次化 ,我们先来看看tinymce的官方例子:
<!DOCTYPE html> <html> <head> <script src="https://cloud.tinymce.com/stable/tinymce.min.js"></script> </head> <body> <textarea>Next, get a free TinyMCE Cloud API key!</textarea> <script> tinymce.init({ selector:'textarea' //or // target: document.querySelector('textarea') }); </script> </body> </html>
能看出tinymce需要引入全局才能使用,就没其他方式了?于是我找了一下 npmjs.org 有的有的,可以用import引入。
于是不用想立马写个例子试试
# index.html <!DOCTYPE html> <html> <body> <textarea>Next, get a free TinyMCE Cloud API key!</textarea> <script src="dist/main.js"></script> </body> </html> # main.js import tinymce form 'tinymce'; tinymce.init({ selector:'textarea' //or // target: document.querySelector('textarea') });
结果发现tinymce是加载出来了,但是样式和图标那些没了...好吧不折腾还是直接引入吧目前来说问题不大。(看看其他库都是直接引入,我不折腾算是对了)
好了,第一步完成了,接下来第二步是 获得/设定富文本内容 ,来看看以下代码:
# main.js tinymce.init({ selector: 'textarea', // 获得editor,当有多个textarea实例时会多次调用setup setup: (editor)=> { // 初次化编辑器 editor.on('init', ()=>{ // 设置默认值 editor.setContent('<p>Default Value!</p>'); // 注册事件 editor.on('input change undo redo', ()=>{ // 获得编辑结果 console.log(editor.getContent()); }); }); } })
上面这段是已总结怎样获得或设置富文本内容,tinymce知道怎样用就能开始写vue组件。
需要怎样的vue组件
作为组件配置当然可以自己设定的固需要 setting
的传入,可能也需要在初次化动手再自定义一些功能所以加上 setup
,再来是获得 editor
进行处理一些富文本数据。起步代码是这样的:
<template> <textarea :id="id"></textarea> </template> <script> export default { props: ['setting','setup', 'value'], data(){ return {id:'tinymce', editor:null}; } mounted(){ const setting = { ...this.setting, { selector: `#${this.id}`, setup: (editor)=> { this.setup(editor); this.editor = editor; editor.on('init', ()=>{ editor.setContent(this.value); editor.on('input change undo redo', ()=>{ this.value = editor.getContent(); }); }); } } }; tinymce.init(setting); }, beforeDestroy: function(){ tinymce.remove(this.id); } } </script>
自管理id
对比其他vue-tinymce组件都要传入id我感到很不解,因为根本没这个必要,所以接下来先解决id自管理问题。
export default { ... // 这里我用render写在template绑定:id一样可以 render(createElement){ return createElement('textarea', { attrs: { id: this.id } }); }, data(){ return { //生成id id: 'vue-tinymce-'+Date.now(), } } ... }
支持v-model双向绑定
这个简单,只要传入字段( props
)包含 value
,使用 v-model
就能从 value
获得绑定数据,然后当富文本编辑器数据跟新时使用 $emit('input', value)
方法便能通知变化跟新value。
export default { ... watchs:{ value(val){ // 当传入值变化时跟新富文本内容 tinymce.get(this.id).setContent(val); } }, mounted(){ const setting = { ...this.setting, { selector: `#${this.id}`, setup: (editor)=> { this.setup(editor); this.editor = editor; editor.on('init', ()=>{ editor.setContent(this.value); editor.on('input change undo redo', ()=>{ this.$emit('input', editor.getContent()); }); }); } } }; tinymce.init(setting); } ... }
到这里将近完成了,可惜这次问题静静地出现了:输入一个字光标就刷到最前面。接下来得解决这问题,思路我猜应该是editor的input事件触发 $emit('input')
然后进入watch调用了 editor.setContent()
方法后导致光标更新,这里解决办法是当前编辑不让触发 editor.seContent()
就不会导致光标更新(当然还有其他方法,比如记录光标位置)。
const INIT = 0; const INPUT = 1; const CHANGED = 2; export default { ... watchs:{ value(val){ // 只在外部引起变化时才跟新编辑器 if(this.status === CHANGED || selt.status === INIT) return this.status = INPUT; tinymce.get(this.id).setContent(val); } }, mounted(){ const setting = { ...this.setting, { selector: `#${this.id}`, setup: (editor)=> { this.setup(editor); this.editor = editor; editor.on('init', ()=>{ editor.setContent(this.value); editor.on('input change undo redo', ()=>{ // 只在用户输入导致事件相应时才更新value数据 if(this.status === INPUT || this.status === INIT) return this.status = CHANGED; this.$emit('input', editor.getContent()); }); }); } } }; tinymce.init(setting); } ... }
当value从外部更新时才更新编辑器内容,编辑器触发的内容更新并不需要绕一圈回来再更新编辑器,这样便能解决光标问题。
结果
就在这 vue-tinymce ,一些细节不补充,建议看源码。以下是使用方法:
安装
$ npm i -D lpreterite/vue-tinymce
使用
# index.html <div id="app"> <vue-tinymce ref="tinymce" v-model="content" :setting="setting"> </vue-tinymce> </div> <!-- in last --> <script src="node_modules/tinymce/tinymce.min.js"></script> # main.js import Vue from 'vue'; import VueTinymce from 'vue-tinymce.vue'; new Vue({ el: '#app', data: function(){ return { content: '<p>html content</p>', setting: { height: 200, language_url: "langs/zh_CN.js", block_formats: "Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;" } } } })
目录结构
dist/ - index.html - main.js - lang/ -zh_CN.js node_modules/ - tinymce/
遇到的问题
刚开始想写vue2组件我跑了一圈github也没发现比较好的例子,构建 工具 及配置直接能用的并没有,参考的倒是找到一些。webpack配置算是个麻烦事,想尽量简化工作就得动动脑子。
vue-cli 是个好东西,能帮你快速创建项目,如想创建vue的单页项目可以这样使用:
$ vue init webpack-simple my-product
可是没见到有快速创建vue组件的项目,所以这里我写了一个 lpreterite/vue-component-project 提供给大家使用。
使用方法:
$ vue init lpreterite/vue-component-project my-vue-component
一路回车之后会提示
vue-cli · Generated "my-vue-component". To get started: cd my-vue-component npm install npm run dev npm run hot.
项目就这样创建好来:ok_hand:,剩下交给你们发挥。
这遍文章算是把手上这个大项目的副产品吧 :) 。希望日后有点时间继续分享其他在经验及一些大项目下的组件,欢迎评论和PR!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端技术演进(三):前端安全
- 【前端优化】前端常见性能优化
- 【前端学习笔记】前端安全详解
- 前端监控和前端埋点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。