当前位置: 首页 > news >正文

哈尔滨网站建设优化在线crm平台

哈尔滨网站建设优化,在线crm平台,深圳建筑工程交易服务主页,短视频创作平台1 引言 在上一篇文章《解决Vditor加载Markdown网页很慢的问题(ViteJSVditor)》中#xff0c;我们通过设置域内CDN的方式解决Vditor加载Markdown网页很慢的问题。而在这篇文章中#xff0c;笔者将会开发实现一个前端中很常见的需求#xff1a;给基于Markdown渲染的文档网页增…1 引言 在上一篇文章《解决Vditor加载Markdown网页很慢的问题(ViteJSVditor)》中我们通过设置域内CDN的方式解决Vditor加载Markdown网页很慢的问题。而在这篇文章中笔者将会开发实现一个前端中很常见的需求给基于Markdown渲染的文档网页增加一个目录组件。 需要说明的是原生的Markdown标准并没有规定生成目录的写法但是国内的博文网站似乎都支持一个拓展来实现目录的生成 [toc]但是这样生成的目录是通常是位于文章页面的最上方这样就失去了目录的意义。比较好的实现是像CSDN或者掘金一样额外生成一个目录组件并且固定在侧栏上方。这样可以在浏览文章的时候随时定位所在的目录同时还可以使用目录来导航。 阅读本文可能需要的前置文章 《通过JS模板引擎实现动态模块组件(ViteJSHandlebars)》《使用Vditor将Markdown文档渲染成网页(ViteJSVditor)》 2 详叙 2.1 整体结构 将渲染Markdown文档的部分封装成单独的组件post-article.js、post-article.handlebars和post-article.css增加一个文章目录组件post-toc.js、post-toc.handlebars、post-toc.css。另外post-data.json是我们提前准备的博客文章里面除了保存有Markdown格式的文档字符串还有一些文章的相关数据1.png和2.png则是文章中图片。项目组织结构如下 my-native-js-app/ ├── public/ │ ├── 1.png │ ├── 2.png │ └── post-data.json ├── src/ │ ├── components/ │ │ ├── post-article.css │ │ ├── post-article.handlebars │ │ ├── post-article.js │ │ ├── post-toc.css │ │ ├── post-toc.handlebars │ │ └── post-toc.js │ ├── main.js │ └── style.css ├── index.html └── package.json 还是按照代码的执行顺序来介绍这个功能的实现。首先还是index.html !DOCTYPE html html langenheadmeta charsetUTF-8 /link relicon typeimage/svgxml href/vite.svg /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleVite App/title /headbodydiv idappdiv idpost-article-placeholder/divdiv idarticle-toc-placeholder/div/divscript typemodule src/src/main.js/script /body/html主要就是增加了post-article-placeholder和article-toc-placeholder这两个元素分别作为Markdown博文和博文目录的容器。其实这里面还有个页面布局的问题不过这个问题我们下一篇文章再说。这里还是先看main.js import ./style.css; import ./components/post-article.js;2.2 博文内容组件 引用了post-article.js也就是Markdown博文内容组件。那么就进入post-article.js import ./post-article.css; import { CreateTocPanel } from ./post-toc.js; import Handlebars from handlebars; import templateSource from ./post-article.handlebars?raw;import vditor/dist/index.css; import Vditor from vditor;// 初始化文章标签面板 async function InitializePostArticlePanel() {try { const response await fetch(/post-data.json);if (!response.ok) {throw new Error(网络无响应);}const blogData await response.json();// 编译模板const template Handlebars.compile(templateSource);// 渲染模板const renderedHtml template({blogMeta: blogData.blogMeta,});// 将渲染好的HTML插入到页面中document.getElementById(post-article-placeholder).innerHTML renderedHtml;// 显示内容Vditor.preview(document.getElementById(post-content), blogData.content, {cdn: window.location.origin,markdown: {toc: false,mark: true, //高亮显示footnotes: true, //脚注autoSpace: true, //自动空格适合中英文混合排版},math: {engine: KaTeX, //支持latex公式inlineDigit: true, //内联公式可以接数字},hljs: {style: github, //代码段样式lineNumber: true, //是否显示行号},anchor: 2, // 为标题添加锚点 0不渲染1渲染于标题前2渲染于标题后lang: zh_CN, //中文theme: {current: light, //light,dark,light,wechat},lazyLoadImage:https://cdn.jsdelivr.net/npm/vditor/dist/images/img-loading.svg,transform: (html) {// 使用正则表达式替换图片路径并添加居中样式及题注return html.replace(/img\s[^]*src\.\/([^])\.([a-zA-Z0-9])\s*alt([^]*)[^]*/g,(match, p1, p2, altText) {// const newSrc ${backendUrl}/blogs/resources/images/${postId}/${p1}.${p2};const newSrc ${p1}.${p2};const imgWithCaption div styletext-align: center;img src${newSrc} classcenter-image alt${altText}p classcaption${altText}/p/div;return imgWithCaption;});},after() {CreateTocPanel();},});} catch (error) {console.error(获取博客失败:, error);} }document.addEventListener(DOMContentLoaded, InitializePostArticlePanel);post-article.js中的内容改进自《通过JS模板引擎实现动态模块组件(ViteJSHandlebars)》中的案例不过略有不同。首先是获取博文数据 const response await fetch(/post-data.json); if (!response.ok) {throw new Error(网络无响应); } const blogData await response.json();// 编译模板 const template Handlebars.compile(templateSource);// 渲染模板 const renderedHtml template({blogMeta: blogData.blogMeta, });// 将渲染好的HTML插入到页面中 document.getElementById(post-article-placeholder).innerHTML renderedHtml;在实际项目开发中应该是从远端API获取数据这里进行了简化将数据提前准备好了放置在域内。然后将这个数据与编译的Handlebars模板一起渲染成HTML元素。从下面的post-article.handlebars中可以看到博文组件中内容不仅包含Markdown博文内容元素还有诸如时间、统计信息、标签等元素 div idmain-contenth1 idpost-title{{blogMeta.title}}/h1div classpost-statsspan class post-statspan/spanspan class text已于/span{{blogMeta.createdTime}}span class text修改/span/spanspan class post-statspan️/span{{blogMeta.postStats.viewCount}}span class text阅读/span/spanspan class post-statspan/span{{blogMeta.postStats.likeCount}}span class text点赞/span/spanspan class post-statspan/span{{blogMeta.postStats.commentCount}}span class text评论/span/span/divdiv classpost-tagsspan class tags-titlespan/spanspan class text文章标签/span/span{{#each blogMeta.tagNames}}span class post-tag{{this}}/span{{/each}}/divdiv classpost-categories专栏{{#each blogMeta.categoryNames}}span {{this}} /span{{/each}}收录该内容/divdiv idpost-content/div /divMarkdown博文内容元素是使用Vditor来渲染初始化的这一点与之前的案例一样。不同的是增加了一个after配置 import { CreateTocPanel } from ./post-toc.js;//...after() {CreateTocPanel(); },这个after配置的意思是当Vditor渲染完成以后就立刻执行CreateTocPanel()函数这个函数来自于博文目录组件post-toc.js表示要开始创建博文目录了。 2.2 博文目录组件 post-toc.js中的代码如下所示 import ./post-toc.css;import Handlebars from handlebars; import templateSource from ./post-toc.handlebars?raw;export function CreateTocPanel() {const headings document.querySelectorAll(#post-content h1, #post-content h2, #post-content h3);const tocContent [];headings.forEach((heading, index) {const content {};content[id] heading.id;content[title] heading.textContent;const marginLeft heading.tagName H2 ? 20 : heading.tagName H3 ? 40 : 0;content[marginLeft] marginLeft;tocContent.push(content);});// 编译模板const template Handlebars.compile(templateSource);// 渲染模板const renderedHtml template({tocContent,});// 将渲染好的HTML插入到页面中const articleTocPlaceholder document.getElementById(article-toc-placeholder);articleTocPlaceholder.innerHTML renderedHtml;// 联动滚动时同步激活目录项window.addEventListener(scroll, () {let activeHeading;headings.forEach((heading) {const rect heading.getBoundingClientRect();if (rect.top 0 rect.top window.innerHeight / 2) {activeHeading heading;}});if (activeHeading) {document.querySelectorAll(.toc-sidebar .toc a).forEach((link) link.classList.remove(active)); const escapedId CSS.escape(activeHeading.id); //安全地转义选择器中的特殊字符const activeLink document.querySelector(.toc-sidebar .toc a[href#${escapedId}]);if (activeLink) activeLink.classList.add(active);}}); }这段代码是实现博文目录功能的关键代码。首先搜索查询渲染成HTML形式的博文内容中的标题元素h1、h2和h3 const headings document.querySelectorAll(#post-content h1, #post-content h2, #post-content h3);然后提取出关键数据 const tocContent [];headings.forEach((heading, index) {const content {};content[id] heading.id;content[title] heading.textContent;const marginLeft heading.tagName H2 ? 20 : heading.tagName H3 ? 40 : 0;content[marginLeft] marginLeft;tocContent.push(content);});将其传入Handlebars模板进行渲染 // 编译模板const template Handlebars.compile(templateSource);// 渲染模板const renderedHtml template({tocContent,});// 将渲染好的HTML插入到页面中const articleTocPlaceholder document.getElementById(article-toc-placeholder);articleTocPlaceholder.innerHTML renderedHtml;模板post-toc.handlebars中的内容非常简单 div classtoc-sidebardiv classtoch3文章目录/h3ul{{#each tocContent}}li stylemargin-left: {{marginLeft}}px;a href#{{id}} class{{title}}/a/li{{/each}}/ul/div /div可以看到这里能够获取一级、二级还有三级标题通过样式的缩进margin-left来体现标题的不同。另外href属性的设置也保证了能通过点击来实现跳转。 最后实现联动通过文章标题元素范围的判定来高亮目录中标题元素的样式让用户直到浏览到博文中的哪一段了 // 联动滚动时同步激活目录项window.addEventListener(scroll, () {let activeHeading;headings.forEach((heading) {const rect heading.getBoundingClientRect();if (rect.top 0 rect.top window.innerHeight / 2) {activeHeading heading;}});if (activeHeading) {document.querySelectorAll(.toc-sidebar .toc a).forEach((link) link.classList.remove(active)); const escapedId CSS.escape(activeHeading.id); //安全地转义选择器中的特殊字符const activeLink document.querySelector(.toc-sidebar .toc a[href#${escapedId}]);if (activeLink) activeLink.classList.add(active);}});3 结语 最终实现的效果如下图所示 虽然功能大致实现了不过还有一些问题没有说清楚比如在浏览文章的过程中博文目录是如何始终保证黏在页面的右上角的这个问题就放在下篇中继续论述了。 实现代码
文章转载自:
http://www.morning.hlxxl.cn.gov.cn.hlxxl.cn
http://www.morning.mlfgx.cn.gov.cn.mlfgx.cn
http://www.morning.tnjkg.cn.gov.cn.tnjkg.cn
http://www.morning.tnjkg.cn.gov.cn.tnjkg.cn
http://www.morning.caswellintl.com.gov.cn.caswellintl.com
http://www.morning.rtlg.cn.gov.cn.rtlg.cn
http://www.morning.ggfdq.cn.gov.cn.ggfdq.cn
http://www.morning.srckl.cn.gov.cn.srckl.cn
http://www.morning.glnxd.cn.gov.cn.glnxd.cn
http://www.morning.wrbnh.cn.gov.cn.wrbnh.cn
http://www.morning.rnmmh.cn.gov.cn.rnmmh.cn
http://www.morning.madamli.com.gov.cn.madamli.com
http://www.morning.ttkns.cn.gov.cn.ttkns.cn
http://www.morning.tkkjl.cn.gov.cn.tkkjl.cn
http://www.morning.dmldp.cn.gov.cn.dmldp.cn
http://www.morning.rxfbf.cn.gov.cn.rxfbf.cn
http://www.morning.mdmxf.cn.gov.cn.mdmxf.cn
http://www.morning.frpm.cn.gov.cn.frpm.cn
http://www.morning.qgcfb.cn.gov.cn.qgcfb.cn
http://www.morning.dgknl.cn.gov.cn.dgknl.cn
http://www.morning.hmqwn.cn.gov.cn.hmqwn.cn
http://www.morning.baguiwei.com.gov.cn.baguiwei.com
http://www.morning.prddj.cn.gov.cn.prddj.cn
http://www.morning.ksggr.cn.gov.cn.ksggr.cn
http://www.morning.bqdpy.cn.gov.cn.bqdpy.cn
http://www.morning.pxspq.cn.gov.cn.pxspq.cn
http://www.morning.cjsnj.cn.gov.cn.cjsnj.cn
http://www.morning.nstml.cn.gov.cn.nstml.cn
http://www.morning.mxptg.cn.gov.cn.mxptg.cn
http://www.morning.qwyms.cn.gov.cn.qwyms.cn
http://www.morning.qqnh.cn.gov.cn.qqnh.cn
http://www.morning.jhqcr.cn.gov.cn.jhqcr.cn
http://www.morning.jwbnm.cn.gov.cn.jwbnm.cn
http://www.morning.rxsgk.cn.gov.cn.rxsgk.cn
http://www.morning.hcbky.cn.gov.cn.hcbky.cn
http://www.morning.fmgwx.cn.gov.cn.fmgwx.cn
http://www.morning.pqkgb.cn.gov.cn.pqkgb.cn
http://www.morning.rknsp.cn.gov.cn.rknsp.cn
http://www.morning.mkrjf.cn.gov.cn.mkrjf.cn
http://www.morning.hbtarq.com.gov.cn.hbtarq.com
http://www.morning.pybqq.cn.gov.cn.pybqq.cn
http://www.morning.qdmdp.cn.gov.cn.qdmdp.cn
http://www.morning.yzygj.cn.gov.cn.yzygj.cn
http://www.morning.rgpbk.cn.gov.cn.rgpbk.cn
http://www.morning.fkgct.cn.gov.cn.fkgct.cn
http://www.morning.tfpbm.cn.gov.cn.tfpbm.cn
http://www.morning.nchlk.cn.gov.cn.nchlk.cn
http://www.morning.lhytw.cn.gov.cn.lhytw.cn
http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn
http://www.morning.rhdln.cn.gov.cn.rhdln.cn
http://www.morning.jbfjp.cn.gov.cn.jbfjp.cn
http://www.morning.kldtf.cn.gov.cn.kldtf.cn
http://www.morning.hffjj.cn.gov.cn.hffjj.cn
http://www.morning.kfldw.cn.gov.cn.kfldw.cn
http://www.morning.pzcqz.cn.gov.cn.pzcqz.cn
http://www.morning.yggwn.cn.gov.cn.yggwn.cn
http://www.morning.jpgfq.cn.gov.cn.jpgfq.cn
http://www.morning.fbhmn.cn.gov.cn.fbhmn.cn
http://www.morning.plqkz.cn.gov.cn.plqkz.cn
http://www.morning.lkhfm.cn.gov.cn.lkhfm.cn
http://www.morning.xrhst.cn.gov.cn.xrhst.cn
http://www.morning.fykqh.cn.gov.cn.fykqh.cn
http://www.morning.xtxp.cn.gov.cn.xtxp.cn
http://www.morning.xjqkh.cn.gov.cn.xjqkh.cn
http://www.morning.sfhjx.cn.gov.cn.sfhjx.cn
http://www.morning.nrgdc.cn.gov.cn.nrgdc.cn
http://www.morning.zczkm.cn.gov.cn.zczkm.cn
http://www.morning.fbylq.cn.gov.cn.fbylq.cn
http://www.morning.rykx.cn.gov.cn.rykx.cn
http://www.morning.rknhd.cn.gov.cn.rknhd.cn
http://www.morning.lnnc.cn.gov.cn.lnnc.cn
http://www.morning.bpmdz.cn.gov.cn.bpmdz.cn
http://www.morning.lftpl.cn.gov.cn.lftpl.cn
http://www.morning.prhfc.cn.gov.cn.prhfc.cn
http://www.morning.kjcll.cn.gov.cn.kjcll.cn
http://www.morning.xjnjb.cn.gov.cn.xjnjb.cn
http://www.morning.ggcjf.cn.gov.cn.ggcjf.cn
http://www.morning.jjxnp.cn.gov.cn.jjxnp.cn
http://www.morning.tcxzn.cn.gov.cn.tcxzn.cn
http://www.morning.smfbw.cn.gov.cn.smfbw.cn
http://www.tj-hxxt.cn/news/239892.html

