zoukankan      html  css  js  c++  java
  • 工作笔记四——vueJS在移动端使用富文本编辑器

    本文主要介绍vue移动端使用富文本编辑器的使用及常见问题处理。参考组件vue-html5-editor。

    本例主要基于vue-cli脚手架创建。更多vue相关应用请参考:https://github.com/JerryYuanJ/a-vue-app-template

    1.项目创建与初始化

    创建一个vue-cli项目,建议在安装的时候不要使用ESLINT做代码检查,练习的项目不需要这种检查机制,会很浪费时间。还有一些自动化测试的插件也最好不要装,影响效率。

    在安装好脚手架的依赖后,要执行 npm install vue-html5-editor -S 来安装这个富文本插件,由于这个富文本插件的图标是依赖font-awesome.css的,所以要npm install font-awesome.css 安装这个css然后在main.js中引入这个css   import   "font-awesome/css/font-awesome.css"

    2.使用vue-html5-editor富文本编辑器

               新建一个common文件夹用于存放我们的工具类js文件,然后将下面的代码copy进去:

    /**
     * author: Joker
     * creationDate: 2018/1/22
     * usage:
     */
    import Vue from 'vue'
    import VueHtml5Editor from 'vue-html5-editor'
    export default function () {
      let opt = {
        // 全局组件名称,使用new VueHtml5Editor(options)时该选项无效
        name: "vue-html5-editor",
        // 是否显示模块名称,开启的话会在工具栏的图标后台直接显示名称
        showModuleName: true,
        // 自定义各个图标的class,默认使用的是font-awesome提供的图标
        icons: {
          text: "fa fa-pencil",
          color: "fa fa-paint-brush",
          font: "fa fa-font",
          align: "fa fa-align-justify",
          list: "fa fa-list",
          link: "fa fa-chain",
          unlink: "fa fa-chain-broken",
          tabulation: "fa fa-table",
          image: "fa fa-file-image-o",
          hr: "fa fa-minus",
          eraser: "fa fa-eraser",
          undo: "fa-undo fa",
          "full-screen": "fa fa-arrows-alt",
          info: "fa fa-info",
        },
        // 配置图片模块
        image: {
          // 文件最大体积,单位字节  
          sizeLimit: 512 * 1024 * 10,
          // 上传参数,默认把图片转为base64而不上传
          // upload config,default null and convert image to base64
          upload: {
            url: null,
            headers: {},
            params: {},
            fieldName: {}
          },
          // 压缩参数,默认使用localResizeIMG进行压缩,设置为null禁止压缩
          // width和height是文件的最大宽高
          compress: {
             600,
            height: 600,
            quality: 80
          },
          // 响应数据处理,最终返回图片链接
          uploadHandler(responseText){
            //default accept json data like  {ok:false,msg:"unexpected"} or {ok:true,data:"image url"}
            var json = JSON.parse(responseText);
            console.info(json);
            if (!json.ok) {
              alert(json.msg)
            } else {
              return json.data
            }
          }
        },
        // 语言,内建的有英文(en-us)和中文(zh-cn)
        language: "zh-cn",
        // 自定义语言
        i18n: {
          "zh-cn": {
            "align": "对齐方式",
            "image": "图片",
            "list": "列表",
            "link": "链接",
            "unlink": "去除链接",
            "table": "表格",
            "font": "文字",
            "full screen": "全屏",
            "text": "排版",
            "eraser": "格式清除",
            "info": "关于",
            "color": "颜色",
            "please enter a url": "请输入地址",
            "create link": "创建链接",
            "bold": "加粗",
            "italic": "倾斜",
            "underline": "下划线",
            "strike through": "删除线",
            "subscript": "上标",
            "superscript": "下标",
            "heading": "标题",
            "font name": "字体",
            "font size": "文字大小",
            "left justify": "左对齐",
            "center justify": "居中",
            "right justify": "右对齐",
            "ordered list": "有序列表",
            "unordered list": "无序列表",
            "fore color": "前景色",
            "background color": "背景色",
            "row count": "行数",
            "column count": "列数",
            "save": "确定",
            "upload": "上传",
            "progress": "进度",
            "unknown": "未知",
            "please wait": "请稍等",
            "error": "错误",
            "abort": "中断",
            "reset": "重置"
          }
        },
        // 隐藏不想要显示出来的模块
        hiddenModules: [],
        // 自定义要显示的模块,并控制顺序
        visibleModules: [
          "text",
          "color",
          "font",
          "align",
          "list",
          "link",
          "unlink",
          "tabulation",
          "image",
          "hr",
          "eraser",
          "undo",
          "full-screen",
          "info",
        ],
        // 扩展模块,具体可以参考examples或查看源码
        // extended modules
        modules: {
          //omit,reference to source code of build-in modules
        }
      };
      Vue.use(VueHtml5Editor, opt);
    }
    

    接着在main.js中引入这个初始化的函数:

    import initRichText from './common/initHTMLEditor';  
    initRichText();

    准备工作已经完成了,我们可以使用这个组件了:

        <template>  
          <div class="content">  
            <vue-html5-editor :content="content" :height="400"  
                              @change="updateData"></vue-html5-editor>  
          
          </div>  
        </template>  
        <style scoped>  
          
        </style>  
        <script>  
          export default {  
            data(){  
              return {content: '请输入文章内容'}  
            },  
            methods: {  
              updateData(e = ''){  
                this.content = e;  
                console.info(e);  
              }  
            }  
          }  
        </script>  

    这个height属性是设置内容区的高度,content是内容区的数据内容,@change事件是内容区的监听事件,会在发生变化时触发,该函数接收一个参数,表示当前编辑器中的内容。运行结果如下(这里对图片的操作是转成base64的字符串):


     

    3.常见问题解决

    a.自定义工具栏的模块

    如果不想要显示这么多的工具,则只要配置visibleModules即可:

    b.工具栏的样式修改

    在移动端我们通常希望工具栏可以固定不动,并且显示在页面最下方,这时候我们要修改该组件的核心js里面的样式代码:

    主要是将

        var template$9 = "<div class="vue-html5-editor" :class="{'full-screen':fullScreen}".......省略很长的代码....)  

        __$styleInject(`.vue-html5-editor,.vue-html5-editor *{box-sizing:border-box}.....省略很长的代码......)  

    分别用下面两个代替:

    1.组件的字符串模板

        var  temlate$9=`  
         <div class="vue-html5-editor" :class="{'full-screen':fullScreen}" :style="{'z-index':zIndex}">  
               
             <div class="content" ref="content" :style="contentStyle" contenteditable  
                  @click="toggleDashboard(dashboard)"></div>  
                    
             <div class="toolbar" :style="{'z-index':zIndex+1}" ref="toolbar">  
               <ul>  
                 <template v-for="module in modules">  
                   <li :title="locale[module.i18n]" @click="activeModule(module)"><span class="icon"  
                                                                                        :class="module.icon"></span>  
                     <template v-if="showModuleName === undefined ? defaultShowModuleName : showModuleName">  
                        {{locale[module.i18n]}}   
                     </template>  
                   </li>  
                 </template>  
               </ul>  
               <div class="dashboard" v-show="dashboard" ref="dashboard">  
                 <keep-alive>  
                   <div v-show="dashboard" :is="dashboard"></div>  
                 </keep-alive>  
               </div>  
             </div>  
               
           </div>  
         `  

    和  2.主要的样式字符串

     `
      .vue-html5-editor, .vue-html5-editor * {
        box-sizing: border-box
      }
    
      .vue-html5-editor {
        font-size: 14px;
        line-height: 1.5;
        background-color: #fff;
        color: #333;
        border: 1px solid #ddd;
        text-align: left;
        border-radius: 5px;
        overflow: hidden
      }
    
      .vue-html5-editor.full-screen {
        position: fixed !important;
        top: 0 !important;
        left: 0 !important;
        bottom: 0 !important;
        right: 0 !important;
        border-radius: 0
      }
    
      .vue-html5-editor > .toolbar {
        position: relative;
        background-color: inherit;
        border-top:1px solid #ccc
      }
    
      .vue-html5-editor > .toolbar > ul {
        list-style: none;
        padding: 0;
        margin: 0;
        border-bottom: 1px solid #ddd
      }
    
      .vue-html5-editor > .toolbar > ul > li {
        display: inline-block;
        cursor: pointer;
        text-align: center;
        line-height: 36px;
        padding: 0 10px
      }
    
      .vue-html5-editor > .toolbar > ul > li .icon {
        height: 16px;
         16px;
        display: inline-block;
        vertical-align: middle
      }
    
      .vue-html5-editor > .toolbar > .dashboard {
        background-color: inherit;
        border-top: 1px solid #ddd;
        padding: 10px;
        position: absolute;
        bottom: 100%;
        left: 0;
        right: 0;
        overflow: auto
      }
    
      .vue-html5-editor > .toolbar > .dashboard input[type=text], .vue-html5-editor > .toolbar > .dashboard input[type=number], .vue-html5-editor > .toolbar > .dashboard select {
        padding: 6px 12px;
        color: inherit;
        background-color: transparent;
        border: 1px solid #ddd;
        border-radius: 5px
      }
    
      .vue-html5-editor > .toolbar > .dashboard input[type=text]:hover, .vue-html5-editor > .toolbar > .dashboard input[type=number]:hover, .vue-html5-editor > .toolbar > .dashboard select:hover {
        border-color: #bebebe
      }
    
      .vue-html5-editor > .toolbar > .dashboard input[type=text][disabled], .vue-html5-editor > .toolbar > .dashboard input[type=text][readonly], .vue-html5-editor > .toolbar > .dashboard input[type=number][disabled], .vue-html5-editor > .toolbar > .dashboard input[type=number][readonly], .vue-html5-editor > .toolbar > .dashboard select[disabled], .vue-html5-editor > .toolbar > .dashboard select[readonly] {
        background-color: #eee;
        opacity: 1
      }
    
      .vue-html5-editor > .toolbar > .dashboard input[type=text][disabled], .vue-html5-editor > .toolbar > .dashboard input[type=number][disabled], .vue-html5-editor > .toolbar > .dashboard select[disabled] {
        cursor: not-allowed
      }
    
      .vue-html5-editor > .toolbar > .dashboard button {
        color: inherit;
        background-color: inherit;
        padding: 6px 12px;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        border: 1px solid #ddd;
        border-radius: 5px;
        margin-right: 4px;
        margin-bottom: 4px
      }
    
      .vue-html5-editor > .toolbar > .dashboard button:hover {
        border-color: #bebebe
      }
    
      .vue-html5-editor > .toolbar > .dashboard button[disabled] {
        cursor: not-allowed;
        opacity: .68
      }
    
      .vue-html5-editor > .toolbar > .dashboard button:last-child {
        margin-right: 0
      }
    
      .vue-html5-editor > .toolbar > .dashboard label {
        font-weight: bolder
      }
    
      .vue-html5-editor > .content {
        overflow: scroll;
        padding: 10px;
        max-height:500px
      }
    
      .vue-html5-editor > .content:focus {
        outline: 0
      }`

    修改的地方不多,请参照具体的样式自己配置自定义的模板。

    我这个修改完以后显示如下。而且输入很长的数据后,只是内容区变成上下滚动的,工具栏不动。

    c.移动端图片上传的处理

    这里我没有配置服务端的上传文件的接口,所以我就直接将图片转成base64的来处理。但是这样会有问题,在PC端图片是可以修改大小的,但是在移动端上传的图片上是原图,也就是很大,图文混排的时候非常不好看,也不好编辑。这时候我做的处理挺投机取巧的,但是也是可行的方法。我们知道change函数是在内容发生变化时触发的,这时候我们只要将获取到的内容做一下修改即可,看代码:

        updateData(e = ''){  
           let c1 = e.replace(/<img width="100%"/g, '<img');  
           let c2 = c1.replace(/<img/g, '<img width="100%"');  
           this.content = c2;  
         }  

    这样就OK了。

    看移动端的效果图:图片是按宽100%自适应缩放的。效果达到。

    本项目的git地址:https://github.com/JerryYuanJ/a-vue-app-template

    主要参考  /src/pages/tool/RichTextTest.vue (使用),/src/init-plugins.js(配置) 

    如果有bug欢迎指正,不胜感激;如果对您有帮助,给个star,谢谢~~

  • 相关阅读:
    Largest Rectangle in Histogram
    Valid Sudoku
    Set Matrix Zeroes
    Unique Paths
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Path Sum II
    Path Sum
    Validate Binary Search Tree
    新手程序员 e
  • 原文地址:https://www.cnblogs.com/jerryyj/p/9621555.html
Copyright © 2011-2022 走看看