https://www.zuoan.com.cn/News3/3487.html
https://www.zuoan.com.cn/News3/3490.html
距离上面发布的文章,在发布文章和编辑文章时添加预览HTML的功能之后,我突然又想在列表上直接预览文章。
第一步:
apps/admin/model/content/ContentModel.php
获取文章列表的地方添加:
'a.content',
其他几处也相应添加,要不然后台列表处无法获取到数据。
第二步:在后台模板文件中添加代码,最终形成如下。
{if($value->status)}
{if(!$value->outlink)}
<input type="hidden" name="urls[[value->id]]" value="{php}echo $link{/php}">
<a href="{php}echo $link{/php}" class="layui-btn layui-btn-xs layui-btn-primary" target="_blank">查看</a>
{else}
<a href="[value->outlink]" class="layui-btn layui-btn-xs layui-btn-primary" target="_blank">查看</a>
{/if}
<!-- 添加的代码 -->
<input type="hidden" name="content[[value->id]]" value="[value->content]">
<a href="javascript:;" class="layui-btn layui-btn-xs btn-preview" data-id="[value->id]">列表预览</a>
<script>
layui.use(['layer', 'jquery'], function () {
var $ = layui.jquery;
var layer = layui.layer;
// 只绑定一次点击事件
$(document).off('click', '.btn-preview').on('click', '.btn-preview', function () {
var id = $(this).data('id');
var $input = $("input[name='content[" + id + "]']");
if (!$input.length) {
layer.alert("未找到 ID=" + id + " 的内容!");
return;
}
var rawHtml = $input.val();
var previewHtml = `<iframe id="previewFrame" style="width:100%;height:100%;border:none;"></iframe>`;
layer.open({
type: 1,
title: '文章内容预览',
area: ['90%', '90%'],
content: previewHtml,
success: function (layero, index) {
var iframe = document.getElementById('previewFrame');
var doc = iframe.contentDocument || iframe.contentWindow.document;
var fullHtml = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
此处可引入你前端的CSS样式,以便预览的时候显示的是你前端的效果,而不是加载后端的样式。
<style>
body { padding: 20px; font-family: "微软雅黑", sans-serif; }
</style>
</head>
<body>
${rawHtml}
</body>
</html>
`;
doc.open();
doc.write(fullHtml);
doc.close();
}
});
});
});
</script>
<!-- 添加的代码 -->
{else}
<a href="javascript:;" class="layui-btn layui-btn-xs layui-btn-disabled">查看</a>
{/if}最后我们来看效果:


使用上面的方法 呢,可能我们会担心一个问题,就是在一个列表中,用
<input type="hidden" name="content[[value->id]]" value="[value->content]">
去获取的数据会不会太大了。假如列表是15篇文章,那就相当于有15篇文章的内容在这个页面中。会造成这个列表数据庞大,会不会卡顿呢?
1. 页面卡顿可能性
每篇文章内容完整HTML都写在了隐藏input的value属性里,浏览器会把这些内容都加载、解析。
如果内容很长,尤其有大量HTML、图片、样式等,页面源码会变得很大,初始加载时浏览器解析负担会增大,加载时间变长。
隐藏字段的value存放大量HTML其实并不太合适,可能导致:
页面体积变大,加载慢
浏览器渲染缓慢
内存占用增加
如果还有JS对这些字段做操作,性能压力更大
2. 用户体验
首屏加载时间变长,影响用户体验。
如果用户只点击少数几篇文章预览,却加载了所有文章内容,浪费资源。
改进方案 方案A:按需加载内容
页面隐藏域只保存文章的 ID、标题等轻量信息,不保存完整内容。
点击“预览”按钮时,通过 Ajax 请求后台接口,传文章ID,服务器返回该文章完整内容(HTML)。
前端收到内容后,再打开弹窗展示。
这样初始页面只加载少量数据,提升首屏性能,点击时才加载详细内容。
所以我们第一步在后台打开API接口。

第二步修改代码。
<!-- 添加的代码 -->
<input type="hidden" name="content[[value->id]]" >
<a href="javascript:;" class="layui-btn layui-btn-xs btn-preview" data-id="[value->id]">预览</a>
<script>
layui.use(['layer', 'jquery'], function () {
var $ = layui.jquery;
var layer = layui.layer;
$(document).off('click.preview').on('click.preview', '.btn-preview', function () {
var id = $(this).data('id');
if (!id) {
layer.alert("未获取到文章ID!");
return;
}
var url = '/api.php/content/' + id;
var loading = layer.load(2);
$.ajax({
type: 'GET', // 改为GET请求
url: url,
dataType: 'json',
data: {
appid: "{pboot:appid}",
timestamp: "{pboot:timestamp}",
signature: "{pboot:signature}"
},
success: function (res) {
layer.close(loading);
if (!res || !res.data || !res.data.content) {
layer.alert("未获取到文章内容!");
return;
}
var rawHtml = res.data.content;
var iframeHtml = '<iframe id="previewFrame" style="width:100%;height:100%;border:none;"></iframe>';
layer.open({
type: 1,
title: '文章预览',
area: ['90%', '90%'],
content: iframeHtml,
success: function () {
var iframe = document.getElementById('previewFrame');
var doc = iframe.contentDocument || iframe.contentWindow.document;
var fullHtml = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/template/peoplesj/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/template/peoplesj/css/style.css">
<style>body { padding: 20px; font-family: "微软雅黑", sans-serif; }</style>
</head>
<body>
${rawHtml}
</body>
</html>
`;
doc.open();
doc.write(fullHtml);
doc.close();
}
});
},
error: function (xhr, status, error) {
layer.close(loading);
console.error("请求失败:", error);
layer.alert("请求失败:" + error);
}
});
});
});
</script>按道理,这样我们连MODE都不用修改了。未作测试,诸君可自行测试一下。
但是有一个问题,我在本地测试的时候,获取不到API,只有放在服务器上才可以。