溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React中使用UEditor百度富文本的方法

發(fā)布時間:2020-08-20 10:10:49 來源:腳本之家 閱讀:413 作者:白馬嘯西風 欄目:web開發(fā)

前言

本文將介紹筆者在React的項目中使用百度的富文本編輯器Ueditor的過程。注意本文不提供一條龍式的使用方法,只是將使用過程中的一些實現(xiàn)思路進行總結,供以參考。react項目中導入ueditor,會存在各種不正交的問題,需要注意。

引入

首先在ueditor官網(wǎng)下載最新安裝包,然后在項目入口的html中導入(導入方式不一,可以采用import的方式,需要自行度娘。但是無論哪種引入方式,只要想自定義功能,不正交問題就難以避免QAQ)。不管三七二十一先跑起來再說。。

<!DOCTYPE HTML>
<html lang="en-US">

<head>
  <meta charset="UTF-8">
  <title>ueditor demo</title>
</head>

<body>
  <!-- 配置文件 -->
  <script type="text/javascript" src="path/ueditor.config.js"></script>
  <!-- 編輯器源碼文件 -->
  <script type="text/javascript" src="path/ueditor.all.js"></script>
 ······
</body>

</html>

在React項目中使用ueditor要注意

  1. 導入的路徑,筆者使用的是項目經(jīng)webpack打包之后的相對路徑。
  2. 導入順序,配置文件要先于源碼。
  3. 筆者這種引入方式存在緩存問題,所以修改ueditor.all.js后需要及時清理緩存,測試新的代碼。

封裝

/**
 * 封裝UEditor
 */
import React from 'react';
import './index.less';

class UEditor extends React.Component {
  constructor(props) {
    super(props);
    this.editor = {};
    this.id = '';
  }
 ······
  componentDidMount() {
    let UE = window.UE;
    let id = this.id;
    if (id) {
      try {
        /* 加載之前先執(zhí)行刪除操作,否則如果存在頁面切換,
      再切回帶編輯器頁面重新加載時不刷新無法渲染出編輯器 */
        UE.delEditor(id);
      } catch (e) {}
      let ueditor = UE.getEditor(id, {
        toolbars: [
          ['bold', 'italic', 'underline', 'kityformula', 'diyimg']
        ],
        initialContent: '',
        autoHeightEnabled: false,
        autoFloatEnabled: false,
        elementPathEnabled: false,
        wordCount: false,
        enableAutoSave: false,
        initialFrameWidth: this.props.width,
        initialFrameHeight: this.props.height
      });
    }
  }
  render() {
    this.id = this.props.id;
    return <div styleName="content" id={this.id} />;
  }
}

export default UEditor;

筆者在項目中使用了加粗,斜體,下劃線,插入圖片,公式等功能,想要自定義配置均可參照ueditor.config.js修改。具體的將一一介紹,最后實現(xiàn)效果如下:

React中使用UEditor百度富文本的方法

問題總結:

1. 禁止自動增高,改用滾動條

autoHeightEnabled: false
initialFrameWidth:this.props.width
initialFrameHeight:this.props.height

autoHeightEnabled可以阻止自動增高,然后再自定義容器寬度和高度。

2. 自定義全局樣式,如容器的padding,p標簽的line-height等

解決方法:ueditor.all.js的第6800多行的render方法,在其中可以自定義全局樣式。

React中使用UEditor百度富文本的方法

3. 導航條切換后,無法再次渲染

解決方法:在每次ueditor實例化之前,先刪除對應的id

 UE.delEditor(id);

原因分析:

從實例化和卸載實例的源碼來看:

getEditor:

UE.getEditor = function (id, opt) {
  var editor = instances[id];
  if (!editor) {
    editor = instances[id] = new UE.ui.Editor(opt);
    editor.render(id);//渲染編輯器
  }
  return editor;
};

delEditor:

UE.delEditor = function (id) {
  var editor;
  if (editor = instances[id]) {
    editor.key && editor.destroy();
    delete instances[id]
  }
};

