<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
wangEditor是一款富文字編譯器外掛,其他的我就不再過多贅述,因為官網上有一大截對於這個編譯器的介紹,但我摸索使用的這兩天裡給我的最直觀的感受就是,它是由中國開發者開發,所有的檔案都是中文的,這一點上對我這個菜雞來說非常友好,不用再去逐字逐句翻譯,然後去讀那些蹩腳的機翻中文。而且功能很豐富,能夠滿足很多需求,wangEditor5提供很多版本的程式碼,vue2,vue3,react都支援。
接下來就介紹一下wangEditor5的基本使用,以及博主在使用中遇到的各種問題以及其解決方案。
官方網站:
wangEditor開源 Web 富文字編輯器,開箱即用,設定簡單https://www.wangeditor.com/
yarn add @wangeditor/editor-for-vue # 或者 npm install @wangeditor/editor-for-vue --save
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
Editor:引入@wangEditor編譯器
Toolbar:引入選單欄
<style src="@wangeditor/editor/dist/css/style.css" > </style>
這裡需要注意,引入的樣式寫在帶有scoped標籤的style內無效。只能引入在全域性樣式裡,但可能會造成樣式覆蓋,一般會有個清除樣式的檔案,會把裡面的樣式覆蓋掉。
工具列設定有很多選項,這裡以官方為主,我只做一些常用的設定介紹。
查詢編輯器註冊的所有選單 key (可能有的不在工具列上)這裡注意要在
onCreated(editor) { this.editor = Object.seal(editor) },
這個函數中去呼叫 (這個函數是基本設定之一),不然好像調不出來,當然也有可能是博主太菜。
toolbarConfig: { excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"] },
這個是選單欄設定的一種:排除某項設定 ,這裡填寫的key值就是用上面那個方法,查出來的key值。
首先在data中return以下資訊。
editorConfig: { placeholder: '請輸入內容...' , MENU_CONF: { uploadImage: { customUpload: this.uploadImg, }, } },
然後書寫this.uploadImg函數。
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); }); },
注意,這裡因為返回的資料結構與@wangeditor要求的不一致,因此要使用 insertFn 函數 去包裹返回的url地址。
(一)、引入@wangEditor 編譯報錯 " 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有序列表無序列表的樣式消失問題。
大概率是全域性樣式清除導致的樣式消失,可以去偵錯工具裡看一看,樣式覆蓋的問題。
然後在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="應用名稱"> <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="選擇應用分類" > <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">為了適應前臺展示,應用只能屬於二級分類</div> </el-form-item> <el-form-item label="所屬組織"> <el-select v-model="appDetail.orgID" placeholder="請選擇所屬組織" 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="標籤"> <el-select v-model="appDetail.tags" multiple filterable style="width: 360px" placeholder="請輸入或選擇應用標籤" > <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="應用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="應用簡介"> <el-input type="textarea" v-model="appDetail.desc" :rows="3" style="width: 360px" ></el-input> </el-form-item> <el-form-item prop="introduction" label="應用詳情"> <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('每個標籤至少兩個字元'); checked = false; return; } if (isChinese(tag) && tag.length > 5) { callback('中文標籤字數應處於2-5個之間'); checked = false; return; } if (Number(tag) > 0) { callback('標籤不能為純數位組成'); checked = false; return; } }); if (checked) { callback(); } }; return { editor: null, toolbarConfig: { excludeKeys:["uploadVideo","fullScreen","emotion","insertTable"] }, editorConfig: { placeholder: '請輸入內容...' , MENU_CONF: { uploadImage: { customUpload: this.uploadImg, }, } }, mode: 'default', // or 'simple' commitLoading: false, classes: [], existTags: [], appPublishTypes: [ { value: 'public', label: '免費公開' }, { 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: '應用名稱不能為空', trigger: 'blur' }, { min: 2, message: '至少兩個字元', trigger: 'blur' }, { max: 24, message: '應用名稱建議不超過24個字元', trigger: 'blur' } ], desc: [ { required: true, message: '應用簡介不能為空', trigger: 'blur' }, { min: 10, message: '至少10個字元', trigger: 'blur' }, { max: 82, message: '描述最多82個字元', trigger: 'blur' } ], introduction: [ { max: 10140, message: '描述最多10240個字元', 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) { // 第一步.將圖片上傳到伺服器. 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( '上傳圖片型別不支援,請上傳以.png .jpg .jpeg 結尾的圖片' ); 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('上傳頭像圖片大小不能超過 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('是否提交資料', '提示', { confirmButtonText: '確定', cancelButtonText: '取消', type: 'warning' }) .then(() => { updateApp(this.appDetail) .then((res) => { this.$message.success('應用資訊更新成功'); 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>
到此這篇關於vue中wangEditor5編輯器的基本使用的文章就介紹到這了,更多相關vue wangEditor5的使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45