file-type

GitHub应用在Markdown文档PR中添加“查看呈现”功能

ZIP文件

下载需积分: 5 | 245KB | 更新于2025-09-10 | 82 浏览量 | 0 下载量 举报 收藏
download 立即下载
该文档描述了一个名为“view-rendered”的GitHub应用程序的功能和使用方法。该应用程序的主要作用是在GitHub的Pull Request(PR)中,当涉及到Markdown文档时,附加一组“查看呈现的”链接。这些链接允许用户预览Markdown文件在GitHub上渲染后的效果,而不必先合并到主分支。下面详细说明文档中提到的知识点: 标题中提到的“Markdown文档”,是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。Markdown文件通常具有“.md”或“.markdown”作为文件扩展名。Markdown广泛应用于编写README文件、论坛发帖以及在线文章等。 标题中的“Pull Request(PR)”是软件开发中用于向项目贡献代码的一种机制。开发者在一个分支(feature branch)上进行更改,之后向项目的主分支(通常是master或main分支)发起PR请求,经过审查后可能会被合并。在这个过程中,PR可以包括新增的代码、修改后的代码或者修复的代码。 描述中的“查看渲染”指的是查看Markdown文档渲染后的结果。在GitHub上,Markdown文档可以被渲染成富文本格式,使得链接、图片、标题和其他格式元素能够以网页的形式展现,而不仅仅是纯文本。这种预览功能非常有用,因为它可以确保文档在提交到项目仓库之前,内容和格式都是正确的。 描述中提到的“构建的GitHub应用程序”是一个特定类型的软件,它能够与GitHub API进行交互,实现特定的功能,例如在本例中自动附加渲染链接。应用程序通常需要注册到GitHub上,并获得相应的权限来进行操作。 文档还提供了一个基本的使用说明,包括安装依赖(npm install)和运行程序(npm start)。这里的npm是Node.js的包管理器,用于安装JavaScript包及其依赖,而"npm start"则是启动应用程序的常用命令。 描述中的“如果您想运行自己的应用程序实例,请参阅。”提示用户,若要自定义或深入了解如何在本地环境中部署和运行这个GitHub应用程序,需要查看其他文档或资料。这可能包括配置环境、管理权限、安全设置以及程序的扩展和维护等。 最后,【标签】中的"JavaScript"是本应用程序的开发语言。JavaScript是一种广泛使用的高级、解释型编程语言,能够创建动态交互式内容,是Web开发中最核心的技术之一。该应用程序可能使用Node.js作为运行环境,因为它允许使用JavaScript编写服务器端应用程序。 压缩包子文件的名称“view-rendered-master”表明了包含该程序代码的压缩包或版本控制系统仓库的名称。这里“master”可能指的是主分支,即代码的主要版本。在Git版本控制系统中,master是默认的主要分支名称,虽然现在很多项目为了更加包容和中性,开始使用main替代master。 综上所述,文档中的知识点涵盖了Markdown文档的使用、Pull Request的流程、GitHub应用程序的构建和运行以及JavaScript在Web开发中的应用等方面。这些知识点对于理解如何在GitHub上实现对Markdown文档的高效预览具有重要作用。

相关推荐

filetype

