Vue2.0項目中使用百度編輯器及爬坑記錄


vue2.0中使用百度編輯器(僅適用於2.0,與3.0有所不同,3.0版本使用者可略過)

1、yarn add vue-ueditor-wrap   //下載此包可實現雙向綁定功能

2、將去官網下載百度編輯器包(jsp版本),將名字改為UEditor放在項目的static文件夾下(與src同級)

3、在src/components文件夾下新建文件Ueditor.vue並寫入以下代碼(提醒:注意下方代碼中的UEDITOR_HOME_URL: '/static/UEditor/',
這個路徑一般情況下是這樣的,但是有時候如果因為跨域問題做了代理,項目地址改變了,這時候這個地址就得換,具體換成什么樣的要去控制台審查過后才能得知。
比如這一次我的項目地址代理后成了http://localhost/hs/.....這種,多了個hs,所以我就得把此地址改成UEDITOR_HOME_URL: '/hs/static/UEditor/'。
沒換之前百度編輯器請求地址http://localhost/static/UEditor/...因此很多文件請求不到,瘋狂報錯。
換了之后百度編輯器請求地址是http://localhost/hs/static/UEdior/...就可以了。
另外static/UEditor/ueditor.config.js文件里也有一處是這個地址,也需要同步換。還有一點值得注意,項目上線后沒有跨域問題了。
因此項目上線后這兩處地址還得再換成原來的static/UEditor。總之根據項目靈活配置路徑是一個關鍵)以下代碼可實現圖片上傳功能,
這里的圖片上傳功能(點擊左邊圖片圖標即可上傳)是自己定義的而非百度編輯器自帶的。百度編輯器自帶的單圖和多圖上傳已被注釋。
<template>
  <div>
    <vue-ueditor-wrap v-model="content" :config="myConfig" @beforeInit="addCustomButtom"></vue-ueditor-wrap>
    <a-modal
      title="圖片上傳"
      :visible="dialogVisible"
      @ok="insertImage"
      @cancel="handleCancel"
      okText="確定"
      cancelText="取消"
      :centered='true'
    >
      <div class="uploadContent">
        <a-upload
            name="file"
            listType="picture-card"
            class="uploader"
            :showUploadList="false"
            accept="image/png, image/jpeg"
            :action="uploadBase"
            @change="handleChange"
        >
            <img class="personImg" v-if="imageUrl" :src="imageUrl" alt="avatar" />
            <div v-else>
              <a-icon :type="loading ? 'loading' : 'plus'" />
              <div class="ant-upload-text">上傳圖片</div>
            </div>
        </a-upload>
      </div>
    </a-modal>
  </div>

</template>

