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']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
|
@ -1,20 +1,38 @@
|
||||
<template>
|
||||
<div class="editor-wrapper border">
|
||||
<Toolbar :class="['toolbar', props.staticToolBar ? 'static-toolbar' : 'dynamic-toolbar']" ref="toolbar"
|
||||
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" />
|
||||
<Toolbar
|
||||
:class="['toolbar', props.staticToolBar ? 'static-toolbar' : 'dynamic-toolbar']"
|
||||
ref="toolbar"
|
||||
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>
|
||||
</template>
|
||||
|
||||
<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 { useStore } from 'vuex'
|
||||
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 model = defineModel()
|
||||
const props = defineProps({
|
||||
@ -34,7 +52,7 @@ const toolbarConfig = computed(() => {
|
||||
'color', // 字体色
|
||||
'bgColor', // 背景色
|
||||
'bold',
|
||||
'insertLink', // 链接
|
||||
'insertLink' // 链接
|
||||
]
|
||||
}
|
||||
if (props.needUploadImage) {
|
||||
@ -51,6 +69,7 @@ const editorConfig = {
|
||||
const store = useStore()
|
||||
const token = _get(store, 'state.user.userInfo.token')
|
||||
|
||||
// 图片
|
||||
editorConfig.MENU_CONF['uploadImage'] = {
|
||||
allowedFileTypes: ['image/jpeg', 'image/png'],
|
||||
server: '/api/file/upload',
|
||||
@ -65,7 +84,7 @@ editorConfig.MENU_CONF['uploadImage'] = {
|
||||
customInsert(res, insertFn) {
|
||||
const url = res.data.url
|
||||
insertFn(url, '', '')
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const setHtml = (newHtml) => {
|
||||
@ -82,7 +101,8 @@ const onCreated = (editor) => {
|
||||
emit('created', editor)
|
||||
}
|
||||
const onChange = (editor) => {
|
||||
const editorHtml = editor.getHtml()
|
||||
const editorHtml = replacePxWithRem(editor.getHtml())
|
||||
|
||||
curValue.value = editorHtml // 记录当前 html 内容
|
||||
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) {
|
||||
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, '')
|
||||
|
||||
return content
|
||||
|
@ -6,9 +6,12 @@
|
||||
<div
|
||||
:class="[
|
||||
'tab-btn',
|
||||
(['QuestionEditIndex', 'QuestionEditSetting', 'QuestionSkinSetting'].includes(
|
||||
route.name
|
||||
) &&
|
||||
([
|
||||
'QuestionEditIndex',
|
||||
'QuestionEditSetting',
|
||||
'QuestionSkinSetting',
|
||||
'QuestionEditResultConfig'
|
||||
].includes(route.name) &&
|
||||
tab.to.name === 'QuestionEditIndex') ||
|
||||
isActive
|
||||
? 'router-link-active'
|
||||
|
@ -16,11 +16,11 @@
|
||||
:label="item.title"
|
||||
minWidth="200"
|
||||
>
|
||||
|
||||
<template #header="scope">
|
||||
<div class="table-row-cell">
|
||||
<span
|
||||
class="table-row-head"
|
||||
@click="onPreviewImage"
|
||||
@mouseover="onPopoverRefOver(scope, 'head')"
|
||||
:ref="(el) => (popoverRefMap[scope.column.id] = el)"
|
||||
v-html="item.title"
|
||||
@ -46,21 +46,19 @@
|
||||
ref="popover"
|
||||
popper-style="text-align: center;font-size: 13px;"
|
||||
:virtual-ref="popoverVirtualRef"
|
||||
placement="top"
|
||||
width="400"
|
||||
placement="bottom"
|
||||
trigger="hover"
|
||||
virtual-triggering
|
||||
>
|
||||
<div v-html="popoverContent"></div>
|
||||
</el-popover>
|
||||
|
||||
<ImagePreview :url="previewImageUrl" v-model:visible="showPreviewImage"/>
|
||||
<ImagePreview :url="previewImageUrl" v-model:visible="showPreviewImage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { cleanRichText } from '@/common/xss'
|
||||
import ImagePreview from './ImagePreview.vue'
|
||||
|
||||
const props = defineProps({
|
||||
@ -106,7 +104,6 @@ const onPreviewImage = (e) => {
|
||||
previewImageUrl.value = e.target.src
|
||||
showPreviewImage.value = true
|
||||
}
|
||||
console.log(e.target.src)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -140,8 +137,10 @@ const onPreviewImage = (e) => {
|
||||
overflow: hidden; /* 超出部分隐藏 */
|
||||
text-overflow: ellipsis; /* 显示省略号 */
|
||||
:deep(img) {
|
||||
height: 23px;
|
||||
width: auto;
|
||||
height: 23px !important;
|
||||
width: auto !important;
|
||||
object-fit: cover;
|
||||
margin-left: 5px;
|
||||
}
|
||||
:deep(p) {
|
||||
display: flex;
|
||||
@ -153,8 +152,3 @@ const onPreviewImage = (e) => {
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.el-popover p image {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Teleport to="body">
|
||||
<Transition>
|
||||
<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">
|
||||
<img :src="props.url" class="image-item" />
|
||||
</div>
|
||||
@ -16,7 +16,6 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const visible = defineModel('visible')
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.v-enter-active,
|
||||
@ -35,7 +34,7 @@ const visible = defineModel('visible')
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba($color: #000000, $alpha: .4);
|
||||
background-color: rgba($color: #000000, $alpha: 0.4);
|
||||
z-index: 2024;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -54,7 +53,6 @@ const visible = defineModel('visible')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
|
@ -58,7 +58,7 @@ watch(
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
cursor: pointer;
|
||||
z-index: 9999;
|
||||
z-index: 999;
|
||||
:deep(.el-radio-button__original-radio + .el-radio-button__inner) {
|
||||
font-size: 12px;
|
||||
height: 28px;
|
||||
|
@ -5,4 +5,4 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user