<template> <view class="webview-container"> <cover-view class="webview-wrapper"> <web-view :src="webviewPath" id="targetWebview" allow-same-origin sandbox="allow-same-origin allow-scripts"></web-view> </cover-view> <cover-view class="bottom-action-area"> <cover-view class="capture-btn" @click="captureWebview"> <cover-view class="btn-text">立即取证</cover-view> </cover-view> </cover-view> <cover-view v-if="showPreview" class="custom-preview"> <cover-view class="preview-header"> <cover-view class="title-container"> <cover-view class="preview-title">预览界面</cover-view> </cover-view> </cover-view> <cover-image :src="screenshotPath" class="preview-image" mode="aspectFit" @error="handleImageError" ></cover-image > <cover-view class="action-buttons"> <cover-view class="action-btn cancel-btn" @click="handleAction('放弃')">放弃</cover-view> <cover-view class="action-btn confirm-btn" @click="handleAction('固化')">固化</cover-view> </cover-view> <cover-view> </cover-view> </cover-view> </view> </template> <script setup lang="ts" > import { onLoad, onReady } from '@dcloudio/uni-app'; import html2canvas from 'html2canvas'; import { ref } from 'vue'; declare const plus: any; const webviewPath = ref(''); const ws = ref<any>(null); const screenshotPath = ref(''); const showPreview = ref(false); const platform = ref(''); const originalWebviewHeight = ref('auto'); const screenshotFilePath = ref(''); const screenshot = ref(''); const iframeRef = ref<HTMLIFrameElement | null>(null); onLoad((options: any) => { if (options.url) { webviewPath.value = decodeURIComponent(options.url); } // 获取当前平台 const systemInfo = uni.getSystemInfoSync(); platform.value = systemInfo.platform; }); onReady(() => { // #ifdef APP-PLUS const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; const currentWebview = currentPage.$getAppWebview(); setTimeout(() => { if (currentWebview.children().length > 0) { const wv = currentWebview.children()[0]; ws.value = wv; // originalWebviewHeight.value = wv.getStyle().height || 'auto'; wv.setStyle({ height: 'auto' }); } }, 1000); // #endif // #ifdef H5 // #endif }); const captureWebview = async () => { uni.showLoading({ title: '正在取证中' }) // #ifdef APP-PLUS if (!ws.value) { uni.showToast({ title: '网页未加载完成', icon: 'none' }); return; } const bitmap = new plus.nativeObj.Bitmap('screenshot') const rand = Math.floor(Math.random() * 10000) const saveUrl = '_doc/' + rand + 'order.jpg' // 绘制页面截图 ws.value.draw(bitmap, () => { // 保存图片 bitmap.save( saveUrl, { format: 'jpg', quality: 90 }, (res:any) => { // 将本地路径转换为可以展示的路径 const previewPath = plus.io.convertLocalFileSystemURL(res.target) screenshotPath.value = previewPath screenshotFilePath.value = res.target; // 保存文件路径 console.log('截图保存成功,预览路径:', previewPath) // 延迟展示,确保加载完成 setTimeout(() => { showPreview.value = true uni.hideLoading() }, 300) bitmap.clear() // 清理 bitmap 占用资源 }, (err:any) => { console.error('保存失败:', err) uni.hideLoading() uni.showToast({ title: '保存失败: ' + err.message, icon: 'none', }) bitmap.clear() } ) }, (err:any) => { console.error('截图失败:', err) uni.showToast({ title: '截图失败: ' + err.message, icon: 'none', }) uni.hideLoading() }) // #endif // #ifdef H5 // #endif } const closePreview = () => { showPreview.value = false; } //上传 const uploadEvidence = () => { // #ifdef APP-PLUS // APP环境上传 plus.io.resolveLocalFileSystemURL(screenshotFilePath.value, (entry:any) => { console.log('文件存在,开始上传:', entry.name); // 继续执行上传逻辑 uni.showLoading({ title: '上传证据中...', mask: true }); // 获取文件系统路径 const filePath = entry.toLocalURL(); uni.uploadFile({ url: 'http://192.168.1.80:1592/api/upload', filePath: filePath, name: 'file', type: 'image', formData: { 'timestamp': Date.now() }, success: (uploadRes) => { uni.hideLoading(); try { const data = JSON.parse(uploadRes.data); if (data.success) { uni.showToast({ title: '证据上传成功', icon: 'none' }) } else { uni.showToast({ title: '上传失败', icon: 'none' }) console.log('上传失败') } } catch (e) { uni.showToast({ title: '解析响应失败', icon: 'none' }) } // 3秒后关闭状态提示 setTimeout(() => { closePreview(); }, 3000); }, fail: (err) => { uni.hideLoading(); console.error('上传错误详情:', err); uni.showToast({ title: '网络错误'+ err.errMsg, icon: 'none' }) setTimeout(() => { }, 3000); } }); }, (err:any) => { console.error('文件不存在或路径错误:', err); uni.showToast({ title: '文件路径无效', icon: 'none' }); } ); uni.showLoading({ title: '上传证据中...', mask: true }); // #endif // #ifdef APP-H5 // H5环境上传 // if (!screenshotFilePath.value) { // uni.hideLoading(); // uni.showToast({ title: '文件路径无效', icon: 'none' }); // return; // } // 获取文件对象 // fetch(screenshotFilePath.value) // .then(res => res.blob()) // .then(blob => { // const formData = new FormData(); // formData.append('evidence', blob, `evidence-${Date.now()}.jpg`); // formData.append('timestamp', Date.now().toString()); // return fetch('http://192.168.1.80:1592/api/upload', { // method: 'POST', // body: formData // }); // }) // .then(response => response.json()) // .then(data => { // uni.hideLoading(); // if (data.success) { // uni.showToast({ title: '证据上传成功', icon: 'none' }); // } else { // uni.showToast({ title: '上传失败'+ data.message, icon: 'none' }); // } // setTimeout(() => { // closePreview(); // }, 3000); // }) // .catch(err => { // uni.hideLoading(); // uni.showToast({ title: '上传失败'+ err.message, icon: 'none' }) // setTimeout(() => { // }, 3000); // }); // #endif } const handleAction = (action: string) => { switch(action) { case '放弃': closePreview(); break; case '固化': // #ifdef APP-PLUS uni.saveImageToPhotosAlbum({ filePath: screenshotPath.value, success: () => { uni.showToast({ title: '证据已固化保存' }); // 调用上传函数 uploadEvidence(); }, fail: (err) => { uni.showToast({ title: '保存失败: ' + err.errMsg, icon: 'none' }); } }); // #endif // #ifdef APP-H5 // #endif break; } } const handleImageError = (e: any) => { console.error('图片加载错误:', e); uni.showToast({ title: '图片加载错误', icon: 'none' }); } </script> <style> .webview-container { position: relative; width: 100%; height: 100vh; overflow: hidden; } .webview-wrapper { height: calc(100vh - 120rpx); width: 100%; overflow: hidden; } .bottom-action-area { position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; background-color: #007aff; padding: 30rpx; padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); display: flex; justify-content: center; align-items: center; } .capture-btn { width: 100%; height: 90rpx; background-color: #007aff; border-radius: 45rpx; box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.2); display: flex; align-items: center; justify-content: center; } .btn-text { color: #ffffff; font-size: 32rpx; font-weight: 500; } /* 优化预览组件 */ .custom-preview { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 9999; background-color: rgba(0, 0, 0, 0.9); display: flex; flex-direction: column; /* 垂直排列子元素 */ align-items: center; /* 关键修改:去掉顶部内边距,只保留底部内边距 */ padding: 0 0 40rpx 0; box-sizing: border-box; } .preview-header { width: 100%; height: 250rpx; /* 增加高度 */ background-color: #007aff; color: #ffffff; font-size: 34rpx; /* 增大字体 */ font-weight: bold; display: flex; align-items: center; justify-content: center; /* 添加圆角效果 */ border-top-left-radius: 16rpx; border-top-right-radius: 16rpx; } .preview-title { color: #ffffff; /* 白色字体 */ font-size: 28rpx; /* 字体大小适配40rpx高度 */ font-weight: bold; line-height: 40rpx; /* 与容器高度一致,实现垂直居中 */ width: 100%; text-align: center; } .preview-image { width: 100%; height: 100%; object-fit: contain; border: 1rpx solid rgba(255, 255, 255, 0.1); border-radius: 8rpx; background-color: #f5f5f5; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.3); } .action-buttons { display: flex; width: 100%; /* 充满整个宽度 */ justify-content: space-between; padding: 30rpx 5%; /* 左右留5%间隙,上下30rpx内边距扩展背景区域 */ margin-top: auto; /* 借助flex布局推到最底部 */ background-color: #353336; /* 底部模块背景色 */ box-sizing: border-box; /* 确保padding不影响宽度计算 */ } .action-btn { flex: 1; height: 90rpx; border-radius: 12rpx; display: flex; align-items: center; justify-content: center; padding: 0; margin: 0 15rpx; border: none; color: #ffffff; /* 文字色适配深色背景 */ font-size: 34rpx; font-weight: 500; line-height: 1; } .cancel-btn { color: #ffffff; /* 文字颜色 */ font-size: 34rpx; font-weight: 500; /* 确保文字本身无偏移 */ line-height: 1; /* 清除行高影响 */ text-align: center; /* 辅助居中(冗余保障) */ background-color: #353336; } .confirm-btn { color: #ffffff; /* 文字颜色 */ font-size: 34rpx; font-weight: 500; /* 确保文字本身无偏移 */ line-height: 1; /* 清除行高影响 */ text-align: center; /* 辅助居中(冗余保障) */ background-color: #353336; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .bottom-action-img{ position: fixed; top: 100; left: 0; right: 0; z-index: 100; background-color: #007aff; padding: 30rpx; display: flex; justify-content: center; align-items: center; } .action-img{ width: 100%; height: 90rpx; background-color: #007aff; display: flex; } </style> 根据这个代码修改 将APP内点击立即取证 将webview内容转换成pdf格式 预览

filetype

import styled, { keyframes } from 'styled-components'; import useStore from '../../store/store'; const LoadingPage = () => { const { loading } = useStore(); return ( <> <LoadingContainer className={loading ? '' : 'loaded'}> {/* <Loader />
Loading...
*/} <LoadingLeft className={loading ? '' : 'loaded'} /> <LoadingRight className={loading ? '' : 'loaded'} /> <SpinnerBox className={loading ? '' : 'loaded'}>
加载中...
</SpinnerBox> </LoadingContainer> </> ) } // 定义加载动画 const spin = keyframes` 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } `; // Loading 组件样式 const LoadingContainer = styled.div` display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; width: 100%; font-size: 24px; z-index: 999; transition: all 2s; opacity: 1; position: fixed; &.loaded { opacity: 0; position: absolute; z-index: -1001; } `; const Loader = styled.div` border: 8px solid rgba(255, 255, 255, 0.3); border-top: 8px solid white; border-radius: 50%; width: 60px; height: 60px; animation: ${spin} 1s linear infinite; `; const LoadingLeft = styled.div` position: fixed; z-index: 1000; width: 52%; height: 100%; background: #37474f; left: 0; transition: all 1s; &.loaded { transform: translate(-100%, 0); } ` const LoadingRight = styled.div` position: fixed; z-index: 1000; width: 52%; height: 100%; background: #37474f; right: 0; transition: all 1s; &.loaded { transform: translate(100%, 0); } ` const SpinnerBox = styled.div` position: fixed; z-index: 1001; opacity: 1; transition: all .3s; &.loaded { opacity: 0; } .configure-border-1 { position: absolute; padding: 3px; width: 115px; height: 115px; background: #ffab91; animation: configure-clockwise 3s ease-in-out 0s infinite alternate; .configure-core { width: 100%; height: 100%; background: #37474f; } } .configure-border-2 { left: -115px; padding: 3px; width: 115px; height: 115px; background: #3ff9dc; transform: rotate(45deg); animation: configure-xclockwise 3s ease-in-out 0s infinite alternate; .configure-core { width: 100%; height: 100%; background: #37474f; } } .loading-word { position: absolute; color: #eff; font-size: 16px; top: 50%; left: 50%; transform: translate(-50%, -50%); white-space: nowrap; } ` export default LoadingPage出现这个bug tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:

简内特
  • 粉丝: 51
上传资源 快速赚钱