UE在全局管理了一個實例池,每次實例化都會根據(jù)id檢索,然后生成實例。從getEditor的源碼中可以看出,ueditor的一個實例在第一次初始化時存在一個editor.render(),這是將此id的實例渲染到對應的id容器上。然而,當用戶tab切換編輯器再切回來時,此時由于該實例已在實例池中存在,于是直接執(zhí)行return editor,所以少了editor.render()這一步,于是不能重新渲染。所以,在Ueditor組件每次實例化之前,先進行delEditor卸載。這里需要注意,從delEditor中可以看出ueditor卸載實例時調(diào)用了實例的destroy方法。從destroy的注釋來看:銷毀編輯器實例,使用textarea代替 ,這解釋了為什么在切換編輯器或者卸載編輯器時,會出現(xiàn)編輯器變?yōu)閠extarea的情況,如圖所示:

React中使用UEditor百度富文本的方法

4. 模擬placeholder實現(xiàn)預置文案

解決方法:在UE的實例中自定義方法,實現(xiàn)填充文字模擬placeholder的效果,代碼如下:

//模擬placeholder和控制toolbar顯示隱藏
UE.Editor.prototype.initDiy = function (placeholder) {
  var _editor = this;
  //獲取焦點
  _editor.addListener("focus", function () {
    UE.isEditored = true;
    var Text = `<p >${placeholder}</p>`
    var localHtml = _editor.getContent();
    if (localHtml === Text) {
      _editor.setContent("");//點擊時清空
      _editor.focus(true);
    }
    //使得其他工具條display置為none
    var list = document.querySelectorAll('.edui-editor-toolbarbox');
    list.forEach((ele) => {
      ele.style.display = 'none';
    });
    var toolbar = findKey(_editor.key);
    toolbar.style.display = 'block';
  });
  // 插入圖片時存在問題
  // _editor.addListener("blur", function () {
  //   var localHtml = _editor.getContent();
  //   if (localHtml === '') {
  //     _editor.setContent(`<p >${placeholder}</p>`);
  //   }
  //   // window.activeEditor = _editor.key;
  // });
  _editor.ready(function () {
    // _editor.fireEvent("blur");
    _editor.setContent(`<p >${placeholder}</p>`);//填充預置文案
  }); 
}
//尋找工具條
function findKey(key) {
  let ele = document.querySelector(`#${key}`);
  let toolbar = ele.querySelector('.edui-editor-toolbarbox');
  return toolbar;
}

原來,筆者實現(xiàn)的效果是點擊時清空,失焦時還原。但是,在做自定義工具條時產(chǎn)生了bug(在5中我會細說),因此我采用了另一種方案:初始時設置預設文案,當用戶聚焦時清空預設,用戶失焦后不再恢復該預設文案。也就是將blur事件注釋了。。。

5. 工具條顯示在編輯器頭部,顯示為懸浮效果,默認隱藏,聚焦時出現(xiàn)

實現(xiàn)思路:將themes/default/css/ueditor.css中加入:

.edui-default .edui-editor-toolbarbox {
  position: absolute;
  ······
  top: -36px;
}

首先實現(xiàn)頭部偏移,然后通過控制toolbar對應dom元素的display來隱藏工具條。實現(xiàn)效果如下:

React中使用UEditor百度富文本的方法

下面解釋一下為什么編輯器失焦的時候不恢復預置文案:
從4中的代碼可以看出,我們是通過觸發(fā)focus和blur事件分別清空和填充編輯器的內(nèi)容。但是當我們點擊工具條時,編輯器就會觸發(fā)blur事件??!于是就會出現(xiàn)各種bug。以百度官網(wǎng)的ueditor為例,控制臺輸入:

React中使用UEditor百度富文本的方法

為該編輯器注冊點擊事件,當點擊加粗按鈕時,控制臺輸出:

React中使用UEditor百度富文本的方法

為了避免點擊工具條時觸發(fā)blur事件,筆者將自定義的blur事件全部注釋了。

6. 自定義按鈕和七牛云圖片上傳

首先,在ueditor.config.js中找到toolbars數(shù)組,增加一個diyimg字符串,然后在zh-cn.js找到labelMap數(shù)組,在末尾加上'diyimg': '插入圖片' 。最后,在ueditor.all.js中找到btnCmds數(shù)組,加入diyimg字符串。初始化時使用這個字符串,工具條上就會顯示一個按鈕,但是我們發(fā)現(xiàn)他顯示的是這樣的:

