长文图片缩放:编辑器拖拽把手的比例在文章页生效(alt 数字还原为宽度并居中)+ 把手默认半透明提高可发现性
This commit is contained in:
@@ -1384,3 +1384,7 @@ a.cm-name-a:hover {color: var(--accent);}
|
||||
.cm-more-r {padding: 10px 0;}
|
||||
.cm-input {font-size: 16px;}
|
||||
}
|
||||
/* 编辑器图片缩放把手:Milkdown 图片块 hover 底部出现拖拽条(上下拖调高度,
|
||||
比例存进 markdown 的 alt)。默认半透明让访客知道它在那儿。 */
|
||||
.admin-shell .image-resize-handle {opacity: 0.45;}
|
||||
.admin-shell .image-wrapper:hover .image-resize-handle {opacity: 1;}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { sanitizeHtml } from '../../utils'
|
||||
import { applyImageRatio, sanitizeHtml } from '../../utils'
|
||||
import { openLightbox } from '../../lightbox'
|
||||
import CommentSection from '../../components/comments/CommentSection.vue'
|
||||
import LinkCard from '../../components/LinkCard.vue'
|
||||
@@ -168,7 +168,7 @@ function onTocClick(e) {
|
||||
<!-- 短文不渲染标题:正文第一句就是全部,再给个截断标题是重复 -->
|
||||
<h1 v-if="isShort" class="sr-only">{{ title }}</h1>
|
||||
|
||||
<div class="prose" :class="{ 'prose-note': isShort }" v-html="sanitizeHtml(props.contentHtml)" />
|
||||
<div class="prose" :class="{ 'prose-note': isShort }" v-html="applyImageRatio(sanitizeHtml(props.contentHtml))" />
|
||||
|
||||
<!-- 短文配图:Twitter 式网格(快发盒上传);点图开预览 -->
|
||||
<div
|
||||
|
||||
@@ -28,6 +28,22 @@ export function thumbURL(u, w = 480) {
|
||||
return '/uploads/thumb/' + key + '?w=' + w
|
||||
}
|
||||
|
||||
// 编辑器拖拽缩放的比例展示:Milkdown 图片块把高度比例写进 markdown 的 alt
|
||||
// (),渲染出的 <img alt="0.6"> 在这里还原成对应的宽度并居中。
|
||||
// 纯数字 alt 才生效(>=1 的当 100% 处理),正常图片的描述性 alt 不受影响。
|
||||
export function applyImageRatio(html) {
|
||||
if (!html) return html
|
||||
return html.replace(/<img\b[^>]*>/gi, (tag) => {
|
||||
const m = tag.match(/\balt="(\d*\.?\d+)"/i)
|
||||
if (!m) return tag
|
||||
const ratio = Number.parseFloat(m[1])
|
||||
if (!Number.isFinite(ratio) || ratio <= 0 || ratio >= 1) return tag
|
||||
const style = `display:block;width:${(ratio * 100).toFixed(1)}%;max-width:100%;height:auto;margin-inline:auto;`
|
||||
if (/\bstyle="/i.test(tag)) return tag.replace(/\bstyle="/i, 'style="' + style)
|
||||
return tag.replace(/^<img/i, '<img style="' + style + '"')
|
||||
})
|
||||
}
|
||||
|
||||
// 时间线正文 HTML(短文全文 / 长文 600 字符截断)里的 <img> 换缩略图 + 补懒加载。
|
||||
// 只在展示层重写,库里存的正文不动。截断的 HTML 可能带半截标签,
|
||||
// 正则只匹配完整的 <img ...src="..."> ,坏尾巴交给 sanitize/浏览器容错。
|
||||
|
||||
@@ -9,7 +9,7 @@ import LinkCard from '../components/LinkCard.vue'
|
||||
import { openLightbox } from '../lightbox'
|
||||
import { publicApi } from '../api'
|
||||
import { site, applyDocTitle } from '../site'
|
||||
import { formatDate, minutesLabel, sanitizeHtml } from '../utils'
|
||||
import { applyImageRatio, formatDate, minutesLabel, sanitizeHtml } from '../utils'
|
||||
|
||||
const route = useRoute()
|
||||
const post = ref(null)
|
||||
@@ -42,7 +42,7 @@ async function load() {
|
||||
try {
|
||||
post.value = await publicApi.post(route.params.slug)
|
||||
const prepared = withHeadingIds(post.value.content_html)
|
||||
contentHtml.value = prepared.html
|
||||
contentHtml.value = applyImageRatio(prepared.html)
|
||||
headings.value = prepared.headings
|
||||
applyDocTitle(post.value.kind === 'short' ? '短文' : post.value.title)
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user