相关文章:

  • 织梦小说网站模板建筑人才网官网首页
  • 做网站赚钱嘛WordPress前台用户发布
  • 手表网站那个好国外域名买卖
  • 网站建设信息安全要求wordpress 权限说明
  • 为网站生成rss防做网站
  • 上海企业建站 免费wordpress 语言包修改
  • 住房和城乡建设部注册中心网站文案发布平台
  • 户外拓展公司网站开发网站加友情链接
  • 建网站卖饮料电商平台如何推广运营
  • 英语不好的做网站运营可以吗上海网站建设 建站猫
  • 一般给公司做网站用什么软件网站建设培训班价格
  • 建设银行网站怎么登陆密码忘了怎么办外贸网站建设哪家好
  • 网站开发 验收周期文化馆网站建设方案
  • 商城网站开发技术可行性分析花体字转换器
  • 个人网站做团购wordpress 小学生
  • 打开网站显示建设中全国室内设计公司排名
  • 网站和做空间微网站 注册
  • 月付网站空间提供商百度推广网站
  • 企业网站响应式怎么做交易平台网站
  • 做任务的网站有哪些家政公司注册的需要哪些条件
  • 网站报错403网站开发相关外文书籍
  • 广西建设学院网站杭州外贸建站公司
  • 企业网站优化报价怎么破解网站后台密码
  • 西安网站建设价格明细网站策划的内容有那些
  • 温州建设信息网站建设工程公司名字
  • 厦门有设计网站的吗wordpress英文文章格式
  • 长沙做网站价格邢台视频优化方案
  • 网站建设策划方案如何写医疗网站建设行情
  • 浙江二建建设集团有限公司网站南通网站快速收录
  • 女人网上量体做衣网站个人主页怎么找