feat: 优化图片尺寸用于移动端
This commit is contained in:
parent
492e0055f0
commit
2ed5b64b18
1
web/components.d.ts
vendored
1
web/components.d.ts
vendored
@ -17,7 +17,6 @@ declare module 'vue' {
|
|||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||||
|
@ -1,20 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editor-wrapper border">
|
<div class="editor-wrapper border">
|
||||||
<Toolbar :class="['toolbar', props.staticToolBar ? 'static-toolbar' : 'dynamic-toolbar']" ref="toolbar"
|
<Toolbar
|
||||||
v-show="showToolbar" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
:class="['toolbar', props.staticToolBar ? 'static-toolbar' : 'dynamic-toolbar']"
|
||||||
<Editor class="editor" ref="editor" :modelValue="curValue" :defaultConfig="editorConfig" @onCreated="onCreated"
|
ref="toolbar"
|
||||||
@onChange="onChange" @onBlur="onBlur" @onFocus="onFocus" :mode="mode" />
|
v-show="showToolbar"
|
||||||
|
:editor="editorRef"
|
||||||
|
:defaultConfig="toolbarConfig"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
<Editor
|
||||||
|
class="editor"
|
||||||
|
ref="editor"
|
||||||
|
:modelValue="curValue"
|
||||||
|
:defaultConfig="editorConfig"
|
||||||
|
@onCreated="onCreated"
|
||||||
|
@onChange="onChange"
|
||||||
|
@onBlur="onBlur"
|
||||||
|
@onFocus="onFocus"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import '@wangeditor/editor/dist/css/style.css'
|
|
||||||
import './styles/reset-wangeditor.scss'
|
|
||||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
|
||||||
import { ref, shallowRef, onBeforeMount, watch, computed } from 'vue'
|
import { ref, shallowRef, onBeforeMount, watch, computed } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { get as _get } from 'lodash-es'
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
import './styles/reset-wangeditor.scss'
|
||||||
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
|
|
||||||
|
import { replacePxWithRem } from './utils'
|
||||||
|
|
||||||
const emit = defineEmits(['input', 'onFocus', 'change', 'blur', 'created'])
|
const emit = defineEmits(['input', 'onFocus', 'change', 'blur', 'created'])
|
||||||
const model = defineModel()
|
const model = defineModel()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -34,7 +52,7 @@ const toolbarConfig = computed(() => {
|
|||||||
'color', // 字体色
|
'color', // 字体色
|
||||||
'bgColor', // 背景色
|
'bgColor', // 背景色
|
||||||
'bold',
|
'bold',
|
||||||
'insertLink', // 链接
|
'insertLink' // 链接
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if (props.needUploadImage) {
|
if (props.needUploadImage) {
|
||||||
@ -51,6 +69,7 @@ const editorConfig = {
|
|||||||
const store = useStore()
|
const store = useStore()
|
||||||
const token = _get(store, 'state.user.userInfo.token')
|
const token = _get(store, 'state.user.userInfo.token')
|
||||||
|
|
||||||
|
// 图片
|
||||||
editorConfig.MENU_CONF['uploadImage'] = {
|
editorConfig.MENU_CONF['uploadImage'] = {
|
||||||
allowedFileTypes: ['image/jpeg', 'image/png'],
|
allowedFileTypes: ['image/jpeg', 'image/png'],
|
||||||
server: '/api/file/upload',
|
server: '/api/file/upload',
|
||||||
@ -65,7 +84,7 @@ editorConfig.MENU_CONF['uploadImage'] = {
|
|||||||
customInsert(res, insertFn) {
|
customInsert(res, insertFn) {
|
||||||
const url = res.data.url
|
const url = res.data.url
|
||||||
insertFn(url, '', '')
|
insertFn(url, '', '')
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setHtml = (newHtml) => {
|
const setHtml = (newHtml) => {
|
||||||
@ -82,7 +101,8 @@ const onCreated = (editor) => {
|
|||||||
emit('created', editor)
|
emit('created', editor)
|
||||||
}
|
}
|
||||||
const onChange = (editor) => {
|
const onChange = (editor) => {
|
||||||
const editorHtml = editor.getHtml()
|
const editorHtml = replacePxWithRem(editor.getHtml())
|
||||||
|
|
||||||
curValue.value = editorHtml // 记录当前 html 内容
|
curValue.value = editorHtml // 记录当前 html 内容
|
||||||
emit('input', editorHtml) // 用于自定义 v-model
|
emit('input', editorHtml) // 用于自定义 v-model
|
||||||
}
|
}
|
||||||
|
31
web/src/common/Editor/utils.js
Normal file
31
web/src/common/Editor/utils.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// px 转换为 rem
|
||||||
|
const pxToRem = (px) => {
|
||||||
|
return `${(parseFloat(px) / 50).toFixed(2)}rem`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片style的宽高改成rem
|
||||||
|
export const replacePxWithRem = (html) => {
|
||||||
|
const imgRegex = /<img[^>]*style=["'][^"']*\b(?:width|height):\s*\d+(\.\d+)?px[^"']*["'][^>]*>/gi
|
||||||
|
const styleRegex = /style="([^"]*)"/g
|
||||||
|
if (!imgRegex.test(html)) {
|
||||||
|
console.log('无需修改')
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = html.replaceAll(imgRegex, (imgHtml) => {
|
||||||
|
return imgHtml.replace(styleRegex, (match, content) => {
|
||||||
|
let styleContent = content
|
||||||
|
const pxRegex = /(width|height):\s*(\d+(\.\d+)?)px/g
|
||||||
|
|
||||||
|
styleContent = styleContent.replace(pxRegex, (pxMatch, prop, value) => {
|
||||||
|
return `${prop}: ${pxToRem(value)}`
|
||||||
|
})
|
||||||
|
|
||||||
|
return `style="${styleContent}"`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('生成的结果', res)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
@ -31,7 +31,9 @@ export const cleanRichTextWithMediaTag = (text) => {
|
|||||||
if (!text) {
|
if (!text) {
|
||||||
return text === 0 ? 0 : ''
|
return text === 0 ? 0 : ''
|
||||||
}
|
}
|
||||||
const html = transformHtmlTag(text).replace(/<img([\w\W]+?)\/>/g,'[图片]').replace(/<video.*\/video>/g,'[视频]')
|
const html = transformHtmlTag(text)
|
||||||
|
.replace(/<img([\w\W]+?)\/>/g, '[图片]')
|
||||||
|
.replace(/<video.*\/video>/g, '[视频]')
|
||||||
const content = html.replace(/<[^<>]+>/g, '').replace(/ /g, '')
|
const content = html.replace(/<[^<>]+>/g, '').replace(/ /g, '')
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
@ -6,9 +6,12 @@
|
|||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
'tab-btn',
|
'tab-btn',
|
||||||
(['QuestionEditIndex', 'QuestionEditSetting', 'QuestionSkinSetting'].includes(
|
([
|
||||||
route.name
|
'QuestionEditIndex',
|
||||||
) &&
|
'QuestionEditSetting',
|
||||||
|
'QuestionSkinSetting',
|
||||||
|
'QuestionEditResultConfig'
|
||||||
|
].includes(route.name) &&
|
||||||
tab.to.name === 'QuestionEditIndex') ||
|
tab.to.name === 'QuestionEditIndex') ||
|
||||||
isActive
|
isActive
|
||||||
? 'router-link-active'
|
? 'router-link-active'
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
:label="item.title"
|
:label="item.title"
|
||||||
minWidth="200"
|
minWidth="200"
|
||||||
>
|
>
|
||||||
|
|
||||||
<template #header="scope">
|
<template #header="scope">
|
||||||
<div class="table-row-cell">
|
<div class="table-row-cell">
|
||||||
<span
|
<span
|
||||||
class="table-row-head"
|
class="table-row-head"
|
||||||
|
@click="onPreviewImage"
|
||||||
@mouseover="onPopoverRefOver(scope, 'head')"
|
@mouseover="onPopoverRefOver(scope, 'head')"
|
||||||
:ref="(el) => (popoverRefMap[scope.column.id] = el)"
|
:ref="(el) => (popoverRefMap[scope.column.id] = el)"
|
||||||
v-html="item.title"
|
v-html="item.title"
|
||||||
@ -46,21 +46,19 @@
|
|||||||
ref="popover"
|
ref="popover"
|
||||||
popper-style="text-align: center;font-size: 13px;"
|
popper-style="text-align: center;font-size: 13px;"
|
||||||
:virtual-ref="popoverVirtualRef"
|
:virtual-ref="popoverVirtualRef"
|
||||||
placement="top"
|
placement="bottom"
|
||||||
width="400"
|
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
virtual-triggering
|
virtual-triggering
|
||||||
>
|
>
|
||||||
<div v-html="popoverContent"></div>
|
<div v-html="popoverContent"></div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
|
|
||||||
<ImagePreview :url="previewImageUrl" v-model:visible="showPreviewImage"/>
|
<ImagePreview :url="previewImageUrl" v-model:visible="showPreviewImage" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { cleanRichText } from '@/common/xss'
|
|
||||||
import ImagePreview from './ImagePreview.vue'
|
import ImagePreview from './ImagePreview.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -106,7 +104,6 @@ const onPreviewImage = (e) => {
|
|||||||
previewImageUrl.value = e.target.src
|
previewImageUrl.value = e.target.src
|
||||||
showPreviewImage.value = true
|
showPreviewImage.value = true
|
||||||
}
|
}
|
||||||
console.log(e.target.src)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -140,8 +137,10 @@ const onPreviewImage = (e) => {
|
|||||||
overflow: hidden; /* 超出部分隐藏 */
|
overflow: hidden; /* 超出部分隐藏 */
|
||||||
text-overflow: ellipsis; /* 显示省略号 */
|
text-overflow: ellipsis; /* 显示省略号 */
|
||||||
:deep(img) {
|
:deep(img) {
|
||||||
height: 23px;
|
height: 23px !important;
|
||||||
width: auto;
|
width: auto !important;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
:deep(p) {
|
:deep(p) {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -153,8 +152,3 @@ const onPreviewImage = (e) => {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
|
||||||
.el-popover p image {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<Transition>
|
<Transition>
|
||||||
<div class="image-preview" v-show="visible">
|
<div class="image-preview" v-show="visible">
|
||||||
<div class="close-btn" @click="visible = false"> <i-ep-close /> </div>
|
<div class="close-btn" @click="visible = false"><i-ep-close /></div>
|
||||||
<div class="image-con">
|
<div class="image-con">
|
||||||
<img :src="props.url" class="image-item" />
|
<img :src="props.url" class="image-item" />
|
||||||
</div>
|
</div>
|
||||||
@ -16,7 +16,6 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const visible = defineModel('visible')
|
const visible = defineModel('visible')
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.v-enter-active,
|
.v-enter-active,
|
||||||
@ -35,7 +34,7 @@ const visible = defineModel('visible')
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: rgba($color: #000000, $alpha: .4);
|
background-color: rgba($color: #000000, $alpha: 0.4);
|
||||||
z-index: 2024;
|
z-index: 2024;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -54,7 +53,6 @@ const visible = defineModel('visible')
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.close-btn {
|
.close-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
@ -58,7 +58,7 @@ watch(
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 9999;
|
z-index: 999;
|
||||||
:deep(.el-radio-button__original-radio + .el-radio-button__inner) {
|
:deep(.el-radio-button__original-radio + .el-radio-button__inner) {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
@ -5,4 +5,4 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user