hookehuyr

test(rich-text): 完善 v-html 测试页面功能

- 添加 HTML 实体解析( , &, <, >, ")
- 实现 a 标签替换为 div + data-href 属性
- 添加 PDF 文件链接点击处理(useFileOperation)
- 新增 transformElement 图片处理测试开关
- 清理所有调试 console.log 语句

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
......@@ -50,6 +50,9 @@
<view class="action-btn success" @tap="loadFromAPI">模拟API加载</view>
<view class="action-btn danger" @tap="loadRealApiData">📄 真实API</view>
<view class="action-btn info" @tap="loadRealApiDataWithDiv">📄 真实API(a→div)</view>
<view class="action-btn" :class="transformEnabled ? 'enabled' : ''" @tap="toggleTransform">
{{ transformEnabled ? '✅' : '⚪' }} 图片自动处理
</view>
</view>
<!-- 对比说明 -->
......@@ -88,6 +91,7 @@ const switchCount = ref(0)
const currentContentType = ref('未加载')
const contentLength = ref(0)
const lastAction = ref('页面初始化')
const transformEnabled = ref(false) // 是否启用 transformElement
// 测试 HTML 内容
const testHtml = ref('')
......@@ -306,6 +310,89 @@ const loadRealApiData = () => {
}, 500)
}
// 切换 transformElement
const toggleTransform = () => {
transformEnabled.value = !transformEnabled.value
if (transformEnabled.value) {
// 启用 transformElement
Taro.options.html.transformElement = (el) => {
const nodeName = el.nodeName?.toLowerCase() || ''
const tagName = el.tagName?.toLowerCase() || ''
// 处理 img/image 标签
if (nodeName === 'img' || tagName === 'img' || nodeName === 'image' || tagName === 'image') {
const src = el.getAttribute('src') || ''
// 检查父元素链
let parent = el.parentElement
let isInsideLink = false
let parentChain = []
while (parent) {
const pName = parent.nodeName?.toLowerCase() || ''
const pDataIsLink = parent.getAttribute?.('data-is-link')
const pClassList = parent.classList?.value || ''
parentChain.push(pName)
if (pName === 'a' || pDataIsLink === 'true' || pClassList.includes('_file_list')) {
isInsideLink = true
break
}
parent = parent.parentElement
}
if (isInsideLink) {
// 在链接内,不处理(图标),但必须返回元素让它显示
return el // 直接返回,不做任何修改
}
// 不在链接内,处理(内容图片)
el.setAttribute('mode', 'widthFix')
el.setAttribute('style', 'width: 100%;')
}
// 所有元素都必须返回,否则会被过滤掉不显示
return el
}
lastAction.value = '已启用 transformElement(外部图片自动 widthFix)'
Taro.showToast({
title: '已启用图片自动处理',
icon: 'success'
})
// 重新加载当前内容以应用 transform
if (testHtml.value) {
const currentContent = testHtml.value
testHtml.value = ''
nextTick(() => {
testHtml.value = currentContent
})
}
} else {
// 禁用 transformElement
Taro.options.html.transformElement = undefined
lastAction.value = '已禁用 transformElement'
Taro.showToast({
title: '已禁用图片自动处理',
icon: 'none'
})
// 重新加载当前内容
if (testHtml.value) {
const currentContent = testHtml.value
testHtml.value = ''
nextTick(() => {
testHtml.value = currentContent
})
}
}
}
// 加载真实 API 数据(<a> 替换为 <div> 版本)
const loadRealApiDataWithDiv = () => {
lastAction.value = '加载真实 API 数据(a→div)...'
......@@ -315,12 +402,6 @@ const loadRealApiDataWithDiv = () => {
// 将 <a> 标签替换为 <div> 标签,保留 href 为 data-href
let content = realApiData.post_content
console.log('[VHtmlTest] 原始内容中的 <a> 标签示例:')
const aTagMatch = content.match(/<a[^>]*>/)
if (aTagMatch) {
console.log('[VHtmlTest]', aTagMatch[0])
}
// 替换 HTML 实体
content = content.replace(/&nbsp;/g, ' ') // 空格
content = content.replace(/&amp;/g, '&') // &
......@@ -334,15 +415,8 @@ const loadRealApiDataWithDiv = () => {
content = content.replace(/href=/g, 'data-href=')
content = content.replace(/<\/a>/g, '</div>')
console.log('[VHtmlTest] 替换后的 div 标签示例:')
const divTagMatch = content.match(/<div[^>]*data-is-link="true"[^>]*>/)
if (divTagMatch) {
console.log('[VHtmlTest]', divTagMatch[0])
}
// 统计 data-href 数量
const hrefCount = (content.match(/data-href=/g) || []).length
console.log('[VHtmlTest] 找到 data-href 数量:', hrefCount)
testHtml.value = content
currentContentType.value = `真实文章(<a>→<div>): ${realApiData.post_title}`
......@@ -354,8 +428,7 @@ const loadRealApiDataWithDiv = () => {
nextTick(() => {
bindImageEvents()
// 绑定文件链接点击事件
const linkCount = bindFileLinkEvents()
console.log('[VHtmlTest] 绑定了', linkCount, '个文件链接')
bindFileLinkEvents()
})
Taro.showToast({
......@@ -368,12 +441,10 @@ const loadRealApiDataWithDiv = () => {
// 绑定图片长按预览事件(类似 activityDetail 页面的实现)
const bindImageEvents = () => {
const imgs = $('#taro_html').children('.h5-p').children('.h5-img')
console.log('[VHtmlTest] 找到图片数量:', imgs.length)
imgs.forEach(function (img) {
$(img).on('longpress', function () {
const src = $(img).attr('src')
console.log('[VHtmlTest] 图片长按事件:', src)
Taro.previewImage({
urls: [src],
......@@ -381,11 +452,10 @@ const bindImageEvents = () => {
indicator: 'default',
loop: false,
success: res => {
console.log('[VHtmlTest] 预览成功:', res)
lastAction.value = '图片预览触发'
},
fail: err => {
console.error('[VHtmlTest] 预览失败:', err)
// 预览失败
}
})
})
......@@ -398,45 +468,22 @@ const bindImageEvents = () => {
const bindFileLinkEvents = () => {
// 先检查 #taro_html 容器是否存在
const container = $('#taro_html')
console.log('[VHtmlTest] 容器存在?', container.length > 0)
// 检查容器内所有 div
const allDivs = container.find('div')
console.log('[VHtmlTest] 容器内所有 div 数量:', allDivs.length)
// 检查带 data-is-link 属性的 div
const fileLinks = container.find('div[data-is-link="true"]')
console.log('[VHtmlTest] 找到文件链接数量 (data-is-link=true):', fileLinks.length)
// 如果找不到,尝试用 class 查找
if (fileLinks.length === 0) {
console.log('[VHtmlTest] 尝试用 _file_list class 查找...')
const classLinks = container.find('._file_list')
console.log('[VHtmlTest] 找到 _file_list 数量:', classLinks.length)
// 检查这些元素的属性
classLinks.each(function (idx, el) {
console.log('[VHtmlTest] _file_list[' + idx + '] 属性:', {
tagName: el.tagName,
className: el.className,
'data-href': el.getAttribute('data-href'),
'data-is-link': el.getAttribute('data-is-link'),
href: el.getAttribute('href'),
innerHTML: el.innerHTML.substring(0, 100)
})
})
// 如果用 class 找到了,绑定到这些元素上
classLinks.each(function (idx, el) {
const $el = $(el)
const dataHref = $el.attr('data-href')
console.log('[VHtmlTest] _file_list[' + idx + '] data-href:', dataHref)
if (dataHref) {
$el.on('tap', function () {
const fileName = $el.find('span span span').first().text() || 'document.pdf'
console.log('[VHtmlTest] 文件链接点击:', { dataHref, fileName })
lastAction.value = `打开文件: ${fileName}`
viewFile({
downloadUrl: dataHref,
......@@ -454,13 +501,9 @@ const bindFileLinkEvents = () => {
const $link = $(link)
const href = $link.attr('data-href')
console.log('[VHtmlTest] 文件链接 data-href:', href)
$link.on('tap', function () {
const fileName = $link.find('span span span').first().text() || 'document.pdf'
console.log('[VHtmlTest] 文件链接点击:', { href, fileName })
if (href) {
lastAction.value = `打开文件: ${fileName}`
......@@ -469,8 +512,6 @@ const bindFileLinkEvents = () => {
downloadUrl: href,
fileName: fileName
})
} else {
console.warn('[VHtmlTest] 链接没有 data-href 属性')
}
})
})
......@@ -479,22 +520,14 @@ const bindFileLinkEvents = () => {
}
// 监听 testHtml 变化
watch(testHtml, (newVal, oldVal) => {
console.log('[VHtmlTest] testHtml 变化:', {
oldLength: oldVal?.length || 0,
newLength: newVal?.length || 0
})
watch(testHtml, (_newVal, _oldVal) => {
renderTest.value = true
})
// 初始化
onMounted(() => {
console.log('[VHtmlTest] 组件已挂载')
// 加载默认测试内容
switchTestContent(1)
console.log('[VHtmlTest] 初始化完成,v-html 应该已绑定到响应式变量 testHtml')
})
</script>
......@@ -660,6 +693,8 @@ onMounted(() => {
border-radius: 8rpx;
font-size: 28rpx;
text-align: center;
background: #f0f0f0;
color: #333;
&.primary {
background: #1989fa;
......@@ -686,6 +721,11 @@ onMounted(() => {
background: #7232dd;
color: #fff;
}
&.enabled {
background: #07c160;
color: #fff;
}
}
.compare-note {
......