123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- <template>
- <div>
- <article :id="id" :style="fullScreen ? { ...fullPositionStyle, ...styles } : styles" class="article" :class="getClass">
- <!-- <textEditor :id="id" :value="inputValue" /> -->
- <span v-show="fullScreen" class="changeSizeBtn" @click="changeSize">
- <svg-icon
- icon-class="icon-sx"
- class="icon"
- />
- </span>
- <span v-show="!fullScreen" class="changeSizeBtn" @click="changeSize">
- <svg-icon
- icon-class="icon-qp"
- class="icon"
- />
- </span>
- <editor :id="'tinymce_'+id" ref="editor" v-model="inputValue" :init="init" @input="changeText" />
- </article>
- </div>
- </template>
- <script>
- import axios from 'axios'
- import tinymce from 'tinymce/tinymce'
- import Editor from '@tinymce/tinymce-vue'
- import 'tinymce/themes/silver/theme'
- import 'tinymce/icons/default/icons'
- // import { uploadImage } from '@/api/common.js'
- // import textEditor from './editor'
- export default {
- components: {
- Editor
- // textEditor
- },
- props: {
- id: {
- type: String,
- default: '',
- required: true
- },
- value: {
- type: String,
- default: '',
- required: false
- },
- height: {
- type: Number,
- default: 200,
- required: false
- },
- fullPositionStyle: {
- type: Object,
- default: () => {
- return { }
- },
- required: false
- },
- styles: {
- type: Object,
- default: () => {
- return { }
- },
- required: false
- },
- bottomMargin: {
- type: Boolean,
- default: false,
- required: false
- }
- },
- data() {
- return {
- fullScreen: false,
- inputValue: '',
- edit: false,
- init: {
- auto_focus: false,
- language_url: '/tinymce/langs/zh_CN.js',
- language: 'zh_CN',
- skin_url: '/tinymce/skins/ui/oxide', // 编辑器需要一个skin才能正常工作,所以要设置一个skin_url指向之前复制出来的skin文件
- height: this.height,
- browser_spellcheck: true, // 拼写检查
- branding: false, // 去水印
- elementpath: false, // 禁用编辑器底部的状态栏
- statusbar: false, // 隐藏编辑器底部的状态栏
- paste_data_images: true, // 允许粘贴图像
- menubar: false, // 隐藏最上方menu
- fontsize_formats: '14px 16px 18px 20px 24px 26px 28px 30px 32px 36px', // 字体大小
- file_picker_types: 'image',
- images_upload_credentials: true,
- plugins: 'fullscreen lists table textcolor wordcount contextmenu', // 引入插件
- toolbar: 'fullscreen bold italic underline strikethrough | fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent table | undo redo | removeformat formatselect',
- table_toolbar: 'tableprops | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol | tablemergecells tablesplitcells'
- }
- }
- },
- computed: {
- getClass() {
- let className = ''
- if (this.fullScreen) {
- className += 'fullScreen'
- }
- if (this.bottomMargin) {
- className += ' bottomMargin'
- }
- return className
- }
- },
- watch: {
- value: {
- handler(newV, oldV) {
- console.log('new', newV, 'old', oldV)
- // resetImgSrc
- this.inputValue = this.resetImgSrc(newV)
- },
- immediate: true
- }
- },
- mounted() {
- tinymce.init({ selector: `#tinymce_${this.id}` })
- },
- methods: {
- async resetImgSrc(str) {
- let newStr = str
- const imgReg = /<img.*?(?:>|\/>)/gi
- const srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i
- const imgArr = newStr.match(imgReg)
- console.log(imgArr)
- imgArr && imgArr.map(async t => {
- var src = t.match(srcReg)
- console.log(src)
- if (src[1] && src[1].includes('data:image')) {
- // var t = src[0].replace(/src/i, "href");
- // alert(t);
- // const res = await uploadImage({
- // 'imgData': src[1],
- // 'innerPublic': true
- // })
- const newImgUrl = await this.uploadImg(src[1])
- newStr = newStr.replace(src[1], newImgUrl)
- console.log(newStr)
- console.log(src[1])
- }
- })
- console.log('newStr', newStr)
- console.log('str', str)
- return newStr
- },
- uploadImg(imgData) {
- // var fd = new FormData();
- // fd.append('file', this.base64Url2Blob(imgData));
- // fd.append('innerPublic',true);
- const config = {
- headers: {
- // 'Content-Type': 'multipart/form-data'
- 'Content-Type': 'multipart/json'
- },
- withCredentials: false
- } // 添加请求头
- return new Promise((resolve, reject) => {
- axios.post(
- '//star.xiaojukeji.com/upload/img.node',
- // fd,
- {
- 'imgData': imgData,
- 'innerPublic': true
- },
- config
- ).then(res => {
- console.log(res)
- // newStr = newStr.replace(imgData, res.url)
- resolve(res.url)
- }).catch(err => {
- reject(err)
- })
- })
- },
- base64Url2Blob (url) {
- // 将base64url通过 , 分割为含有两个元素的数组
- const temp = url.split(',')
- // 将图片的base64编码数据解码
- const bytes = window.atob(temp[1])
- // 匹配图片的 mime
- const mime = temp[0].match(/:(.*?);/)[1]
- // 创建一个类型化数组,该数组的长度与解码后的图片数据长度相同
- let ia = new Uint8Array(bytes.length)
- // 变量图片数据的每一位,并将每一位的 Unicode 编码存入类型化数组
- for (let i = 0; i < bytes.length; i++) {
- ia[i] = bytes.charCodeAt(i)
- }
- // 通过类型化数组创建一个 Blob 对象
- return new Blob([ia], {type: mime})
- },
- changeText(e) { // 富文本内容改变
- this.inputValue = e
- this.$emit('update:value', this.inputValue)
- this.$emit('change', this.inputValue)
- },
- changeSize() {
- this.fullScreen = !this.fullScreen
- }
- }
- }
- </script>
- <style scoped lang="less">
- .article {
- position: relative;
- .changeSizeBtn {
- position: absolute;
- top: 3px;
- right: 0px;
- z-index: 1000;
- height: 34px;
- width: 24px;
- text-align: center;
- line-height: 34px;
- border-radius: 3px;
- .icon {
- color: #409eff;
- font-weight: 700;
- font-size: 18px;
- }
- &:hover {
- background: #c8cbcf;
- border: 0;
- box-shadow: none;
- }
- }
- }
- .fullScreen {
- position: fixed;
- top: 0px;
- bottom: 0;
- left: 225px;
- right: 0;
- z-index: 1000;
- height: 100vh!important;
- /deep/.tox-tinymce {
- height: 100vh!important;
- }
- &.bottomMargin {
- /deep/.tox-tinymce {
- height: calc(100vh - 40px)!important;
- }
- }
- }
- .editor {
- border: 1px solid #666;
- }
- </style>
|