React中使用UEditor百度富文本的方法

這是因為ueditor默認使用加粗的icon作為自定義按鈕的默認icon,所以為了使用默認的插入圖片的圖標,我們需要到themes/default/css/ueditor.css中,在最后一行加入:

/*自定義圖片上傳按鈕 */
.edui-default .edui-toolbar .edui-for-diyimg .edui-icon {
  background-position: -380px 0px;//這個位置是“插入圖片”的icon,其他圖標可自行調(diào)整
}

添加后,顯示效果如下:

React中使用UEditor百度富文本的方法

圖標正常顯示后,需要為該圖標添加相應的點擊事件,在ueditor.all.js中加入:

//圖片上傳
UE.commands['diyimg'] = {
  execCommand : function(){
    const upload = async(e) => {
      ······//完成圖片上傳的代碼
    }
    const fileInput = document.getElementById('diyimg');//獲取dom上隱藏的一個input標簽
    fileInput.onchange = upload;
    fileInput.click();//觸發(fā)input標簽實現(xiàn)文件上傳
    return true; 
  },
  queryCommandState:function(){
  
  }
};

筆者這里不贅述圖片上傳的代碼,度娘上很多,我簡單說說實現(xiàn)的思路:

先實現(xiàn)一個插入圖片的按鈕,然后為該按鈕注冊相應的事件diyimg,然后在頁面中添加一個input file標簽并隱藏,diyimg事件會觸發(fā)該標簽的點擊事件,彈出文件上傳彈窗,此時選擇文件點擊后會觸發(fā)onchange事件,執(zhí)行相應的圖片上傳代碼。上傳成功到服務器后,服務器會返回圖片對應的url,此時拿到該url填入對應編輯器實例,執(zhí)行編輯器的插入圖片的代碼:

this.execCommand('insertimage', {
  src: res.data.downloadUrl,//回調(diào)傳來的url
  width:'60'
  // height:'45'
});

7. 給在編輯器內(nèi)部的img等標簽添加內(nèi)聯(lián)樣式

ueditor默認存在xss過濾?。?!這里以給img標簽添加style=“vertical-top”為例。

首先要找到ueditor.config.js,在其中搜索xss,在第403行左右有代碼:

img:  [src', 'alt', 'title', 'width', 'height', 'id', '_src', 'loadingclass', 'class', 'data-latex'],

往數(shù)組里加入style字符串,然后在ueditor.all.js中搜索UE.commands['insertimage'] ,在第約11172行找到str,往里面加入內(nèi)聯(lián)樣式即可。

一些吐槽:

1. 在react項目里使用script形式引入,感覺格格不入

2. 為了實現(xiàn)placeholder,各個事件之間存在不正交的現(xiàn)象。諸如點擊按鈕,卻觸發(fā)了編輯器的失焦事件

3. 在使用自定義的字數(shù)限制功能時,筆者使用ueditor的contentChange去檢測內(nèi)容字數(shù),但是contentChange事件是定時的,所以計算字數(shù)會有問題。

實現(xiàn)中的問題及解決方法

1.上傳圖片時的跨域問題

在源碼里 有 header['X_Requested_With'] = 'XMLHttpRequest';

后端需要配置 header('Access-Control-Allow-Headers', 'AccessToken, Content-Type, WebOrigin,X-Requested-With,X_Requested_With');

2. 進入文本編輯界面編輯器沒有加載出來

可能原因: 放置編輯器的容器id, 容器下的編輯器已經(jīng)存在

解決方法如代碼所示

this.editor.ready(function (ueditor) {
if (!ueditor) {
// 如果初始化后ueditor不存在刪除后重新調(diào)用
UE.delEditor(self.props.id);
self.initEditor();
}
})

3.注意這兩個參數(shù)配置

'UEDITOR_HOME_URL': '/react/dist/ueditor/', // 編輯器實例路徑,即ueditor文件包所放置的位置

serverUrl: window.api_host + '/innerMessage/uploadImage', // 后端提供加載圖片接口,這是個共同接口接口包括了后端配置的config.json文件 通過url中action

值不同來區(qū)分(config|uploaimage 等)

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI