带你定义自己的 editor.js 工具 - 扩展自定义

3,395 阅读5分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战

前言

前几天简单的介绍了一款富文本编辑器 - Editor.js ,观看本文章之前可以先去了解一下简单的自定义,因为本文主要是在上次的基础上进行自定义扩展,文章链接: 带你定义自己的 editor.js 工具 - 掘金 (juejin.cn)

本文主要带大家来实现三个扩展功能:暂存数据以及回显存储数据校验小工具自定义样式

暂存数据以及回显

保存数据

上文中有提到过通过类中的save函数我们能自定义块输出的保存数据

image.png 并且我们为了方便操作数据将数据都绑定在了类底下的一个data属性中:

image.png 并且可以通过input上特有的onchange事件实时改变data.value的值:

image.png 这样编辑器就会把我们更改的数据保存起来,所以现在我们要先来找一个地方存放我们的数据。

这里因为没有后端的支持,所以暂时先用Window.localStorage来保存数据,接着有了保存数据的地方,我们就要来获取我们的数据,我们先定义一个保存按钮

image.png

在我们的editor实例上,有一个editor.save()方法存放着我们输入的所有数据,要注意这个方法是个异步方法,我们需要用 .then 的方式来获取数据

 editor.save().then((outputData) => { console.log(outputData); }

image.png 可以看到我们自定义的stars块,并且其中含有数据 value,然后我们就可以把数据保存到 window.localStorage 当中

数据回显

EditorJS 在实例化的时候提供了一个属性 data,顾名思义,我们只需要将刚刚获取到的outputData赋值给它,就能够在初始化的时候加载之前的内容,这样,哪怕是刷新也不会丢失之前的输入内容,进一步的数据保存就需要后端数据库的支持了

const editor = new EditorJS({
    holder: 'editorjs',
    data: storage.getData('noteData') || '',
});

存储数据校验

官方文档中还提供了 Saved data validation 数据检验的方法,比如说上面我保存进去的数据可以发现,第二个块的数据为空格,这种不符合条件的数据我们完全可以通过数据检验来取消它的保存。

validate(savedData) :这个方法会将保存的data作为参数传入进去,在里面我们就可以做一些基础的数据校验:

validate(savedData) {
    console.log(savedData);
    if (!savedData.value.trim()){
        return false;
    }
    return true;
}

image.png 可以看到,在添加了数据校验之后,我们的保存方法就不会将不满足条件的数据返回出来,这样也不会被存入window.localStorage。基于这个方法,我们还可以通过定义正则来做一些比较复杂的数据校验,比如说数据格式不为正确的网址就不保存等等,这样就能够实现存储数据的校验

小工具自定义样式

如果有使用过这个富文本编辑器的话,应该会发现编辑器还存在一个小工具

13287835755815544.gif

正常的文本只有三个小工具,图片的话则有六个小工具,通过点击不同的工具也能够实现图片样式的更改,并且,这个更改是会被保存下来的,会当成一种状态作为图片的数据之一。

image.png 对于我们的自定义块,官方也提供给我们自定义小工具的功能,这次就来自定义一个改变我们stars样式的小工具,点击过后会更改input框的样式和前面的小图标,最后我们要实现一个这样的效果:

13287838862816798.gif

我们可以在我们的类中添加一个 renderSettings() 方法,这个方法的返回值会直接影响到小工具的生成,除了官方默认的两个移动和一个删除,其他工具我们都可以自定义。

首先和块的图标一样,我们要先给我们的工具一个图标和名称,一样的,我们要将他挂载到类的实例底下,这样方便我们在类的每个地方使用:

this.settings = [{
    name: "starsError",
    icon: `<svg>...</svg>`,
}];

然后我们就可以来定义我们的 renderSettings() 方法

renderSettings() {
    const wrapper = document.createElement("div");

    this.settings.forEach((tune) => {
        let button = document.createElement("div");
        button.classList.add(this.api.styles.settingsButton);
        button.classList.toggle(
            this.api.styles.settingsButtonActive,
            this.data[tune.name]
        );
        button.innerHTML = tune.icon;
        wrapper.appendChild(button);
        button.addEventListener("click", () => {
            this._toggleTune(tune.name);
            button.classList.toggle(this.api.styles.settingsButtonActive);
        });
    });

    return wrapper;
}

toggle 函数如果传参的话会根据参数去添加或者删除类名,如果没有传参则会去判断当前当前按钮是否有某个类名,有的话就移出,没有的话就添加,然后this.api.styles.settingsButtonActive是官方提供给我们的一个参数,

button.classList.toggle(
    this.api.styles.settingsButtonActive,
    this.data[tune.name]
);

等同于:

button.classList.toggle(
    'cdx-settings-button--active',
    this.data[tune.name]
);

引入api只是能更方便的使用一些官方提供的样式,之后如果有机会在来专门讲讲这个。

然后其中一样的,我们要循环遍历小工具列表然后将其 append 进一个父容器当中,最后将这个父容器 return 出去就可以了,其中绑定监听事件,我们需要去判断当前的按钮是激活状态还是未激活状态,然后切换他们的值

关于其中判断按钮是否激活的这个值,我们需要像数据一样存储到我们的data当中去,这样才能保证它是一个会被保存下来的状态

 this.data = {
    value: data.value || '',
    starsError: data.starsError || false,
};

然后在 _toggleTune() 函数中,我们去修改这个值,并且在激活状态下,我们要在这个块元素下添加一个类名,这个类名当中我们就可以去预设一些样式,这样就可以在点击之后展示出来了

/**
 * @private
 * Click on the Settings Button
 * @param {string} tune — tune name from this.settings
 */
_toggleTune(tune) {
    this.data[tune] = !this.data[tune];
    this._acceptTuneView();
}

/**
 * Add specified class corresponds with activated tunes
 * @private
 */
_acceptTuneView() {
    this.settings.forEach((tune) => {
        this.wrapper.classList.toggle(tune.name, !!this.data[tune.name]);
    });
}

image.png 查看一眼 window.localStorage 其中数据成功存储进去并且会随着点击发生变化这样这个小工具就算是成功了

image.png

总结

本篇文章对在上一篇的基础上做了扩展,新手还是建议先跟着上一篇文章自定义一个块,然后再来添加这些附加功能。然后如果有使用这个插件的小伙伴有什么新奇的功能想要实现,也可以提出来,我会尽力帮忙实现,也算是一种锻炼。

带你定义自己的 editor.js 工具 - 掘金 (juejin.cn)