<script>
  import common from '../api/common.js'   //這個common.js文件是自己寫的,里面是接口地址,文件內容是export default{base:'http://localhost/apis',}
  import '../../static/UEditor/ueditor.config.js'
  import '../../static/UEditor/ueditor.all.js'
  import '../../static/UEditor/lang/zh-cn/zh-cn.js'
  import VueUeditorWrap from 'vue-ueditor-wrap'

    function getBase64(img, callback) {
        const reader = new FileReader();
        reader.addEventListener('load', () => callback(reader.result));
        reader.readAsDataURL(img);
    }

  export default {
    name: "Ueditor",
    components: {
      VueUeditorWrap,
    },
    props: {
      value: {
        type: String,
        default: ''
      },
      myConfig: {
        type: Object,
        default: () => ({
            // 編輯器不自動被內容撐高
            autoHeightEnabled: false,
            // 初始容器高度
            initialFrameHeight: 400,
            // 初始容器寬度
            initialFrameWidth: '100%',
            // UEditor 資源文件的存放路徑,如果你使用的是 vue-cli 生成的項目,通常不需要設置該選項,vue-ueditor-wrap 會自動處理常見的情況,如果需要特殊配置,參考下方的常見問題2
            UEDITOR_HOME_URL: '/static/UEditor/'
          }
        )
      }
    },
    data(){
      return{
        uploadBase: `${common.base}/uploadimg`,//圖片上傳地址
        dialogVisible: false,
        imageList: [],
        editorHandler: null,
        content: this.value,

        imageUrl:'',  //upload框里圖片的url
        loading: false,   //圖片上傳加載
        contentImg:'',   //轉換過后的url鏈接
      }
    },
    watch: {
      value (newValue) {
        this.content = newValue
      },
      content (newValue) {
        this.$emit('input', newValue)
      }
    },
    methods:{
      handleCancel(){
        this.dialogVisible=false
        this.imageUrl=''
        this.contentImg=''
      },
      handleChange(info) {
            if (info.file.status === 'uploading') {
                this.loading = true;
                return;
            }
            if (info.file.status === 'done') {
                getBase64(info.file.originFileObj, imageUrl => {
                    this.imageUrl = imageUrl;
                    this.loading = false;
                });
                // console.log(info.file)
                if(info.file.response.code==200){
                    this.contentImg=info.file.response.msg
                }else if(info.file.response.code==401){
                    this.$message.warning("登錄超時,請重新登錄!")
                    this.$router.push({name:'Login'})
                }
            }
        },
      insertImage () {
        if(this.contentImg==''){
            this.$message.warning("您還未上傳圖片!")
            return
        }
        let imgUrl = this.contentImg;
        let imageHtml = "";
        imageHtml = imageHtml + "<p><img src=\"" + imgUrl + "\"/></p>";
        if (imageHtml != "") {
          this.editorHandler.execCommand('inserthtml', imageHtml);
        }
        this.dialogVisible = false;
        this.imageUrl=''
        this.contentImg=''
      },
      addCustomButtom (editorId) {
        let _this = this;
        window.UE.registerUI('test-button', function (editor, uiName) {
          // 注冊按鈕執行時的 command 命令,使用命令默認就會帶有回退操作
          editor.registerCommand(uiName, {
            execCommand: () => {
              _this.imageList = [];
              _this.dialogVisible = true;
              _this.editorHandler = editor;
              //editor.execCommand('inserthtml', `<span>這是一段由自定義按鈕添加的文字</span>`)
            }
          })

          // 創建一個 button
          var btn = new window.UE.ui.Button({
            // 按鈕的名字
            name: uiName,
            // 提示
            title: '鼠標懸停時的提示文字',
            // 需要添加的額外樣式,可指定 icon 圖標,圖標路徑參考常見問題 2
            cssRules: "background-position: -380px 0;",
            // 點擊時執行的命令
            onclick: function () {
              // 這里可以不用執行命令,做你自己的操作也可
              editor.execCommand(uiName)
            }
          })

          // 當點到編輯內容上時,按鈕要做的狀態反射
          editor.addListener('selectionchange', function () {
            var state = editor.queryCommandState(uiName)
            if (state === -1) {
              btn.setDisabled(true)
              btn.setChecked(false)
            } else {
              btn.setDisabled(false)
              btn.setChecked(state)
            }
          })
          // 因為你是添加 button,所以需要返回這個 button
          return btn
        }, 47 /* 指定添加到工具欄上的哪個位置,默認時追加到最后 */, editorId /* 指定這個 UI 是哪個編輯器實例上的,默認是頁面上所有的編輯器都會添加這個按鈕 */)
      }
    },
  }
</script>

<style scoped>
    .uploadContent{
        width:100%;
        text-align: center;
    }
    .uploader{
        display: inline-block;
    }
    .personImg{
        width:200px;
    }
</style>

4、在main.js中全局注冊組件
import Ueditor from './components/Ueditor.vue'   //百度編輯器組件
Vue.component('Ueditor',Ueditor)

5、使用
<Ueditor v-model="intro"></Ueditor>

6、修改編輯器css樣式,使其更加美觀,在static/UEditor/themes/default/css/ueditor.css里添加以下代碼

