tinymce编辑器结合vue开发模板库

699 阅读1分钟
针对项目需求,苦苦研究tinymce英文api一周时间,终于搞清楚了如何开发,不定期分享一下开发经验。首先我们讲如何在vue中方便的开发插件。

tinymce 此页英文文档:https://www.tiny.cloud/docs/configure/editor-appearance/

先看一下效果:

模板库维护页面:

编辑器模板库呈现效果:

1、项目说明

本项目基于vue开发,tinymce没有针对vue专属的插件开发方法,只能用原生js编辑插件然后导入插件,但是我不想放弃element-ui这么强大的vue组件库,耗费精力去写样式,所以我简化操作,直接在引入tinymce时使用setup方法,在方法内注入按钮和对应的操作,代码如下:

//注入模板库

setup: (editor) => {            //注入模板库            editor.ui.registry.getAll().icons.templatestore || editor.ui.registry.addIcon('templatestore',              `<svg t="1589192112197" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4265" width="20" height="20">              <path d="M85.344 0v1024h853.344V0H85.344z m768 938.656H170.688V85.312h682.656v853.344z" p-id="4266"></path><path d="M256 170.656h512v170.656H256V170.656zM426.656              426.656H768V512H426.656v-85.344zM426.656 597.344H768v85.344H426.656v-85.344zM426.656 768H768v85.344H426.656V768zM256 426.656h85.344v426.656H256V426.656z"              p-id="4267"></path></svg>`              );
            editor.ui.registry.addButton('templatestore', {              icon: 'templatestore',              tooltip: '模板库',              onAction: () => {                this.$refs.store.open();              }            });          },

//引入模板库组件
<template>  <div class="tinymce-box">    <!-- <button @click="inset">插入</button> -->    <editor v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick">    </editor>    //模板库
    <template-store ref="store" @interpositionFun="insertTemplate"></template-store>
  </div>

对如何引用vue组件我就不在这里详细描述了,组件内的代码给大家呈现一下,都是基于element组件库的

<template>  <el-dialog title="模板库" :visible.sync="dialogVisible" width="820px">    <div class="template-store">      <el-form :inline="true" :model="form" class="demo-form-inline">        <el-form-item label="模板名称">          <el-input v-model="form.templateName" placeholder="模板名称"></el-input>        </el-form-item>        <el-form-item label="是否公开">          <el-select v-model="form.isPublic" placeholder="是否公开">            <el-option label="是" value="1"></el-option>            <el-option label="否" value="0"></el-option>          </el-select>        </el-form-item>        <el-form-item>          <el-button type="primary" @click="fetchList" size="mini">查询</el-button>        </el-form-item>        <el-button type="primary" @click="onSubmit(true)" size="mini" style="float:right;margin-top:4px">插入</el-button>        <el-button type="primary" @click="onSubmit(false)" size="mini" style="float:right;margin:4px 4px 0 0">替换</el-button>      </el-form>      <div class="dialog_content_list">        <span v-for="(item, index) in tableData" :key="index">          <div :class="item.isAction ? 'dialog_list_item select_list_item' : 'dialog_list_item'" @click="selectTemplate(item, index)">            <el-image :src="item.coverUrls || defautUrl"></el-image>            <div class="dialog_list_item_tit" :title="item.templateName || '暂无'">{{ item.templateName || '暂无' }}</div>            <time>{{ item.createTime }}</time>            <span class="sanjiao"></span>          </div>        </span>      </div>      <div class="pagination_box">        <el-pagination          :current-page.sync="page.current"          :page-size="page.size"          @current-change="paginationCurrentChange"          @size-change="paginationSizeChange"          layout="total, sizes ,prev, pager, next, jumper"          :total="page.total">        </el-pagination>      </div>    </div>  </el-dialog></template>
<script>  import {    getTemplate  } from '@/api/yc/template'
  export default {    name:'templateStore',    data() {      return {        dialogVisible:false,        value:'',
        page: {          total: 0, // 总页数          currentPage: 1, // 当前页数          pageSize: 8 // 每页显示多少条        },
        tableData:[],        tableIndex:'',
        form:{          templateName:'',          isPublic:'',          content:'',        },        defautUrl: require('@/assets/images/default_audio.jpg'),      }    },    created(){      this.fetchList();    },    methods: {      open(){        this.dialogVisible = true      },      fetchList(){        getTemplate(Object.assign({          current: this.page.currentPage,          size: this.page.pageSize        }, this.form)).then(({data:res}) => {          this.tableData = res.data.records.map(item=>{            item.isAction = false;            return item;          });          this.page.total = res.data.total        })      },      //确定选择      onSubmit(status){        if(!this.tableIndex){          this.$message.error('请选择模板')          return false        }
        this.$emit('interpositionFun',{          data:this.tableData[this.tableIndex].content,          status:status,        });        this.dialogVisible = false;      },      selectTemplate (item, index) {
        if(this.tableIndex === index){          this.tableData[index].isAction = false;          this.tableIndex = '';          return        }
        if(this.tableIndex || this.tableIndex === 0){          this.tableData[this.tableIndex].isAction = false;        }
        this.tableIndex = index;        this.tableData[index].isAction = true;      },      // 分页      paginationSizeChange (val) {        this.page.size = val        this.fetchList()      },      paginationCurrentChange (val) {        this.page.current = val        this.fetchList()      },    }  }</script>
<style lang="scss">$color: #e5e5e5;.template-store{  .dialog_content_list {    margin-top: 10px;    .dialog_list_item {      display: inline-block;      margin-right: 14px;      margin-bottom: 20px;      padding: 10px;      border: 1px solid $color;      position: relative;      overflow: hidden;      cursor: pointer;      max-width: 180px;      .el-image {        width: 160px;        height: 120px;      }      .dialog_list_item_tit {        font-size: 14px;        color: #333;        width: 100%;        overflow: hidden;        text-overflow: ellipsis;        white-space: nowrap;        line-height: 26px;      }      time {        color: #9a9a9a;        font-size: 12px;      }      .sanjiao {        display: inline-block;        width: 50px;        height: 20px;        background: $color;        position: absolute;        top: -6px;        right: -14px;        transform: rotate(45deg);        &::before {          display: inline-block;          content: '✓';          color: #fff;          position: absolute;          top: 1px;          right: 15px;          transform: rotate(-45deg);        }      }    }    .select_list_item {      border-color: #268bff;      .sanjiao {        background: #268bff;      }    }  }  .pagination_box {    text-align: right;    padding-bottom: 20px;  }}</style>

如果想更好的封装其实也是可以的,但是我想用的插件可能就只有模板库、图片库,所以暂时就这样吧。

下篇我们讲一下如何使用tinymce快捷键