codex-team / editor.js

A block-style editor with clean JSON output
https://editorjs.io
Apache License 2.0
28.6k stars 2.08k forks source link

How to use editor.js in Vue or React project? #678

Closed EricHan0723 closed 3 years ago

EricHan0723 commented 5 years ago

I want to use editorjs build a article edit system, but can't find a vuejs or react example

n0str commented 5 years ago

You can write your own wrapper. There are also several examples written by a community:

https://github.com/changjoo-park/vue-editor-js https://www.npmjs.com/package/vue-editor-js

EricHan0723 commented 5 years ago

Thank you. It helps a lot.

gohabereg commented 5 years ago

Recently a React wrapper was published by @stfy

https://github.com/stfy/react-editor.js https://www.npmjs.com/package/@stfy/react-editor.js

qiutian00 commented 5 years ago

it is so good

cossssmin commented 5 years ago

With Vue.js, if you don't want to use a third-party wrapper component, simply init the editor in the mounted() hook and assign it to window:

mounted() {
  window.editor = new EditorJS({...})
}

You can now use that object to access editor.js methods:

data() {
  return {
    content: {}
  }
},
methods: {
  save() {
    window.editor.save().then(saved => this.content = saved)
  },
},
khaydarov commented 3 years ago

For your convenience we've collected an awesome-list with third-party libraries and extensions. You can find there wrappers for React and Vue

jtlindsey commented 3 years ago

I also don't think third party wrappers are the best option. Every third party module you add to your project is one more security or privacy risk to monitor. Note it might be helpful to make a "recipes" directory with simple one page files like "Using with Nuxt.js", "Using with React.js", "Using with Angular", etc. Here is an example of how I used it in a Nuxt.js project:

Using with Nuxt.js (2.15.x)

Tested with editor.js 2.22.x and nuxt 2.15.x. You will obviously have to expand for your needs but this is the basics.

Install modules

Install all your modules: npm i --save @editorjs/editorjs @editorjs/header

Create plugin

1. Create the following in your Nuxt project plugins/editor.js

import EditorJS from '@editorjs/editorjs';
import Header from '@editorjs/header';

export default (context, inject) => {
  const defaultOptions = {
    id: '',
    data: {},
    onChange: () => {},
  }

  const editor = (options = defaultOptions) => {
    return new EditorJS({
      placeholder: 'Let`s write an awesome story!',
      /**
       * Id of Element that should contain Editor instance
       */
      holder: options.id,
      /** 
       * Available Tools list. 
       * Pass Tool's class or Settings object for each Tool you want to use 
       */
      tools: {
        header: Header,
      },
      /**
       * Previously saved data that should be rendered
       */
      data: options.data || {},
      onChange(data) {
        // pass in function from component to run on change
        options.onChange(data)
      }
    })
  };

  inject('editor', options => editor(options));
}

2. Edit your nuxt.config.js plugins block to include it:

  plugins: [
    ...
    { src: '~/plugins/editor.js', mode: 'client' },
    ...
  ],

3. Create component components/Editor.vue

<template>
  <div id="editorjs" />
</template>

<script>
export default {
  name: 'Editor',
  props: {
    existingContent: { type: Object, default: () => {} }
  },
  data() {
    return {
      editor: null,
    }
  },
  async mounted() {
    const editorOptions = {
      id: 'editorjs',
      data: this.existingContent,
      onChange: this.onChange
    };
    this.editor = this.$editor(editorOptions);
    await this.editor.isReady;
  },
  methods: {
    async onChange() {
      try {
        const updatedData = await this.editor.save();
        console.log('Article data saved: ', updatedData)
        this.$emit('contentChanged', updatedData);
      } catch (error) {
        console.log('Saving failed: ', error)
      }
    },
  }
}
</script>

4. Create component to display editor results in components/Blog.vue

<template>
  <div>
    <template v-for="block in editorContent.blocks">
      <h1
        v-if="block.type === 'header' && block.data.level === 1"
        :key="block.id"
      >{{ block.data.text }}</h1>

      <h2
        v-if="block.type === 'header' && block.data.level === 2"
        :key="block.id"
      >{{ block.data.text }}</h2>

      <p
        v-if="block.type === 'paragraph'"
        :key="block.id"
      >{{ block.data.text }}</p>
    </template>
  </div>
</template>

<script>
export default {
  name: 'Blog',
  props: {
    editorContent: { type: Object, default: () => {} },
  }
}
</script>

4. Example using in pages/index.vue

<template>
  <div>
    <Editor
      :blog-content="editorContent"
      @contentChanged="onChange"
    />
    <Blog :editor-content="editorContent" />
  </div>
</template>

<script>
import Blog from '~/components/Blog.vue'
import Editor from '~/components/Editor.vue'
const editorContent = {
  time: 1629305722425,
  blocks: [
    {
      id: 'P0gOThWo9y',
      type: 'header',
      data: {
        text: 'Editor.js',
        level: 1,
      },
    },
    {
      id: 'YsJdcKCfHt',
      type: 'paragraph',
      data: {
        text: 'Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.',
      },
    },
    {
      id: 'iIhdNHjLzc',
      type: 'header',
      data: {
        text: 'What does it mean clean data output',
        level: 2,
      },
    },
    {
      id: 'BaOtN0Tn3V',
      type: 'paragraph',
      data: {
        text: 'Classic WYSIWYG-editors produce raw HTML-markup with both content data and content appearance. On the contrary, Editor.js outputs JSON object with data of each Block. You can see an example below',
      },
    },
    {
      id: '0ReqIOJLNx',
      type: 'paragraph',
      data: {
        text: 'Given data can be used as you want: render with HTML for <code class="inline-code">Web clients</code>, render natively for <code class="inline-code">mobile apps</code>, create markup for <code class="inline-code">Facebook Instant Articles</code> or <code class="inline-code">Google AMP</code>, generate an <code class="inline-code">audio version</code> and so on.',
      },
    },
    {
      id: '7UTs8tiQqx',
      type: 'paragraph',
      data: {
        text: 'Clean data is useful to sanitize, validate and process on the backend.',
      },
    },
    {
      id: 'iFrktjRJ5I',
      type: 'paragraph',
      data: {
        text: "We have been working on this project more than three years. Several large media projects help us to test and debug the Editor, to make it's core more stable. At the same time we significantly improved the API. Now, it can be used to create any plugin for any task. Hope you enjoy. 😏",
      },
    },
  ],
  version: '2.22.2',
}

export default {
  components: { Editor, Blog },
  data() {
    return { editorContent }
  },
  methods: {
    onChange(data) {
      console.log('component content was changed...')
      this.editorContent = data;
    }
  }
}
</script>
vmangelovv commented 1 year ago

@jtlindsey Hi. I copied all your code. Can you look at this and if you can help with advice? I am using latest 2.x.x version of Nuxt image

jtlindsey commented 1 year ago

Hey @vmangelovv It could be syntax error or other issue. The only way i'll likely be able to help figure that out is to see a minimal reproduction.

  1. Create a new nuxt project using the latest version of nuxt, OR your projects version of nuxt (2.x) if you have other plugins that depend on that version.
  2. Add the the editor.js dependency code.
  3. Create your minimal example components and page
  4. Do not add any other dependencies or code.
  5. Run code, see error (usually it's easiest to solve the problem from here with minimum reproduction)
  6. Commit and push that code to a public repo
  7. Link to that repo

A lot of devs can help without you needing to do all that. Unless it's an error I frequently see, I'm usually not one of them.