.edui-default.edui-editor-toolbarbox{
    box-shadow: none!important;
}
.edui-default.edui-editor-toolbarboxouter{
    background-image:-webkit-linear-gradient(top,#fff,#fff)!important;
    box-shadow:none!important;
}
.edui-default.edui-editor{
    border-radius: 0!important;
}

解決百度圖片伸縮框錯位的問題

1、找到\static\UEditor\index.html並將其<script type="text/javascript" charset="utf-8" src="ueditor.all.min.js"> </script>改為<script type="text/javascript" charset="utf-8" src="ueditor.all.js"> </script>
2、找到api\ueditor\ueditor.all.js(視后台編輯器引入文件進行修改),查找attachTo: function (targetObj)字段
3、將
attachTo: function (targetObj) {
    var me = this,
    target = me.target = targetObj,
    resizer = this.resizer,
    imgPos = domUtils.getXY(target),
    iframePos = domUtils.getXY(me.editor.iframe),
    editorPos = domUtils.getXY(resizer.parentNode);

    domUtils.setStyles(resizer, {
        'width': target.width + 'px',
        'height': target.height + 'px',
        'left': iframePos.x + imgPos.x - me.editor.document.body.scrollLeft - editorPos.x - parseInt(resizer.style.borderLeftWidth) + 'px',
        'top': iframePos.y + imgPos.y - me.editor.document.body.scrollTop - editorPos.y - parseInt(resizer.style.borderTopWidth) + 'px'
    })
}
修改為
attachTo: function (a) {
    var b = this,
    c = b.target = a,
    d = this.resizer,
    e = domUtils.getXY(c),
    f = domUtils.getXY(b.editor.iframe),
    g = domUtils.getXY(d.parentNode),
    h = b.editor.document;
    domUtils.setStyles(d, {
        width: c.width + "px",
        height: c.height + "px",
        left: f.x + e.x - (h.documentElement.scrollLeft || h.body.scrollLeft || 0) - g.x - parseInt(d.style.borderLeftWidth) + "px",
        top: f.y + e.y - (h.documentElement.scrollTop || h.body.scrollTop || 0) - g.y - parseInt(d.style.borderTopWidth) + "px"
    })
}
4、重新加載項目,大功告成

解決因百度編輯器自動保存功能引起的回撤等相關功能失效的問題

--出現原因:
百度編輯器自動保存是保存在localStorage里的。當內容過多時,會溢出localStorage儲存范圍。導致報錯

--解決方法:
1、將ueditor.config.js文件中
enableAutoSave的注釋去掉,並設置成false,
saveInterval的注釋也去掉,並設置成0;
2、在ueditor.all.js文件中
在'contentchange': function () {   函數的第一行添加以下一段代碼:

    if (!me.getOpt('enableAutoSave')) {
        return;
    }

百度編輯器上傳超大圖片時,圖片寬度會超出編輯器寬度

--問題:當上傳一個超大圖片時,比如3840*2160,假設編輯器的寬度只有1200px。此時上傳此圖片后,圖片會超出編輯器寬度,樣式如下
解決:
找到themes/iframe.css文件
在里面加入以下代碼
img {
    max-width: 100%; /*圖片自適應寬度*/
}
body {
    overflow-y: scroll !important;
}
.view {
    word-break: break-all;
}
.vote_area {
    display: block;
}
.vote_iframe {
    background-color: transparent;
    border: 0 none;
    height: 100%;
}
--解決后:上傳的圖片寬度若超過編輯器寬度,則設置圖片寬度等於編輯器寬度


百度編輯器里設置圖片最小寬度和高度

為什么這樣做:百度編輯器圖片寬高設置存在選定問題。有時會導致圖片瞬間寬高接近0,變成一個點。這里需要設置一下最小寬高來兼容一下這個問題。等后續解決圖片選定問題,可以不用此方法兼容。
同上,在iframe.css文件里
img {
    max-width: 100%; /*圖片自適應寬度*/
    min-width: 100px;
    min-height: 100px;
}

解決內容無法居中或者居中一片區域時,未選中區域也被居中問題

歸根結底可能是因為編輯器內文檔是從別的地方直接復制進來的。
問題1:內容里的最外層標簽可能帶有屬性,如section帶有了inline-block屬性。
問題2:復制的內容里有多個內容放在一個標簽內。

問題1:當最外層標簽帶屬性會導致的問題:如img放在section標簽里,而section又被設置了inline-block屬性。此時設置圖片居中則無效的。
解決:復制此內容,刪除此內容,再在同一位置上重新粘貼此內容,section標簽就會消失了

問題2:此外,若多個內容放在一個標簽內,比如此時居中第一個內容,會導致給父標簽添加text-align:center屬性,會導致此標簽下其他內容也被居中,目前未找到較好解決辦法

編輯器過濾section樣式,導致微信或其他地方編輯好的內容復制到百度編輯器里不生效的問題

原因:發現ueditor中有xss過濾器,默認啟用,按照配置文件中的白名單列表,不在其中的將去除。

解決:
ueditor.config.js文件下
找到whitList,更改以下代碼
-  section:[],
+  section:['class', 'style'],

給

解決編輯器表格拖拽選中的問題

原因:是編輯器為了區分用戶是單擊表格還是雙擊,對表格拖拽做了延時處理。這也導致了如改變表格寬度等拖拽操作的識別不靈敏的問題。默認是360ms的延時
解決:
1、將延時處理時間變短,變成20以下,使得用戶無法完成雙擊操作。此時用戶無論單擊,雙擊都能選中邊框了
2、將表格邊框變寬一些,增加識別范圍
3、將邊框選中顏色變明顯一些,提高識別度

1、延時時間變短
搜索dblclickTime,將dblclickTime = 360 設置為 dblclickTime = 20
2、表格邊框變寬
搜索cellBorderWidth,將cellBorderWidth = 5 修改為cellBorderWidth = 10 
3、見下方

修改表格拖拽選中邊框時的邊框顏色,使其更明顯,更容易識別

在ueditor.all.js里搜索dragLine.style.cssText
找到如下兩行,其中opacity為透明度,background-color是選中表格邊框顏色。如圖


修改前:

修改后:

解決編輯器里表格居中問題

百度編輯器里選定表格->右鍵->表格對齊方式->居中顯示。完成此操作后,會在table屬性里添加align="center"以實現居中效果。
但是這個align="center"貌似並沒有那么好用。所以我在ueditor.all.js里做了一下改動
在ueditor.all.js里搜索“表格對齊方式”查詢到以下代碼,做出相關改動即可
//表格對齊方式
    UE.commands['tablealignment'] = {
        queryCommandState: function () {
            if (browser.ie && browser.version < 8) {
                return -1;
            }
            return getTableItemsByRange(this).table ? 0 : -1
        },
        execCommand: function (cmd, value) {
            var me = this,
                start = me.selection.getStart(),
                table = start && domUtils.findParentByTagName(start, ["table"], true);

            if (table) {
                table.setAttribute("align",value);
+                if(value=="center"){
+                    table.style.margin="0 auto"  //通過設置margin:0 auto來實現居中效果
+                }else{
+                    table.style.margin="0"
+                }
            }
        }
    };

解決表格邊框在編輯器里可見,但在頁面里卻失效的問題

如下圖
選中表格->右擊->設置表格邊線可見。即可

全選后設置字體為黑體,會有部分設置失效

記錄一下,還未解決

解決百度編輯器段間距過大,但是設置行間距以及段間距無效的問題

問題:
當你在段落與段落之間enter換行時。百度編輯器會生成一個包裹span標簽的p標簽。然后你設置了行間距,但是無效,為什么呢。因為你的行間距設置在了外層的p標簽上,而span標簽卻有一個默認的line-height。p標簽被span撐開了。

怎么辦:enter換行之后,鍵入一個空格或者文字,再刪除此空格或文字。span標簽就會隨着空格或文字的刪除而刪除。此時就剩一個p標簽了,就可以設置行間距以及段前距段后距了。

百度編輯器多圖上傳完整代碼(配合antd-vue組件庫,此頁最上方代碼改進版)

<template>
  <div>
    <vue-ueditor-wrap v-model="content" :config="myConfig" @beforeInit="addCustomButtom"></vue-ueditor-wrap>
    <a-modal
      	title="圖片上傳"
      	:visible="dialogVisible"
	  	width="550px"
      	@ok="insertImage"
      	@cancel="handleCancel"
      	okText="確定"
      	cancelText="取消"
      	:centered='true'
    >
		<div class="imgContent" >
			<ul>
				<li class="everyImg" v-for="(item,index) in imageList" :key="index">
					<div class="imgBody">
						<img :src="item" alt="avatar" />
						<div class="mask">
							<div class="leftmove" @click="moveLeft(index)"><a-icon type="left-circle" /></div>
							<div class="delimg" @click="imgDelete(index)"><a-icon type="delete" /></div>
							<div class="rightmove" @click="moveRight(index)"><a-icon type="right-circle" /></div>
						</div>
					</div>
				</li>
			</ul>
		</div>
      	<div class="uploadContent">
        	<a-upload
        	    name="file"
        	    listType="picture-card"
        	    class="uploader"
        	    :showUploadList="false"
        	    accept="image/png, image/jpeg"
        	    :action="uploadBase"
        	    @change="handleChange"
        	>
            	<div>
              		<a-icon :type="loading ? 'loading' : 'plus'" />
              		<div class="ant-upload-text">上傳圖片</div>
            	</div>
        	</a-upload>
      </div>
    </a-modal>
  </div>

</template>

<script>
  import common from '../api/common.js'  //這個common.js文件是自己寫的,里面是接口地址,文件內容是export default{base:'http://localhost/apis',}
  import '../../static/UEditor/ueditor.config.js'
  import '../../static/UEditor/ueditor.all.js'
  import '../../static/UEditor/lang/zh-cn/zh-cn.js'
  import VueUeditorWrap from 'vue-ueditor-wrap'

    function getBase64(img, callback) {
        const reader = new FileReader();
        reader.addEventListener('load', () => callback(reader.result));
        reader.readAsDataURL(img);
    }

  export default {
    name: "Ueditor",
    components: {
      VueUeditorWrap,
    },
    props: {
      value: {
        type: String,
        default: ''
      },
      myConfig: {
        type: Object,
        default: () => ({
            // 編輯器不自動被內容撐高
            autoHeightEnabled: false,
            // 初始容器高度
            initialFrameHeight: 200,
            // 初始容器寬度
            initialFrameWidth: '100%',
            // UEditor 資源文件的存放路徑,如果你使用的是 vue-cli 生成的項目,通常不需要設置該選項,vue-ueditor-wrap 會自動處理常見的情況,如果需要特殊配置,參考下方的常見問題2
            UEDITOR_HOME_URL: '/static/UEditor/'
          }
        )
      }
    },
    data(){
      return{
        uploadBase: `${common.base}/uploadimg`,//圖片上傳地址
        dialogVisible: false,
        imageList: [],   //圖片列表
        editorHandler: null,
        content: this.value,
        loading: false,   //圖片上傳加載
      }
    },
    watch: {
      value (newValue) {
        this.content = newValue
      },
      content (newValue) {
        this.$emit('input', newValue)
      }
    },
    methods:{
	//取消上傳圖片彈框
    handleCancel(){
    	this.dialogVisible=false
      	this.imageList=[]
	},
	//刪除圖片
	imgDelete(i){
		this.imageList.splice(i,1)
	},
	//圖片向左移動
	moveLeft(i){
		let a=this.imageList
		if(i!=0){
			a[i]=a.splice(i-1,1,a[i])[0]
		}else{
			this.$message.warning("已經是最左邊了")
		}
		console.log(this.imageList)
	},
	//圖片向右移動
	moveRight(i){
		let a=this.imageList
		if(i!=a.length-1){
			a[i]=a.splice(i+1,1,a[i])[0]
		}else{
			this.$message.warning("已經是最右邊了")
		}
	},
	//進行圖片上傳
    handleChange(info) {
        if (info.file.status === 'uploading') {
            this.loading = true;
            return;
        }
        if (info.file.status === 'done') {
            getBase64(info.file.originFileObj, imageUrl => {
                this.loading = false;
            });
            // console.log(info.file)
            if(info.file.response.code==200){
				this.imageList.push(info.file.response.msg)
            }else if(info.file.response.code==401){
                this.$message.warning("登錄超時,請重新登錄!")
                this.$router.push({name:'Login'})
            }
        }
    },
    insertImage () {
        if(this.imageList.length==0){
            this.$message.warning("您還未上傳圖片!")
            return
        }
        let imageHtml = "";
		for(let item of this.imageList){
			imageHtml = imageHtml + "<p><img src=\"" + item + "\"/></p>";
		}
        if (imageHtml != "") {
          this.editorHandler.execCommand('inserthtml', imageHtml);
        }
        this.dialogVisible = false;
		this.imageList=[]
      },
      addCustomButtom (editorId) {
        let _this = this;
        window.UE.registerUI('test-button', function (editor, uiName) {
          // 注冊按鈕執行時的 command 命令,使用命令默認就會帶有回退操作
          editor.registerCommand(uiName, {
            execCommand: () => {
              _this.imageList = [];
              _this.dialogVisible = true;
              _this.editorHandler = editor;
              //editor.execCommand('inserthtml', `<span>這是一段由自定義按鈕添加的文字</span>`)
            }
          })

          // 創建一個 button
          var btn = new window.UE.ui.Button({
            // 按鈕的名字
            name: uiName,
            // 提示
            title: '鼠標懸停時的提示文字',
            // 需要添加的額外樣式,可指定 icon 圖標,圖標路徑參考常見問題 2
            cssRules: "background-position: -380px 0;",
            // 點擊時執行的命令
            onclick: function () {
              // 這里可以不用執行命令,做你自己的操作也可
              editor.execCommand(uiName)
            }
          })

          // 當點到編輯內容上時,按鈕要做的狀態反射
          editor.addListener('selectionchange', function () {
            var state = editor.queryCommandState(uiName)
            if (state === -1) {
              btn.setDisabled(true)
              btn.setChecked(false)
            } else {
              btn.setDisabled(false)
              btn.setChecked(state)
            }
          })
          // 因為你是添加 button,所以需要返回這個 button
          return btn
        }, 47 /* 指定添加到工具欄上的哪個位置,默認時追加到最后 */, editorId /* 指定這個 UI 是哪個編輯器實例上的,默認是頁面上所有的編輯器都會添加這個按鈕 */)
      }
    },
  }
</script>

<style scoped>
	.imgContent ul{
		margin-bottom: 15px;
	}
	.imgContent .everyImg{
		list-style: none;
		padding:5px;
		border:1px dashed #dcdcdc;
		margin:0 10px 10px 0;
		border-radius: 4px;
		cursor: pointer;
		transition: all 0.2s;
		display:inline-block;
		vertical-align:top;
    }
	.imgContent .everyImg:hover{
		border:1px dashed #1890FF;
		transition: all 0.2s;
	}
	.imgBody{
		position: relative;
	}
	.imgBody:hover .mask{
		opacity: 1;
	}
	.imgBody img{
		width:100px;
		height:auto;
		border-radius: 4px;
	}
	.mask{
		transition: all .3s;
		opacity: 0;
		width:100%;
		height:100%;
		position: absolute;
		border-radius: 4px;
		top:0;
		left:0;
		background-color: rgba(0,0,0,.4);
	}
	.leftmove,.delimg,.rightmove{
		color:#dcdcdc;
		font-size: 22px;
		position: absolute;
		top:50%;
		transform: translateY(-50%);
		transition: all .2s;
	}
	.leftmove{
		left:2px;
	}
	.leftmove:hover{
		color:#1890FF;
	}
	.delimg{
		left:40px;
	}
	.delimg:hover{
		color:#1890FF;
	}
	.rightmove{
		right:2px;
	}
	.rightmove:hover{
		color:#1890FF;
	}
    .uploadContent{
        width:100%;
        text-align: center;
    }
    .uploader{
        display: inline-block;
    }
</style>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM