vue中wangEditor5編輯器的基本使用
一、wangEditor5是什么
wangEditor是一款富文本編譯器插件,其他的我就不再過(guò)多贅述,因?yàn)楣倬W(wǎng)上有一大截對(duì)于這個(gè)編譯器的介紹,但我摸索使用的這兩天里給我的最直觀的感受就是,它是由中國(guó)開(kāi)發(fā)者開(kāi)發(fā),所有的文檔都是中文的,這一點(diǎn)上對(duì)我這個(gè)菜雞來(lái)說(shuō)非常友好,不用再去逐字逐句翻譯,然后去讀那些蹩腳的機(jī)翻中文。而且功能很豐富,能夠滿足很多需求,wangEditor5提供很多版本的代碼,vue2,vue3,react都支持。
接下來(lái)就介紹一下wangEditor5的基本使用,以及博主在使用中遇到的各種問(wèn)題以及其解決方案。
官方網(wǎng)站:
wangEditor開(kāi)源 Web 富文本編輯器,開(kāi)箱即用,配置簡(jiǎn)單https://www.wangeditor.com/
二、wangEditor5基本使用
(一)、安裝
yarn add @wangeditor/editor-for-vue # 或者 npm install @wangeditor/editor-for-vue --save
(二)、編譯器引入
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
Editor:引入@wangEditor編譯器
Toolbar:引入菜單欄
(三)、css及變量引入
<style src="@wangeditor/editor/dist/css/style.css" > </style>
這里需要注意,引入的樣式寫在帶有scoped標(biāo)簽的style內(nèi)無(wú)效。只能引入在全局樣式里,但可能會(huì)造成樣式覆蓋,一般會(huì)有個(gè)清除樣式的文件,會(huì)把里面的樣式覆蓋掉。
三、wangEditor5工具欄配置
工具欄配置有很多選項(xiàng),這里以官方為主,我只做一些常用的配置介紹。
(一)、editor.getAllMenuKeys()
查詢編輯器注冊(cè)的所有菜單 key (可能有的不在工具欄上)這里注意要在
onCreated(editor) { this.editor = Object.seal(editor) },
這個(gè)函數(shù)中去調(diào)用 (這個(gè)函數(shù)是基本配置之一),不然好像調(diào)不出來(lái),當(dāng)然也有可能是博主太菜。
(二)、toolbarConfig中的excludeKeys
toolbarConfig: { excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"] },
這個(gè)是菜單欄配置的一種:排除某項(xiàng)配置 ,這里填寫的key值就是用上面那個(gè)方法,查出來(lái)的key值。
四、wangEditor5上傳圖片
首先在data中return以下信息。
editorConfig: { placeholder: '請(qǐng)輸入內(nèi)容...' , MENU_CONF: { uploadImage: { customUpload: this.uploadImg, }, } },
然后書寫this.uploadImg函數(shù)。
uploadImg(file, insertFn){ let imgData = new FormData(); imgData.append('file', file); axios({ url: this.uploadConfig.api, method: 'post', data: imgData, }).then((response) => { insertFn(response.data.FileURL); }); },
注意,這里因?yàn)榉祷氐臄?shù)據(jù)結(jié)構(gòu)與@wangeditor要求的不一致,因此要使用 insertFn 函數(shù) 去包裹返回的url地址。
五、wangEditor5的一些問(wèn)題收集及解決
(一)、引入@wangEditor 編譯報(bào)錯(cuò) " Module parse failed: Unexpected token (12828:18)You may need an appropriate loader to handle this file type."
解決方法:在 wwebpack.base.conf.js 文件的module>rules>.js 的include下加入
resolve('node_modules/@wangeditor')
就可以了。
(二)、@wangeditor有序列表無(wú)序列表的樣式消失問(wèn)題。
大概率是全局樣式清除導(dǎo)致的樣式消失,可以去調(diào)試工具里看一看,樣式覆蓋的問(wèn)題。
然后在style里deep一下改變樣式就行了。
.editorStyle{ /deep/ .w-e-text-container>.w-e-scroll>div ol li{ list-style: auto ; } /deep/ .w-e-text-container>.w-e-scroll>div ul li{ list-style: disc ; } /deep/ .w-e-text-placeholder{ top:7px; } }
六、完整代碼
<template> <div v-loading="Loading" class="app_detail"> <el-form ref="form" :rules="rules" :model="appDetail" label-width="80px"> <el-form-item prop="name" label="應(yīng)用名稱"> <el-input v-model="appDetail.name" style="width: 360px"></el-input> </el-form-item> <el-form-item label="分類"> <el-select v-model="appDetail.appClassificationID" style="width: 360px" placeholder="選擇應(yīng)用分類" > <template v-for="item in classes"> <el-option v-if="item.parentAppClassificationID" :key="item.appClassificationID" :label="item.appClassificationName" :value="item.appClassificationID" ></el-option> </template> </el-select> <div class="inputdesc">為了適應(yīng)前臺(tái)展示,應(yīng)用只能屬于二級(jí)分類</div> </el-form-item> <el-form-item label="所屬組織"> <el-select v-model="appDetail.orgID" placeholder="請(qǐng)選擇所屬組織" style="width: 360px" > <el-option v-for="item in myorgs" :key="item.orgID" :label="item.name" :value="item.orgID" ></el-option> </el-select> </el-form-item> <el-form-item prop="tags" label="標(biāo)簽"> <el-select v-model="appDetail.tags" multiple filterable style="width: 360px" placeholder="請(qǐng)輸入或選擇應(yīng)用標(biāo)簽" > <el-option v-for="item in existTags" :key="item" :label="item" :value="item" ></el-option> </el-select> </el-form-item> <el-row> <el-col :span="8" class="appsFrom"> <el-form-item label="應(yīng)用Logo" ref="uploadpic" class="el-form-item-cen" prop="logo" > <el-upload class="avatar-uploader" :action="uploadConfig.api" :with-credentials="true" :headers="uploadConfig.headers" :show-file-list="false" :on-success="handleAvatarSuccess" :on-error="handleAvatarError" :before-upload="beforeAvatarUpload" > <img v-if="appDetail.logo" :src="appDetail.logo" class="avatar" /> <i v-else class="el-icon-plus avatar-uploader-icon"></i> <i v-if="appDetail.logo" class="el-icon-delete" @click.stop="() => handleRemove()" ></i> </el-upload> <span style="color: #999999; font-size: 12px"> 建議上傳 100*100 比例的Logo </span> </el-form-item> </el-col> </el-row> <el-form-item prop="desc" label="應(yīng)用簡(jiǎn)介"> <el-input type="textarea" v-model="appDetail.desc" :rows="3" style="width: 360px" ></el-input> </el-form-item> <el-form-item prop="introduction" label="應(yīng)用詳情"> <div style="border: 1px solid #ccc; "> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" class="barStyle" /> <Editor style="height: 500px; overflow-y: hidden;" v-model="appDetail.introduction" :defaultConfig="editorConfig" :mode="mode" @onCreated="onCreated" class="editorStyle" /> </div> </el-form-item> </el-form> <el-button class="save_btn" type="primary" @click="onSubmit" :loading="commitLoading" >保存</el-button > </div> </template> <script> import { updateApp } from '@/api/app'; import { getStoreAvailableTags } from '@/api/appStore'; import { getToken } from '@/utils/auth'; import axios from 'axios'; import { errorHandle } from '../../../../utils/error'; import { Editor, Toolbar } from '@wangeditor/editor-for-vue'; import { IToolbarConfig, DomEditor, IEditorConfig } from '@wangeditor/editor' export default { name: 'BasicInfo', components: { Editor, Toolbar }, props: { appDetail: { type: Object }, marketID: { type: String }, Loading: Boolean }, data() { var baseDomain = process.env.BASE_API; if (baseDomain == '/') { baseDomain = window.location.origin; } const isChinese = (temp) => { return /^[\u4e00-\u9fa5]+$/i.test(temp); }; const tagValidate = (rule, value, callback) => { let checked = true; value.map((tag) => { if (tag.length < 2) { callback('每個(gè)標(biāo)簽至少兩個(gè)字符'); checked = false; return; } if (isChinese(tag) && tag.length > 5) { callback('中文標(biāo)簽字?jǐn)?shù)應(yīng)處于2-5個(gè)之間'); checked = false; return; } if (Number(tag) > 0) { callback('標(biāo)簽不能為純數(shù)字組成'); checked = false; return; } }); if (checked) { callback(); } }; return { editor: null, toolbarConfig: { excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"] }, editorConfig: { placeholder: '請(qǐng)輸入內(nèi)容...' , MENU_CONF: { uploadImage: { customUpload: this.uploadImg, }, } }, mode: 'default', // or 'simple' commitLoading: false, classes: [], existTags: [], appPublishTypes: [ { value: 'public', label: '免費(fèi)公開(kāi)' }, { value: 'integral', label: '金額銷售' }, { value: 'private', label: '私有' }, { value: 'show', label: '展覽' } ], uploadConfig: { api: `${baseDomain}/app-server/uploads/picture`, headers: { Authorization: getToken() }, }, editorOption: {}, rules: { name: [ { required: true, message: '應(yīng)用名稱不能為空', trigger: 'blur' }, { min: 2, message: '至少兩個(gè)字符', trigger: 'blur' }, { max: 24, message: '應(yīng)用名稱建議不超過(guò)24個(gè)字符', trigger: 'blur' } ], desc: [ { required: true, message: '應(yīng)用簡(jiǎn)介不能為空', trigger: 'blur' }, { min: 10, message: '至少10個(gè)字符', trigger: 'blur' }, { max: 82, message: '描述最多82個(gè)字符', trigger: 'blur' } ], introduction: [ { max: 10140, message: '描述最多10240個(gè)字符', trigger: 'blur' } ], tags: [{ validator: tagValidate, trigger: 'change' }] } }; }, created() { this.fetchStoreAppClassList(); this.fetchStoreAppTags(); }, computed: { myorgs() { return this.$store.state.user.userOrgs; } }, methods: { uploadImg(file, insertFn){ let imgData = new FormData(); imgData.append('file', file); axios({ url: this.uploadConfig.api, method: 'post', data: imgData, }).then((response) => { insertFn(response.data.FileURL); }); }, onCreated(editor) { this.editor = Object.seal(editor) }, fetchStoreAppTags() { getStoreAvailableTags({ marketID: this.marketID, size: -1 }) .then((res) => { if (res && res.tags) { const tags = []; res.tags.map((item) => { tags.push(item.name); }); this.existTags = tags; } }) .catch((err) => { this.Loading = false; }); }, fetchStoreAppClassList() { this.$store .dispatch('GetStoreAppClassificationList', { marketID: this.marketID, disableTree: true }) .then((res) => { if (res) { this.classes = res; } }) .catch(() => {}); }, fetchUserOrgs() { this.$store .dispatch('GetUserOrgList') .then((res) => { if (res) { this.myorgs = res; } }) .catch(() => {}); }, markdownContentUpdate(md, render) { this.appData.introduction_html = render; }, markdownImgAdd(pos, $file) { // 第一步.將圖片上傳到服務(wù)器. var formdata = new FormData(); formdata.append('file', $file); axios({ url: this.api, method: 'post', data: formdata, headers: this.Token }).then((re) => { if (re && re.data && re.data.data) { this.$refs.md.$img2Url(pos, re.data.data); } }); }, handleAvatarSuccess(res, file) { this.appDetail.logo = res.FileURL; }, handleAvatarError(re) { if (re.code == 10024) { this.$message.warning( '上傳圖片類型不支持,請(qǐng)上傳以.png .jpg .jpeg 結(jié)尾的圖片' ); return; } this.$message.warning('上傳失敗!'); }, beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isPng = file.type === 'image/png'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG && !isPng) { this.$message.warning('上傳Logo圖片只能是JPG、PNG格式!'); } if (!isLt2M) { this.$message.warning('上傳頭像圖片大小不能超過(guò) 2MB!'); } return (isJPG || isPng) && isLt2M; }, handleRemove() { this.$confirm('是否刪除logo', '提示', { confirmButtonText: '確定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.appDetail.logo = ''; }); }, handlePictureCardPreview(file) { this.dialogImageUrl = file.url; this.dialogVisible = true; }, changeSelectApp_type_id(value) { this.appData.app_type_id = value; this.$forceUpdate(); }, changeSelectPublish_type(value) { this.appData.publish_type = value; this.$forceUpdate(); }, onSubmit() { this.$refs.form.validate((valid) => { if (valid) { this.commitLoading = true; this.$confirm('是否提交數(shù)據(jù)', '提示', { confirmButtonText: '確定', cancelButtonText: '取消', type: 'warning' }) .then(() => { updateApp(this.appDetail) .then((res) => { this.$message.success('應(yīng)用信息更新成功'); this.commitLoading = false; }) .catch((err) => { errorHandle(err); this.commitLoading = false; }); }) .catch(() => { this.commitLoading = false; }); } else { return false; } }); } } }; </script> <style lang="scss" scoped > .app_detail { position: relative; padding-bottom: 20px; .save_btn { margin-left: 80px; } .el-select { width: 100%; } } .editorStyle{ /deep/ .w-e-text-container>.w-e-scroll>div ol li{ list-style: auto ; } /deep/ .w-e-text-container>.w-e-scroll>div ul li{ list-style: disc ; } /deep/ .w-e-text-placeholder{ top:7px; } } .barStyle{ /deep/ .w-e-bar-item{ padding:2.5px } /deep/ .w-e-bar-item > button >.title{ border-left:0 !important; } } </style> <style src="@wangeditor/editor/dist/css/style.css" > .inputdesc { font-size: 12px; color: rgba(0, 0, 0, 0.45); transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1); } .app_detail img { width: auto; } .app_detail .ql-formats { line-height: 22px; } </style>
總結(jié)
到此這篇關(guān)于vue中wangEditor5編輯器的基本使用的文章就介紹到這了,更多相關(guān)vue wangEditor5的使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js每天必學(xué)之過(guò)濾器與自定義過(guò)濾器
Vue.js每天必學(xué)之過(guò)濾器與自定義過(guò)濾器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Vue+axios使用FormData方式向后端發(fā)送數(shù)據(jù)
在前后端分離的項(xiàng)目中經(jīng)常使用到Vue+axios通過(guò)FormData的方式向后端發(fā)送表單數(shù)據(jù),下面就來(lái)介紹一下如何實(shí)現(xiàn),感興趣的可以了解一下2023-09-09vue前端實(shí)現(xiàn)驗(yàn)證碼登錄功能
這篇文章主要介紹了vue前端實(shí)現(xiàn)驗(yàn)證碼登錄功能,登錄時(shí)圖形驗(yàn)證通過(guò)三種方法結(jié)合實(shí)例代碼給大家講解的非常詳細(xì), 通過(guò)實(shí)例代碼介紹了vue登錄時(shí)圖形驗(yàn)證碼功能的實(shí)現(xiàn),感興趣的朋友一起看看吧2023-12-12vue-cli開(kāi)發(fā)時(shí),關(guān)于ajax跨域的解決方法(推薦)
下面小編就為大家分享一篇vue-cli開(kāi)發(fā)時(shí),關(guān)于ajax跨域的解決方法(推薦),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02vue單頁(yè)面打包文件大?首次加載慢?nginx帶你飛,從7.5M到1.3M蛻變過(guò)程(推薦)
這篇文章主要介紹了vue單頁(yè)面打包文件大?首次加載慢?nginx帶你飛,從7.5M到1.3M蛻變過(guò)程,需要的朋友可以參考下2018-01-01vue3.0+echarts實(shí)現(xiàn)立體柱圖
這篇文章主要為大家詳細(xì)介紹了vue3.0+echarts實(shí)現(xiàn)立體柱圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09vue-router路由懶加載及實(shí)現(xiàn)的3種方式
這篇文章主要給大家介紹了關(guān)于vue-router路由懶加載及實(shí)現(xiàn)的3種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02