富文本编辑器tinymce(@tinymce/tinymce-vue)

 

<template>
  <div class="m-exam-wrap">
    <div class="m-exam-center">
      <el-form
        :model="listForm"
        :rules="listRules"
        ref="listDialogFormRef"
        label-width="150px"
      >
        <el-form-item label="" prop="list">
          <div>
            <div>
              <div
                v-for="(item, index) in listForm.list"
                :key="item.id"
                class="m-exam-list-item"
              >
                <div class="m-exam-row-empty">
                  <span class="m-exam-row-label-empty"></span>
                  <span class="m-exam-row-info">
                    <el-button
                      type="danger"
                      icon="el-icon-delete"
                      circle
                      @click="handleDelete(item)"
                    ></el-button
                  ></span>
                </div>
                <div
                  :class="[
                    `m-exam-row ${
                      item.id === currentId && currentKey === 'question'
                        ? 'active'
                        : ''
                    }`,
                  ]"
                  @click="handleSelect(item.id, 'question')"
                >
                  <span class="m-exam-row-label">问题{
   
   { index + 1 }}</span>
                  <span class="m-exam-row-info" v-html="item.question"></span>
                </div>
                <div
                  v-for="(optionItem, optionIndex) in item.option"
                  :key="optionItem.id"
                  :class="[
                    `m-exam-row ${
                      item.id === currentId &&
                      currentKey === 'option' &&
                      currentOptionId === optionItem.id
                        ? 'active'
                        : ''
                    }`,
                  ]"
                  @click="handleSelect(item.id, 'option', optionItem.id)"
                >
                  <span class="m-exam-row-label"
                    >选项{
   
   { getLetterByNum(optionIndex) }}</span
                  >
                  <span
                    class="m-exam-row-info"
                    v-html="optionItem.value"
                  ></span>
                </div>
                <div class="m-exam-row-empty">
                  <span class="m-exam-row-label">正确答案</span>
                  <span class="m-exam-row-info">
                    <el-select v-model="item.answer" clearable>
                      <el-option
                        v-for="(optionItem, optionIndex) in item.option"
                        :key="optionItem.id"
                        :label="getLetterByNum(optionIndex)"
                        :value="getLetterByNum(optionIndex)"
                      ></el-option>
                    </el-select>
                  </span>
                </div>
                <div
                  :class="[
                    `m-exam-row ${
                      item.id === currentId && currentKey === 'analysis'
                        ? 'active'
                        : ''
                    }`,
                  ]"
                  @click="handleSelect(item.id, 'analysis')"
                >
                  <span class="m-exam-row-label">答案解析</span>
                  <span class="m-exam-row-info" v-html="item.analysis"></span>
                </div>
              </div>
            </div>
            <div>
              <el-button size="small" @click="handleAdd" type="primary"
                >增加问题</el-button
              >
            </div>
          </div>
        </el-form-item>
        <el-form-item label="">
          <el-button
            type="primary"
            size="small"
            @click="handleSubmit('listDialogFormRef', false)"
            >保存</el-button
          >
        </el-form-item>
      </el-form>
    </div>
    <div class="m-exam-right">
      <editor
        api-key="vn97n20mvo4lrz05yowxf9rm2lri5zekmem1j0v20vd1i9vz"
        :init="tinymceInit"
        v-model="currentValue"
        ref="editor"
      />
      <!-- <textarea id="tinymce" /> -->
    </div>
  </div>
</template>

<script>
import { ExchangeService } from "@/api";
import { LessonTaskService } from "@/api";
import { getTinymceInit } from "./config";
import { deepClone } from "@/util/util";
//#region tinymce
import Editor from "@tinymce/tinymce-vue";
import tinymce from "tinymce";
import "tinymce/plugins/image";
import "tinymce/themes/silver";
import "tinymce/plugins/preview";
import "tinymce/plugins/searchreplace/plugin";
import "tinymce/plugins/autolink/plugin";
import "tinymce/plugins/directionality/plugin";
import "tinymce/plugins/visualblocks/plugin";
import "tinymce/plugins/visualchars/plugin";
import "tinymce/plugins/fullscreen/plugin";
import "tinymce/plugins/link/plugin";
import "tinymce/plugins/media/plugin";
import "tinymce/plugins/template/plugin";
import "tinymce/plugins/code/plugin";
import "tinymce/plugins/codesample/plugin";
import "tinymce/plugins/table/plugin";
import "tinymce/plugins/charmap/plugin";
import "tinymce/plugins/pagebreak/plugin";
import "tinymce/plugins/nonbreaking/plugin";
import "tinymce/plugins/anchor/plugin";
import "tinymce/plugins/insertdatetime/plugin";
import "tinymce/plugins/advlist/plugin";
import "tinymce/plugins/lists/plugin";
import "tinymce/plugins/wordcount/plugin";
import "tinymce/plugins/help/plugin";
import "tinymce/plugins/emoticons/plugin";
import "tinymce/plugins/autosave/plugin";
import "tinymce/plugins/autoresize/plugin";
import "tinymce/plugins/emoticons/js/emojis";
import "tinymce/icons/default/icons";
import "tinymce/skins/ui/oxide/skin.min.css";
import "tinymce/skins/ui/oxide/content.min.css";
import "tinymce/skins/content/default/content.min.css";
import "tinymce/models/dom/model";
import "./plugins/langs/zh_CN";
import "./plugins/kityformula-editor/kityformula-editor";
//#endregion

import "./index.css";

