前端手札——vue组件vue-tinymce开发经验分享

栏目: 编程语言 · 发布时间: 7年前

内容简介:前端手札——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!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

领域驱动设计

领域驱动设计

埃文斯 / 赵俐、盛海艳、刘霞 / 人民邮电出版社 / 2010-11 / 69.00元

《领域驱动设计:软件核心复杂性应对之道》是领域驱动设计方面的经典之作。全书围绕着设计和开发实践,结合若干真实的项目案例,向读者阐述如何在真实的软件开发中应用领域驱动设计。书中给出了领域驱动设计的系统化方法,并将人们普遍接受的一些最佳实践综合到一起,融入了作者的见解和经验,展现了一些可扩展的设计最佳实践、已验证过的技术以及便于应对复杂领域的软件项目开发的基本原则。《领域驱动设计:软件核心复杂性应对之......一起来看看 《领域驱动设计》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具