export default {
  data() {
    return {
      listForm: {
        id: "",
        list: [
          {
            id: Date.now(),
            question: "<div>2</div>",
            option: [
              {
                id: 0,
                value: "<div>3</div>",
              },
              {
                id: 1,
                value: "<div>4</div>",
              },
              {
                id: 2,
                value: "<div>5</div>",
              },
              {
                id: 3,
                value: "<div>6</div>",
              },
            ],
            answer: "",
            analysis: "<div>7</div>",
          },
        ],
      },
      //列表对话框验证规则
      listRules: {},
      listDialogType: "edit",
      currentValue: "1",
      currentId: "",
      currentKey: "",
      currentOptionId: "",
      isOption: false,
      tinymceInit: getTinymceInit(),
    };
  },
  components: {
    editor: Editor,
  },
  mounted() {
    console.log(this.$refs.editor);
    this.initEditor();
  },
  watch: {
    currentValue(newData, oldData) {
      if (this.isOption) {
        const resultItemIndex = this.listForm.list.findIndex(
          (item) => item.id === this.currentId
        );
        if (resultItemIndex >= 0) {
          const resultOptionIndex = this.listForm.list[
            resultItemIndex
          ].option.findIndex((item) => item.id === this.currentOptionId);
          if (resultOptionIndex >= 0) {
            this.listForm.list[resultItemIndex].option[resultOptionIndex] = {
              ...this.listForm.list[resultItemIndex].option[resultOptionIndex],
              value: newData,
            };
            this.listForm.list = deepClone(this.listForm.list);
          }
        }
      } else {
        const resultItemIndex = this.listForm.list.findIndex(
          (item) => item.id === this.currentId
        );
        if (resultItemIndex >= 0) {
          this.listForm.list[resultItemIndex][this.currentKey] = newData;

          this.listForm.list = deepClone(this.listForm.list);
        }
      }
    },
  },
  methods: {
    initEditor() {
      //tinymce.init(getTinymceInit());
      // var aaa = tinymce.init({
      //     selector: '#tinymce',
      //     //skin:'oxide-dark',
      //     language:'zh_CN',
      //     plugins: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template advcode codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help emoticons autosave bdmap indent2em autoresize formatpainter axupimgs importword kityformula-editor',
      //     toolbar: 'code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | \
      //      styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
      //      table image media charmap emoticons hr pagebreak insertdatetime print preview | fullscreen | bdmap indent2em lineheight formatpainter axupimgs importword kityformula-editor',
      //     height: 650, //编辑器高度
      //     min_height: 400,
      //     /*content_css: [ //可设置编辑区内容展示的css,谨慎使用
      //         '/static/reset.css',
      //         '/static/ax.css',
      //         '/static/css.css',
      //     ],*/
      //     fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
      //     font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;知乎配置=BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif;小米配置=Helvetica Neue,Helvetica,Arial,Microsoft Yahei,Hiragino Sans GB,Heiti SC,WenQuanYi Micro Hei,sans-serif',
      //     link_list: [
      //         { title: '预置链接1', value: 'http://www.tinymce.com' },
      //         { title: '预置链接2', value: 'http://tinymce.ax-z.cn' }
      //     ],
      //     image_list: [
      //         { title: '预置图片1', value: 'https://www.tiny.cloud/images/[email protected]' },
      //         { title: '预置图片2', value: 'https://www.baidu.com/img/bd_logo1.png' }
      //     ],
      //     image_class_list: [
      //     { title: 'None', value: '' },
      //     { title: 'Some class', value: 'class-name' }
      //     ],
      //     //importcss_append: true,
      //     //自定义文件选择器的回调内容
      //     file_picker_callback: function (callback, value, meta) {
      //         if (meta.filetype === 'file') {
      //           callback('https://www.baidu.com/img/bd_logo1.png', { text: 'My text' });
      //         }
      //         if (meta.filetype === 'image') {
      //           callback('https://www.baidu.com/img/bd_logo1.png', { alt: 'My alt text' });
      //         }
      //         if (meta.filetype === 'media') {
      //           callback('movie.mp4', { source2: 'alt.ogg', poster: 'https://www.baidu.com/img/bd_logo1.png' });
      //         }
      //     },
      //     //为内容模板插件提供预置模板
      //     templates: [
      //         { title: '模板1', description: '介绍文字1', content: '模板内容' },
      //         { title: '模板2', description: '介绍文字2', content: '<div class="mceTmpl"><span class="cdate">CDATE</span>,<span class="mdate">MDATE</span>,我的内容</div>' }
      //     ],
      //     //content_security_policy: "script-src *;",
      //     extended_valid_elements:'script[src]',
      //     //
      //     template_cdate_format: '[CDATE: %m/%d/%Y : %H:%M:%S]',
      //     template_mdate_format: '[MDATE: %m/%d/%Y : %H:%M:%S]',
      //     autosave_ask_before_unload: false,
      //     toolbar_mode : 'wrap',
      //     automatic_uploads : false,
      //     images_upload_base_path: '/demo',
      //     images_upload_handler: function (blobInfo, succFun, failFun) {
      //         succFun('/demo/images/img.jpg');
      //     },
      //     //icons:'ax-color',

      // });
    },
    //增加问题
    handleAdd() {
      console.log(666, this.listForm.list);

      this.listForm.list.push({
        id: Date.now(),
        question: "<div>2</div>",
        option: [
          {
            id: 0,
            value: "<div>3</div>",
          },
          {
            id: 1,
            value: "<div>4</div>",
          },
          {
            id: 2,
            value: "<div>5</div>",
          },
          {
            id: 3,
            value: "<div>6</div>",
          },
        ],
        answer: "",
        analysis: "<div>7</div>",
      });
    },
    //删除问题
    handleDelete(deleteItem) {
      this.listForm.list = this.listForm.list.filter(
        (item) => item.id !== deleteItem.id
      );
    },
    //选择组件
    handleSelect(id, key, optionId) {
      const resultItem = this.listForm.list.find((item) => item.id === id);
      if (resultItem) {
        if (typeof optionId !== "undefined") {
          const resultOptionItem = resultItem.option.find(
            (item) => item.id === optionId
          );
          if (resultOptionItem) {
            this.currentValue = resultOptionItem.value;
          }
          this.isOption = true;
        } else {
          this.currentValue = resultItem[key];
          this.isOption = false;
        }

        this.currentId = id;
        this.currentKey = key;
        this.currentOptionId = optionId;
      }
    },
    //保存
    handleSubmit(formName, isOpenDesignDialog) {
      console.log("提交");
      console.log(666, this.currentValue);
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          const formatValues = { ...this.listForm };
          const id = 1;
          if (this.listDialogType === "add") {
          } else if (this.listDialogType === "edit") {
            ExchangeService.ruleEdit(
              {
                ...formatValues,
              },
              id
            ).then(async (res) => {
              if (res.code === 200) {
                this.listDialogVisible = false;
                this.$message.success("操作成功");
                this.loadList();
              }
            });
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    //数字映射字母
    getLetterByNum(num) {
      const hook = {
        0: "A",
        1: "B",
        2: "C",
        3: "D",
        4: "E",
        5: "F",
        6: "G",
      };

      return hook[num] ? hook[num] : "";
    },
  },
};
</script>

<style></style>

config.js:

import { PictureService } from "@/api";

function convertBase64UrlToBlob(urlData) {
  let bytes = window.atob(urlData.split(",")[1]); //去掉url的头,并转换为byte
  //处理异常,将ascii码小于0的转换为大于0
  let ab = new ArrayBuffer(bytes.length);
  let ia = new Uint8Array(ab);
  for (var i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i);
  }

  return new Blob([ab], {
    type: "image/jpg",
  });
}

const getTinymceInit = () => {
  return {
    selector: "#tinymce",
    language: "zh_CN",
    //media template pagebreak anchor nonbreaking codesample
    plugins:
      "preview searchreplace autolink directionality visualblocks visualchars fullscreen image link code table charmap insertdatetime advlist lists wordcount help emoticons autosave autoresize kityformula-editor",
    toolbar:
      "code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link | alignleft aligncenter alignright alignjustify outdent indent | \
    styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
    table image charmap emoticons insertdatetime print | fullscreen | lineheight kityformula-editor",

    // plugins: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image imagetools link media template advcode codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help emoticons autosave bdmap indent2em autoresize formatpainter axupimgs importword kityformula-editor',
    // toolbar: 'code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | \
    //  styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
    //  table image imagetools media charmap emoticons hr pagebreak insertdatetime print preview | fullscreen | bdmap indent2em lineheight formatpainter axupimgs importword kityformula-editor',

    height: 650, //编辑器高度
    min_height: 400,
    /*content_css: [ //可设置编辑区内容展示的css,谨慎使用
    '/static/reset.css',
    '/static/ax.css',
    '/static/css.css',
    ],*/
    fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
    font_formats:
      "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",
    importcss_append: true,
    //自定义文件选择器的回调内容
    file_picker_callback: function (callback, value, meta) {
      if (meta.filetype === "file") {
        callback("https://www.baidu.com/img/bd_logo1.png", {
          text: "My text",
        });
      }
      if (meta.filetype === "image") {
        callback("https://www.baidu.com/img/bd_logo1.png", {
          alt: "My alt text",
        });
      }
      if (meta.filetype === "media") {
        callback("movie.mp4", {
          source2: "alt.ogg",
          poster: "https://www.baidu.com/img/bd_logo1.png",
        });
      }
    },
    link_list: [
      { title: "预置链接1", value: "http://www.tinymce.com" },
      { title: "预置链接2", value: "http://tinymce.ax-z.cn" },
    ],
    image_list: [
      {
        title: "预置图片1",
        value: "https://www.tiny.cloud/images/[email protected]",
      },
      {
        title: "预置图片2",
        value: "https://www.baidu.com/img/bd_logo1.png",
      },
    ],
    image_class_list: [
      { title: "None", value: "" },
      { title: "Some class", value: "class-name" },
    ],
    object_resizing: true,
    toolbar_mode: "wrap",
    toolbar_sticky: true,
    autosave_ask_before_unload: false,
    images_upload_handler: function (blobInfo, succFun, failFun) {
      return new Promise((resolve, reject) => {
        let formdata = new FormData();
        formdata.append("pic_type", 3);
        console.log(formdata);
        console.log("filename", blobInfo.filename());
        const filename = blobInfo.filename();
        if (filename.includes("blobid")) {
          //formdata.append("file", "data:image/png;base64," + blobInfo.base64());
          let imgeFile = convertBase64UrlToBlob(
            "data:image/png;base64," + blobInfo.base64()
          );
          formdata.append("file", imgeFile, new Date().getTime() + ".jpg");

          // document
          //   .getElementById("img")
          //   .setAttribute("src", "data:image/png;base64," + blobInfo.base64());
        } else {
          formdata.append("file", blobInfo.blob());
        }
        PictureService.upload(formdata)
          .then((res) => {
            console.log(res);
            if (res.code === 200) {
              resolve("https://static.bestvedu.com/images/" + res.data.file_id);
            }
          })
          .catch((err) => {
            reject(err);
          });
      });
    },
  };
};

export { getTinymceInit };

富文本编辑tinymce公式插件,图片可以拖动改变大小,汉化-Javascript文档类资源-CSDN下载


 

链接:https://pan.baidu.com/s/1ZDRkdjH8gbG8374G0xe96g
提取码:h9c6

猜你喜欢

转载自blog.csdn.net/xutongbao/article/details/125387308